eslint-plugin-jsdoc 52.0.3 → 52.0.4

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 (357) 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 +383 -398
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.ts +6 -11
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/iterateJsdoc.cjs +1988 -1528
  22. package/dist/iterateJsdoc.cjs.map +1 -1
  23. package/dist/iterateJsdoc.d.ts +349 -358
  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 +2518 -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 -22
  231. package/dist/index.d.cts.map +0 -1
  232. package/dist/index.js +0 -425
  233. package/dist/index.js.map +0 -1
  234. package/dist/iterateJsdoc.d.cts +0 -471
  235. package/dist/iterateJsdoc.d.cts.map +0 -1
  236. package/dist/iterateJsdoc.js +0 -1617
  237. package/dist/iterateJsdoc.js.map +0 -1
  238. package/dist/jsdocUtils.js +0 -1123
  239. package/dist/jsdocUtils.js.map +0 -1
  240. package/dist/rules/checkAccess.js +0 -33
  241. package/dist/rules/checkAccess.js.map +0 -1
  242. package/dist/rules/checkAlignment.js +0 -47
  243. package/dist/rules/checkAlignment.js.map +0 -1
  244. package/dist/rules/checkExamples.js +0 -348
  245. package/dist/rules/checkExamples.js.map +0 -1
  246. package/dist/rules/checkIndentation.js +0 -59
  247. package/dist/rules/checkIndentation.js.map +0 -1
  248. package/dist/rules/checkLineAlignment.js +0 -229
  249. package/dist/rules/checkLineAlignment.js.map +0 -1
  250. package/dist/rules/checkParamNames.js +0 -237
  251. package/dist/rules/checkParamNames.js.map +0 -1
  252. package/dist/rules/checkPropertyNames.js +0 -88
  253. package/dist/rules/checkPropertyNames.js.map +0 -1
  254. package/dist/rules/checkSyntax.js +0 -25
  255. package/dist/rules/checkSyntax.js.map +0 -1
  256. package/dist/rules/checkTagNames.js +0 -191
  257. package/dist/rules/checkTagNames.js.map +0 -1
  258. package/dist/rules/checkTemplateNames.js +0 -124
  259. package/dist/rules/checkTemplateNames.js.map +0 -1
  260. package/dist/rules/checkTypes.js +0 -299
  261. package/dist/rules/checkTypes.js.map +0 -1
  262. package/dist/rules/checkValues.js +0 -103
  263. package/dist/rules/checkValues.js.map +0 -1
  264. package/dist/rules/convertToJsdocComments.js +0 -231
  265. package/dist/rules/convertToJsdocComments.js.map +0 -1
  266. package/dist/rules/emptyTags.js +0 -67
  267. package/dist/rules/emptyTags.js.map +0 -1
  268. package/dist/rules/implementsOnClasses.js +0 -40
  269. package/dist/rules/implementsOnClasses.js.map +0 -1
  270. package/dist/rules/importsAsDependencies.js +0 -68
  271. package/dist/rules/importsAsDependencies.js.map +0 -1
  272. package/dist/rules/informativeDocs.js +0 -110
  273. package/dist/rules/informativeDocs.js.map +0 -1
  274. package/dist/rules/linesBeforeBlock.js +0 -75
  275. package/dist/rules/linesBeforeBlock.js.map +0 -1
  276. package/dist/rules/matchDescription.js +0 -167
  277. package/dist/rules/matchDescription.js.map +0 -1
  278. package/dist/rules/matchName.js +0 -77
  279. package/dist/rules/matchName.js.map +0 -1
  280. package/dist/rules/multilineBlocks.js +0 -245
  281. package/dist/rules/multilineBlocks.js.map +0 -1
  282. package/dist/rules/noBadBlocks.js +0 -68
  283. package/dist/rules/noBadBlocks.js.map +0 -1
  284. package/dist/rules/noBlankBlockDescriptions.js +0 -41
  285. package/dist/rules/noBlankBlockDescriptions.js.map +0 -1
  286. package/dist/rules/noBlankBlocks.js +0 -30
  287. package/dist/rules/noBlankBlocks.js.map +0 -1
  288. package/dist/rules/noDefaults.js +0 -56
  289. package/dist/rules/noDefaults.js.map +0 -1
  290. package/dist/rules/noMissingSyntax.js +0 -126
  291. package/dist/rules/noMissingSyntax.js.map +0 -1
  292. package/dist/rules/noMultiAsterisks.js +0 -58
  293. package/dist/rules/noMultiAsterisks.js.map +0 -1
  294. package/dist/rules/noRestrictedSyntax.js +0 -49
  295. package/dist/rules/noRestrictedSyntax.js.map +0 -1
  296. package/dist/rules/noTypes.js +0 -65
  297. package/dist/rules/noTypes.js.map +0 -1
  298. package/dist/rules/noUndefinedTypes.js +0 -303
  299. package/dist/rules/noUndefinedTypes.js.map +0 -1
  300. package/dist/rules/requireAsteriskPrefix.js +0 -112
  301. package/dist/rules/requireAsteriskPrefix.js.map +0 -1
  302. package/dist/rules/requireDescription.js +0 -95
  303. package/dist/rules/requireDescription.js.map +0 -1
  304. package/dist/rules/requireDescriptionCompleteSentence.js +0 -220
  305. package/dist/rules/requireDescriptionCompleteSentence.js.map +0 -1
  306. package/dist/rules/requireExample.js +0 -77
  307. package/dist/rules/requireExample.js.map +0 -1
  308. package/dist/rules/requireFileOverview.js +0 -81
  309. package/dist/rules/requireFileOverview.js.map +0 -1
  310. package/dist/rules/requireHyphenBeforeParamDescription.js +0 -89
  311. package/dist/rules/requireHyphenBeforeParamDescription.js.map +0 -1
  312. package/dist/rules/requireJsdoc.js +0 -404
  313. package/dist/rules/requireJsdoc.js.map +0 -1
  314. package/dist/rules/requireParam.js +0 -344
  315. package/dist/rules/requireParam.js.map +0 -1
  316. package/dist/rules/requireParamDescription.js +0 -59
  317. package/dist/rules/requireParamDescription.js.map +0 -1
  318. package/dist/rules/requireParamName.js +0 -36
  319. package/dist/rules/requireParamName.js.map +0 -1
  320. package/dist/rules/requireParamType.js +0 -59
  321. package/dist/rules/requireParamType.js.map +0 -1
  322. package/dist/rules/requireProperty.js +0 -35
  323. package/dist/rules/requireProperty.js.map +0 -1
  324. package/dist/rules/requirePropertyDescription.js +0 -21
  325. package/dist/rules/requirePropertyDescription.js.map +0 -1
  326. package/dist/rules/requirePropertyName.js +0 -21
  327. package/dist/rules/requirePropertyName.js.map +0 -1
  328. package/dist/rules/requirePropertyType.js +0 -21
  329. package/dist/rules/requirePropertyType.js.map +0 -1
  330. package/dist/rules/requireReturns.js +0 -131
  331. package/dist/rules/requireReturns.js.map +0 -1
  332. package/dist/rules/requireReturnsCheck.js +0 -66
  333. package/dist/rules/requireReturnsCheck.js.map +0 -1
  334. package/dist/rules/requireReturnsDescription.js +0 -43
  335. package/dist/rules/requireReturnsDescription.js.map +0 -1
  336. package/dist/rules/requireReturnsType.js +0 -36
  337. package/dist/rules/requireReturnsType.js.map +0 -1
  338. package/dist/rules/requireTemplate.js +0 -122
  339. package/dist/rules/requireTemplate.js.map +0 -1
  340. package/dist/rules/requireThrows.js +0 -67
  341. package/dist/rules/requireThrows.js.map +0 -1
  342. package/dist/rules/requireYields.js +0 -115
  343. package/dist/rules/requireYields.js.map +0 -1
  344. package/dist/rules/requireYieldsCheck.js +0 -105
  345. package/dist/rules/requireYieldsCheck.js.map +0 -1
  346. package/dist/rules/sortTags.js +0 -262
  347. package/dist/rules/sortTags.js.map +0 -1
  348. package/dist/rules/tagLines.js +0 -183
  349. package/dist/rules/tagLines.js.map +0 -1
  350. package/dist/rules/textEscaping.js +0 -102
  351. package/dist/rules/textEscaping.js.map +0 -1
  352. package/dist/rules/validTypes.js +0 -259
  353. package/dist/rules/validTypes.js.map +0 -1
  354. package/dist/tagNames.js +0 -144
  355. package/dist/tagNames.js.map +0 -1
  356. package/dist/utils/hasReturnValue.js +0 -265
  357. package/dist/utils/hasReturnValue.js.map +0 -1
@@ -0,0 +1,1896 @@
1
+ import getDefaultTagStructureForMode from './getDefaultTagStructureForMode.js';
2
+ import {
3
+ closureTags,
4
+ jsdocTags,
5
+ typeScriptTags,
6
+ } from './tagNames.js';
7
+ import WarnSettings from './WarnSettings.js';
8
+ import {
9
+ tryParse,
10
+ } from '@es-joy/jsdoccomment';
11
+
12
+ /**
13
+ * @typedef {number} Integer
14
+ */
15
+ /**
16
+ * @typedef {import('./utils/hasReturnValue.js').ESTreeOrTypeScriptNode} ESTreeOrTypeScriptNode
17
+ */
18
+
19
+ /**
20
+ * @typedef {"jsdoc"|"typescript"|"closure"|"permissive"} ParserMode
21
+ */
22
+
23
+ /**
24
+ * @type {import('./getDefaultTagStructureForMode.js').TagStructure}
25
+ */
26
+ let tagStructure;
27
+
28
+ /**
29
+ * @param {ParserMode} mode
30
+ * @returns {void}
31
+ */
32
+ const setTagStructure = (mode) => {
33
+ tagStructure = getDefaultTagStructureForMode(mode);
34
+ };
35
+
36
+ /**
37
+ * @typedef {undefined|string|{
38
+ * name: Integer,
39
+ * restElement: boolean
40
+ * }|{
41
+ * isRestProperty: boolean|undefined,
42
+ * name: string,
43
+ * restElement: boolean
44
+ * }|{
45
+ * name: string,
46
+ * restElement: boolean
47
+ * }} ParamCommon
48
+ */
49
+ /**
50
+ * @typedef {ParamCommon|[string|undefined, (FlattendRootInfo & {
51
+ * annotationParamName?: string,
52
+ * })]|NestedParamInfo} ParamNameInfo
53
+ */
54
+
55
+ /**
56
+ * @typedef {{
57
+ * hasPropertyRest: boolean,
58
+ * hasRestElement: boolean,
59
+ * names: string[],
60
+ * rests: boolean[],
61
+ * }} FlattendRootInfo
62
+ */
63
+ /**
64
+ * @typedef {[string, (string[]|ParamInfo[])]} NestedParamInfo
65
+ */
66
+ /**
67
+ * @typedef {ParamCommon|
68
+ * [string|undefined, (FlattendRootInfo & {
69
+ * annotationParamName?: string
70
+ * })]|
71
+ * NestedParamInfo} ParamInfo
72
+ */
73
+
74
+ /**
75
+ * Given a nested array of property names, reduce them to a single array,
76
+ * appending the name of the root element along the way if present.
77
+ * @callback FlattenRoots
78
+ * @param {ParamInfo[]} params
79
+ * @param {string} [root]
80
+ * @returns {FlattendRootInfo}
81
+ */
82
+
83
+ /** @type {FlattenRoots} */
84
+ const flattenRoots = (params, root = '') => {
85
+ let hasRestElement = false;
86
+ let hasPropertyRest = false;
87
+
88
+ /**
89
+ * @type {boolean[]}
90
+ */
91
+ const rests = [];
92
+
93
+ const names = params.reduce(
94
+ /**
95
+ * @param {string[]} acc
96
+ * @param {ParamInfo} cur
97
+ * @returns {string[]}
98
+ */
99
+ (acc, cur) => {
100
+ if (Array.isArray(cur)) {
101
+ let nms;
102
+ if (Array.isArray(cur[1])) {
103
+ nms = cur[1];
104
+ } else {
105
+ if (cur[1].hasRestElement) {
106
+ hasRestElement = true;
107
+ }
108
+
109
+ if (cur[1].hasPropertyRest) {
110
+ hasPropertyRest = true;
111
+ }
112
+
113
+ nms = cur[1].names;
114
+ }
115
+
116
+ const flattened = flattenRoots(nms, root ? `${root}.${cur[0]}` : cur[0]);
117
+ if (flattened.hasRestElement) {
118
+ hasRestElement = true;
119
+ }
120
+
121
+ if (flattened.hasPropertyRest) {
122
+ hasPropertyRest = true;
123
+ }
124
+
125
+ const inner = /** @type {string[]} */ ([
126
+ root ? `${root}.${cur[0]}` : cur[0],
127
+ ...flattened.names,
128
+ ].filter(Boolean));
129
+ rests.push(false, ...flattened.rests);
130
+
131
+ return acc.concat(inner);
132
+ }
133
+
134
+ if (typeof cur === 'object') {
135
+ if ('isRestProperty' in cur && cur.isRestProperty) {
136
+ hasPropertyRest = true;
137
+ rests.push(true);
138
+ } else {
139
+ rests.push(false);
140
+ }
141
+
142
+ if ('restElement' in cur && cur.restElement) {
143
+ hasRestElement = true;
144
+ }
145
+
146
+ acc.push(root ? `${root}.${String(cur.name)}` : String(cur.name));
147
+ } else if (typeof cur !== 'undefined') {
148
+ rests.push(false);
149
+ acc.push(root ? `${root}.${cur}` : cur);
150
+ }
151
+
152
+ return acc;
153
+ }, [],
154
+ );
155
+
156
+ return {
157
+ hasPropertyRest,
158
+ hasRestElement,
159
+ names,
160
+ rests,
161
+ };
162
+ };
163
+
164
+ /**
165
+ * @param {import('@typescript-eslint/types').TSESTree.TSIndexSignature|
166
+ * import('@typescript-eslint/types').TSESTree.TSConstructSignatureDeclaration|
167
+ * import('@typescript-eslint/types').TSESTree.TSCallSignatureDeclaration|
168
+ * import('@typescript-eslint/types').TSESTree.TSPropertySignature} propSignature
169
+ * @returns {undefined|string|[string, string[]]}
170
+ */
171
+ const getPropertiesFromPropertySignature = (propSignature) => {
172
+ if (
173
+ propSignature.type === 'TSIndexSignature' ||
174
+ propSignature.type === 'TSConstructSignatureDeclaration' ||
175
+ propSignature.type === 'TSCallSignatureDeclaration'
176
+ ) {
177
+ return undefined;
178
+ }
179
+
180
+ if (propSignature.typeAnnotation && propSignature.typeAnnotation.typeAnnotation.type === 'TSTypeLiteral') {
181
+ return [
182
+ /** @type {import('@typescript-eslint/types').TSESTree.Identifier} */ (
183
+ propSignature.key
184
+ ).name,
185
+ propSignature.typeAnnotation.typeAnnotation.members.map((member) => {
186
+ return /** @type {string} */ (
187
+ getPropertiesFromPropertySignature(
188
+ /** @type {import('@typescript-eslint/types').TSESTree.TSPropertySignature} */ (
189
+ member
190
+ ),
191
+ )
192
+ );
193
+ }),
194
+ ];
195
+ }
196
+
197
+ return /** @type {import('@typescript-eslint/types').TSESTree.Identifier} */ (
198
+ propSignature.key
199
+ ).name;
200
+ };
201
+
202
+ /**
203
+ * @param {ESTreeOrTypeScriptNode|null} functionNode
204
+ * @param {boolean} [checkDefaultObjects]
205
+ * @throws {Error}
206
+ * @returns {ParamNameInfo[]}
207
+ */
208
+ const getFunctionParameterNames = (
209
+ functionNode, checkDefaultObjects,
210
+ ) => {
211
+ /* eslint-disable complexity -- Temporary */
212
+ /**
213
+ * @param {import('estree').Identifier|import('estree').AssignmentPattern|
214
+ * import('estree').ObjectPattern|import('estree').Property|
215
+ * import('estree').RestElement|import('estree').ArrayPattern|
216
+ * import('@typescript-eslint/types').TSESTree.TSParameterProperty|
217
+ * import('@typescript-eslint/types').TSESTree.Property|
218
+ * import('@typescript-eslint/types').TSESTree.RestElement|
219
+ * import('@typescript-eslint/types').TSESTree.Identifier|
220
+ * import('@typescript-eslint/types').TSESTree.ObjectPattern|
221
+ * import('@typescript-eslint/types').TSESTree.BindingName|
222
+ * import('@typescript-eslint/types').TSESTree.Parameter
223
+ * } param
224
+ * @param {boolean} [isProperty]
225
+ * @returns {ParamNameInfo|[string, ParamNameInfo[]]}
226
+ */
227
+ const getParamName = (param, isProperty) => {
228
+ /* eslint-enable complexity -- Temporary */
229
+ const hasLeftTypeAnnotation = 'left' in param && 'typeAnnotation' in param.left;
230
+
231
+ if ('typeAnnotation' in param || hasLeftTypeAnnotation) {
232
+ const typeAnnotation = hasLeftTypeAnnotation ?
233
+ /** @type {import('@typescript-eslint/types').TSESTree.Identifier} */ (
234
+ param.left
235
+ ).typeAnnotation :
236
+ /** @type {import('@typescript-eslint/types').TSESTree.Identifier|import('@typescript-eslint/types').TSESTree.ObjectPattern} */
237
+ (param).typeAnnotation;
238
+
239
+ if (typeAnnotation?.typeAnnotation?.type === 'TSTypeLiteral') {
240
+ const propertyNames = typeAnnotation.typeAnnotation.members.map((member) => {
241
+ return getPropertiesFromPropertySignature(
242
+ /** @type {import('@typescript-eslint/types').TSESTree.TSPropertySignature} */
243
+ (member),
244
+ );
245
+ });
246
+
247
+ const flattened = {
248
+ ...flattenRoots(propertyNames),
249
+ annotationParamName: 'name' in param ? param.name : undefined,
250
+ };
251
+ const hasLeftName = 'left' in param && 'name' in param.left;
252
+
253
+ if ('name' in param || hasLeftName) {
254
+ return [
255
+ hasLeftName ?
256
+ /** @type {import('@typescript-eslint/types').TSESTree.Identifier} */ (
257
+ param.left
258
+ ).name :
259
+ /** @type {import('@typescript-eslint/types').TSESTree.Identifier} */ (
260
+ param
261
+ ).name,
262
+ flattened,
263
+ ];
264
+ }
265
+
266
+ return [
267
+ undefined, flattened,
268
+ ];
269
+ }
270
+ }
271
+
272
+ if ('name' in param) {
273
+ return param.name;
274
+ }
275
+
276
+ if ('left' in param && 'name' in param.left) {
277
+ return param.left.name;
278
+ }
279
+
280
+ if (
281
+ param.type === 'ObjectPattern' ||
282
+ ('left' in param &&
283
+ (
284
+ param
285
+ ).left.type === 'ObjectPattern')
286
+ ) {
287
+ const properties = /** @type {import('@typescript-eslint/types').TSESTree.ObjectPattern} */ (
288
+ param
289
+ ).properties ||
290
+ /** @type {import('estree').ObjectPattern} */
291
+ (
292
+ /** @type {import('@typescript-eslint/types').TSESTree.AssignmentPattern} */ (
293
+ param
294
+ ).left
295
+ )?.properties;
296
+ const roots = properties.map((prop) => {
297
+ return getParamName(prop, true);
298
+ });
299
+
300
+ return [
301
+ undefined, flattenRoots(roots),
302
+ ];
303
+ }
304
+
305
+ if (param.type === 'Property') {
306
+ switch (param.value.type) {
307
+ case 'ArrayPattern': {
308
+ return [
309
+ /** @type {import('estree').Identifier} */
310
+ (param.key).name,
311
+ /** @type {import('estree').ArrayPattern} */ (
312
+ param.value
313
+ ).elements.map((prop, idx) => {
314
+ return {
315
+ name: idx,
316
+ restElement: prop?.type === 'RestElement',
317
+ };
318
+ }),
319
+ ];
320
+ }
321
+
322
+ case 'ObjectPattern': {
323
+ return [
324
+ /** @type {import('estree').Identifier} */ (param.key).name,
325
+ /** @type {import('estree').ObjectPattern} */ (
326
+ param.value
327
+ ).properties.map((prop) => {
328
+ return /** @type {string|[string, string[]]} */ (getParamName(prop, isProperty));
329
+ }),
330
+ ];
331
+ }
332
+
333
+ case 'AssignmentPattern': {
334
+ switch (param.value.left.type) {
335
+ case 'ArrayPattern':
336
+ return [
337
+ /** @type {import('estree').Identifier} */
338
+ (param.key).name,
339
+ /** @type {import('estree').ArrayPattern} */ (
340
+ param.value.left
341
+ ).elements.map((prop, idx) => {
342
+ return {
343
+ name: idx,
344
+ restElement: prop?.type === 'RestElement',
345
+ };
346
+ }),
347
+ ];
348
+ case 'Identifier':
349
+ // Default parameter
350
+ if (checkDefaultObjects && param.value.right.type === 'ObjectExpression') {
351
+ return [
352
+ /** @type {import('estree').Identifier} */ (
353
+ param.key
354
+ ).name,
355
+ /** @type {import('estree').AssignmentPattern} */ (
356
+ param.value
357
+ ).right.properties.map((prop) => {
358
+ return /** @type {string} */ (getParamName(
359
+ /** @type {import('estree').Property} */
360
+ (prop),
361
+ isProperty,
362
+ ));
363
+ }),
364
+ ];
365
+ }
366
+
367
+ break;
368
+ case 'ObjectPattern':
369
+ return [
370
+ /** @type {import('estree').Identifier} */
371
+ (param.key).name,
372
+ /** @type {import('estree').ObjectPattern} */ (
373
+ param.value.left
374
+ ).properties.map((prop) => {
375
+ return getParamName(prop, isProperty);
376
+ }),
377
+ ];
378
+ }
379
+ }
380
+ }
381
+
382
+ switch (param.key.type) {
383
+ case 'Identifier':
384
+ return param.key.name;
385
+
386
+ // The key of an object could also be a string or number
387
+ case 'Literal':
388
+ /* c8 ignore next 2 -- `raw` may not be present in all parsers */
389
+ return /** @type {string} */ (param.key.raw ||
390
+ param.key.value);
391
+
392
+ // case 'MemberExpression':
393
+ default:
394
+ // Todo: We should really create a structure (and a corresponding
395
+ // option analogous to `checkRestProperty`) which allows for
396
+ // (and optionally requires) dynamic properties to have a single
397
+ // line of documentation
398
+ return undefined;
399
+ }
400
+ }
401
+
402
+ if (
403
+ param.type === 'ArrayPattern' ||
404
+ /** @type {import('estree').AssignmentPattern} */ (
405
+ param
406
+ ).left?.type === 'ArrayPattern'
407
+ ) {
408
+ const elements = /** @type {import('estree').ArrayPattern} */ (
409
+ param
410
+ ).elements || /** @type {import('estree').ArrayPattern} */ (
411
+ /** @type {import('estree').AssignmentPattern} */ (
412
+ param
413
+ ).left
414
+ )?.elements;
415
+ const roots = elements.map((prop, idx) => {
416
+ return {
417
+ name: `"${idx}"`,
418
+ restElement: prop?.type === 'RestElement',
419
+ };
420
+ });
421
+
422
+ return [
423
+ undefined, flattenRoots(roots),
424
+ ];
425
+ }
426
+
427
+ if ([
428
+ 'ExperimentalRestProperty', 'RestElement',
429
+ ].includes(param.type)) {
430
+ return {
431
+ isRestProperty: isProperty,
432
+ name: /** @type {import('@typescript-eslint/types').TSESTree.Identifier} */ (
433
+ /** @type {import('@typescript-eslint/types').TSESTree.RestElement} */ (
434
+ param
435
+ // @ts-expect-error Ok
436
+ ).argument).name ?? param?.argument?.elements?.map(({
437
+ // @ts-expect-error Ok
438
+ name,
439
+ }) => {
440
+ return name;
441
+ }),
442
+ restElement: true,
443
+ };
444
+ }
445
+
446
+ if (param.type === 'TSParameterProperty') {
447
+ return getParamName(
448
+ /** @type {import('@typescript-eslint/types').TSESTree.Identifier} */ (
449
+ /** @type {import('@typescript-eslint/types').TSESTree.TSParameterProperty} */ (
450
+ param
451
+ ).parameter
452
+ ),
453
+ true,
454
+ );
455
+ }
456
+
457
+ throw new Error(`Unsupported function signature format: \`${param.type}\`.`);
458
+ };
459
+
460
+ if (!functionNode) {
461
+ return [];
462
+ }
463
+
464
+ return (/** @type {import('@typescript-eslint/types').TSESTree.FunctionDeclaration} */ (
465
+ functionNode
466
+ ).params || /** @type {import('@typescript-eslint/types').TSESTree.MethodDefinition} */ (
467
+ functionNode
468
+ ).value?.params || []).map((param) => {
469
+ return getParamName(param);
470
+ });
471
+ };
472
+
473
+ /**
474
+ * @param {ESTreeOrTypeScriptNode} functionNode
475
+ * @returns {Integer}
476
+ */
477
+ const hasParams = (functionNode) => {
478
+ // Should also check `functionNode.value.params` if supporting `MethodDefinition`
479
+ return /** @type {import('@typescript-eslint/types').TSESTree.FunctionDeclaration} */ (
480
+ functionNode
481
+ ).params.length;
482
+ };
483
+
484
+ /**
485
+ * Gets all names of the target type, including those that refer to a path, e.g.
486
+ * `foo` or `foo.bar`.
487
+ * @param {import('comment-parser').Block} jsdoc
488
+ * @param {string} targetTagName
489
+ * @returns {{
490
+ * idx: Integer,
491
+ * name: string,
492
+ * type: string
493
+ * }[]}
494
+ */
495
+ const getJsdocTagsDeep = (jsdoc, targetTagName) => {
496
+ const ret = [];
497
+ for (const [
498
+ idx,
499
+ {
500
+ name,
501
+ tag,
502
+ type,
503
+ },
504
+ ] of jsdoc.tags.entries()) {
505
+ if (tag !== targetTagName) {
506
+ continue;
507
+ }
508
+
509
+ ret.push({
510
+ idx,
511
+ name,
512
+ type,
513
+ });
514
+ }
515
+
516
+ return ret;
517
+ };
518
+
519
+ const modeWarnSettings = WarnSettings();
520
+
521
+ /**
522
+ * @param {ParserMode|undefined} mode
523
+ * @param {Reporter} context
524
+ * @returns {import('./tagNames.js').AliasedTags}
525
+ */
526
+ const getTagNamesForMode = (mode, context) => {
527
+ switch (mode) {
528
+ case 'closure':
529
+ case 'permissive':
530
+ return closureTags;
531
+ case 'jsdoc':
532
+ return jsdocTags; case 'typescript':
533
+ return typeScriptTags;
534
+ default:
535
+ if (!modeWarnSettings.hasBeenWarned(context, 'mode')) {
536
+ context.report({
537
+ loc: {
538
+ end: {
539
+ column: 1,
540
+ line: 1,
541
+ },
542
+ start: {
543
+ column: 1,
544
+ line: 1,
545
+ },
546
+ },
547
+ message: `Unrecognized value \`${mode}\` for \`settings.jsdoc.mode\`.`,
548
+ });
549
+ modeWarnSettings.markSettingAsWarned(context, 'mode');
550
+ }
551
+
552
+ // We'll avoid breaking too many other rules
553
+ return jsdocTags;
554
+ }
555
+ };
556
+
557
+ /**
558
+ * @param {import('comment-parser').Spec} tg
559
+ * @param {boolean} [returnArray]
560
+ * @returns {string[]|string}
561
+ */
562
+ const getTagDescription = (tg, returnArray) => {
563
+ /**
564
+ * @type {string[]}
565
+ */
566
+ const descriptions = [];
567
+ tg.source.some(({
568
+ tokens: {
569
+ description,
570
+ end,
571
+ lineEnd,
572
+ name,
573
+ postDelimiter,
574
+ postTag,
575
+ tag,
576
+ type,
577
+ },
578
+ }) => {
579
+ const desc = (
580
+ tag && postTag ||
581
+ !tag && !name && !type && postDelimiter || ''
582
+
583
+ // Remove space
584
+ ).slice(1) +
585
+ (description || '') + (lineEnd || '');
586
+
587
+ if (end) {
588
+ if (desc) {
589
+ descriptions.push(desc);
590
+ }
591
+
592
+ return true;
593
+ }
594
+
595
+ descriptions.push(desc);
596
+
597
+ return false;
598
+ });
599
+
600
+ return returnArray ? descriptions : descriptions.join('\n');
601
+ };
602
+
603
+ /**
604
+ * @typedef {{
605
+ * report: (descriptor: import('eslint').Rule.ReportDescriptor) => void
606
+ * }} Reporter
607
+ */
608
+
609
+ /**
610
+ * @param {string} name
611
+ * @param {ParserMode|undefined} mode
612
+ * @param {TagNamePreference} tagPreference
613
+ * @param {Reporter} context
614
+ * @returns {string|false|{
615
+ * message: string;
616
+ * replacement?: string|undefined;
617
+ * }}
618
+ */
619
+ const getPreferredTagNameSimple = (
620
+ name,
621
+ mode,
622
+ tagPreference = {},
623
+ // eslint-disable-next-line unicorn/no-object-as-default-parameter -- Ok
624
+ context = {
625
+ report () {
626
+ // No-op
627
+ },
628
+ },
629
+ ) => {
630
+ const prefValues = Object.values(tagPreference);
631
+ if (prefValues.includes(name) || prefValues.some((prefVal) => {
632
+ return prefVal && typeof prefVal === 'object' && prefVal.replacement === name;
633
+ })) {
634
+ return name;
635
+ }
636
+
637
+ // Allow keys to have a 'tag ' prefix to avoid upstream bug in ESLint
638
+ // that disallows keys that conflict with Object.prototype,
639
+ // e.g. 'tag constructor' for 'constructor':
640
+ // https://github.com/eslint/eslint/issues/13289
641
+ // https://github.com/gajus/eslint-plugin-jsdoc/issues/537
642
+ const tagPreferenceFixed = Object.fromEntries(
643
+ Object
644
+ .entries(tagPreference)
645
+ .map(([
646
+ key,
647
+ value,
648
+ ]) => {
649
+ return [
650
+ key.replace(/^tag /v, ''), value,
651
+ ];
652
+ }),
653
+ );
654
+
655
+ if (Object.hasOwn(tagPreferenceFixed, name)) {
656
+ return tagPreferenceFixed[name];
657
+ }
658
+
659
+ const tagNames = getTagNamesForMode(mode, context);
660
+
661
+ const preferredTagName = Object.entries(tagNames).find(([
662
+ , aliases,
663
+ ]) => {
664
+ return aliases.includes(name);
665
+ })?.[0];
666
+ if (preferredTagName) {
667
+ return preferredTagName;
668
+ }
669
+
670
+ return name;
671
+ };
672
+
673
+ /**
674
+ * @param {import('eslint').Rule.RuleContext} context
675
+ * @param {ParserMode|undefined} mode
676
+ * @param {string} name
677
+ * @param {string[]} definedTags
678
+ * @returns {boolean}
679
+ */
680
+ const isValidTag = (
681
+ context,
682
+ mode,
683
+ name,
684
+ definedTags,
685
+ ) => {
686
+ const tagNames = getTagNamesForMode(mode, context);
687
+
688
+ const validTagNames = Object.keys(tagNames).concat(Object.values(tagNames).flat());
689
+ const additionalTags = definedTags;
690
+ const allTags = validTagNames.concat(additionalTags);
691
+
692
+ return allTags.includes(name);
693
+ };
694
+
695
+ /**
696
+ * @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc
697
+ * @param {string} targetTagName
698
+ * @returns {boolean}
699
+ */
700
+ const hasTag = (jsdoc, targetTagName) => {
701
+ const targetTagLower = targetTagName.toLowerCase();
702
+
703
+ return jsdoc.tags.some((doc) => {
704
+ return doc.tag.toLowerCase() === targetTagLower;
705
+ });
706
+ };
707
+
708
+ /**
709
+ * @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc
710
+ * @param {(tag: import('@es-joy/jsdoccomment').JsdocTagWithInline) => boolean} filter
711
+ * @returns {import('@es-joy/jsdoccomment').JsdocTagWithInline[]}
712
+ */
713
+ const filterTags = (jsdoc, filter) => {
714
+ return jsdoc.tags.filter((tag) => {
715
+ return filter(tag);
716
+ });
717
+ };
718
+
719
+ /**
720
+ * @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc
721
+ * @param {string} tagName
722
+ * @returns {import('comment-parser').Spec[]}
723
+ */
724
+ const getTags = (jsdoc, tagName) => {
725
+ return filterTags(jsdoc, (item) => {
726
+ return item.tag === tagName;
727
+ });
728
+ };
729
+
730
+ /**
731
+ * @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc
732
+ * @param {{
733
+ * tagName: string,
734
+ * context?: import('eslint').Rule.RuleContext,
735
+ * mode?: ParserMode,
736
+ * report?: import('./iterateJsdoc.js').Report
737
+ * tagNamePreference?: TagNamePreference
738
+ * skipReportingBlockedTag?: boolean,
739
+ * allowObjectReturn?: boolean,
740
+ * defaultMessage?: string,
741
+ * }} cfg
742
+ * @returns {string|undefined|false|{
743
+ * message: string;
744
+ * replacement?: string|undefined;
745
+ * }|{
746
+ * blocked: true,
747
+ * tagName: string
748
+ * }}
749
+ */
750
+ const getPreferredTagName = (jsdoc, {
751
+ allowObjectReturn = false,
752
+ context,
753
+ tagName,
754
+ defaultMessage = `Unexpected tag \`@${tagName}\``,
755
+ mode,
756
+ report = () => {},
757
+ skipReportingBlockedTag = false,
758
+ tagNamePreference,
759
+ }) => {
760
+ const ret = getPreferredTagNameSimple(tagName, mode, tagNamePreference, context);
761
+ const isObject = ret && typeof ret === 'object';
762
+ if (hasTag(jsdoc, tagName) && (ret === false || isObject && !ret.replacement)) {
763
+ if (skipReportingBlockedTag) {
764
+ return {
765
+ blocked: true,
766
+ tagName,
767
+ };
768
+ }
769
+
770
+ const message = isObject && ret.message || defaultMessage;
771
+ report(message, null, getTags(jsdoc, tagName)[0]);
772
+
773
+ return false;
774
+ }
775
+
776
+ return isObject && !allowObjectReturn ? ret.replacement : ret;
777
+ };
778
+
779
+ /**
780
+ * @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc
781
+ * @param {string} tagName
782
+ * @param {(
783
+ * matchingJsdocTag: import('@es-joy/jsdoccomment').JsdocTagWithInline,
784
+ * targetTagName: string
785
+ * ) => void} arrayHandler
786
+ * @param {object} cfg
787
+ * @param {import('eslint').Rule.RuleContext} [cfg.context]
788
+ * @param {ParserMode} [cfg.mode]
789
+ * @param {import('./iterateJsdoc.js').Report} [cfg.report]
790
+ * @param {TagNamePreference} [cfg.tagNamePreference]
791
+ * @param {boolean} [cfg.skipReportingBlockedTag]
792
+ * @returns {void}
793
+ */
794
+ const forEachPreferredTag = (
795
+ jsdoc, tagName, arrayHandler,
796
+ {
797
+ context,
798
+ mode,
799
+ report,
800
+ skipReportingBlockedTag = false,
801
+ tagNamePreference,
802
+ } = {},
803
+ ) => {
804
+ const targetTagName = /** @type {string|false} */ (
805
+ getPreferredTagName(jsdoc, {
806
+ context,
807
+ mode,
808
+ report,
809
+ skipReportingBlockedTag,
810
+ tagName,
811
+ tagNamePreference,
812
+ })
813
+ );
814
+ if (!targetTagName ||
815
+ skipReportingBlockedTag && targetTagName && typeof targetTagName === 'object'
816
+ ) {
817
+ return;
818
+ }
819
+
820
+ const matchingJsdocTags = jsdoc.tags.filter(({
821
+ tag,
822
+ }) => {
823
+ return tag === targetTagName;
824
+ });
825
+
826
+ for (const matchingJsdocTag of matchingJsdocTags) {
827
+ arrayHandler(
828
+ /**
829
+ * @type {import('@es-joy/jsdoccomment').JsdocTagWithInline}
830
+ */ (
831
+ matchingJsdocTag
832
+ ), targetTagName,
833
+ );
834
+ }
835
+ };
836
+
837
+ /**
838
+ * Get all tags, inline tags and inline tags in tags
839
+ * @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc
840
+ * @returns {(import('comment-parser').Spec|
841
+ * import('@es-joy/jsdoccomment').JsdocInlineTagNoType)[]}
842
+ */
843
+ const getAllTags = (jsdoc) => {
844
+ return [
845
+ ...jsdoc.tags,
846
+ ...jsdoc.inlineTags.map((inlineTag) => {
847
+ // Tags don't have source or line numbers, so add before returning
848
+ let line = -1;
849
+ for (const {
850
+ tokens: {
851
+ description,
852
+ },
853
+ } of jsdoc.source) {
854
+ line++;
855
+ if (description && description.includes(`{@${inlineTag.tag}`)) {
856
+ break;
857
+ }
858
+ }
859
+
860
+ inlineTag.line = line;
861
+
862
+ return inlineTag;
863
+ }),
864
+ ...jsdoc.tags.flatMap((tag) => {
865
+ let tagBegins = -1;
866
+ for (const {
867
+ tokens: {
868
+ tag: tg,
869
+ },
870
+ } of jsdoc.source) {
871
+ tagBegins++;
872
+ if (tg) {
873
+ break;
874
+ }
875
+ }
876
+
877
+ for (const inlineTag of tag.inlineTags) {
878
+ /** @type {import('./iterateJsdoc.js').Integer} */
879
+ let line = 0;
880
+ for (const {
881
+ number,
882
+ tokens: {
883
+ description,
884
+ },
885
+ } of tag.source) {
886
+ if (description && description.includes(`{@${inlineTag.tag}`)) {
887
+ line = number;
888
+ break;
889
+ }
890
+ }
891
+
892
+ inlineTag.line = tagBegins + line - 1;
893
+ }
894
+
895
+ return (
896
+ /**
897
+ * @type {import('comment-parser').Spec & {
898
+ * inlineTags: import('@es-joy/jsdoccomment').JsdocInlineTagNoType[]
899
+ * }}
900
+ */ (
901
+ tag
902
+ ).inlineTags
903
+ );
904
+ }),
905
+ ];
906
+ };
907
+
908
+ /**
909
+ * @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc
910
+ * @param {string[]} targetTagNames
911
+ * @returns {boolean}
912
+ */
913
+ const hasATag = (jsdoc, targetTagNames) => {
914
+ return targetTagNames.some((targetTagName) => {
915
+ return hasTag(jsdoc, targetTagName);
916
+ });
917
+ };
918
+
919
+ /**
920
+ * Checks if the JSDoc comment has an undefined type.
921
+ * @param {import('comment-parser').Spec|null|undefined} tag
922
+ * the tag which should be checked.
923
+ * @param {ParserMode} mode
924
+ * @returns {boolean}
925
+ * true in case a defined type is undeclared; otherwise false.
926
+ */
927
+ const mayBeUndefinedTypeTag = (tag, mode) => {
928
+ // The function should not continue in the event the type is not defined...
929
+ if (typeof tag === 'undefined' || tag === null) {
930
+ return true;
931
+ }
932
+
933
+ // .. same applies if it declares an `{undefined}` or `{void}` type
934
+ const tagType = tag.type.trim();
935
+
936
+ // Exit early if matching
937
+ if (
938
+ tagType === 'undefined' || tagType === 'void' ||
939
+ tagType === '*' || tagType === 'any'
940
+ ) {
941
+ return true;
942
+ }
943
+
944
+ let parsedTypes;
945
+ try {
946
+ parsedTypes = tryParse(
947
+ tagType,
948
+ mode === 'permissive' ? undefined : [
949
+ mode,
950
+ ],
951
+ );
952
+ } catch {
953
+ // Ignore
954
+ }
955
+
956
+ if (
957
+ // We do not traverse deeply as it could be, e.g., `Promise<void>`
958
+ parsedTypes &&
959
+ parsedTypes.type === 'JsdocTypeUnion' &&
960
+ parsedTypes.elements.find((elem) => {
961
+ return elem.type === 'JsdocTypeUndefined' ||
962
+ elem.type === 'JsdocTypeName' && elem.value === 'void';
963
+ })) {
964
+ return true;
965
+ }
966
+
967
+ // In any other case, a type is present
968
+ return false;
969
+ };
970
+
971
+ /**
972
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} map
973
+ * @param {string} tag
974
+ * @returns {Map<string, string|string[]|boolean|undefined>}
975
+ */
976
+ const ensureMap = (map, tag) => {
977
+ if (!map.has(tag)) {
978
+ map.set(tag, new Map());
979
+ }
980
+
981
+ return /** @type {Map<string, string | boolean>} */ (map.get(tag));
982
+ };
983
+
984
+ /**
985
+ * @param {import('./iterateJsdoc.js').StructuredTags} structuredTags
986
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
987
+ * @returns {void}
988
+ */
989
+ const overrideTagStructure = (structuredTags, tagMap = tagStructure) => {
990
+ for (const [
991
+ tag,
992
+ {
993
+ name,
994
+ required = [],
995
+ type,
996
+ },
997
+ ] of Object.entries(structuredTags)) {
998
+ const tagStruct = ensureMap(tagMap, tag);
999
+
1000
+ tagStruct.set('namepathRole', name);
1001
+ tagStruct.set('typeAllowed', type);
1002
+
1003
+ const requiredName = required.includes('name');
1004
+ if (requiredName && name === false) {
1005
+ throw new Error('Cannot add "name" to `require` with the tag\'s `name` set to `false`');
1006
+ }
1007
+
1008
+ tagStruct.set('nameRequired', requiredName);
1009
+
1010
+ const requiredType = required.includes('type');
1011
+ if (requiredType && type === false) {
1012
+ throw new Error('Cannot add "type" to `require` with the tag\'s `type` set to `false`');
1013
+ }
1014
+
1015
+ tagStruct.set('typeRequired', requiredType);
1016
+
1017
+ const typeOrNameRequired = required.includes('typeOrNameRequired');
1018
+ if (typeOrNameRequired && name === false) {
1019
+ throw new Error('Cannot add "typeOrNameRequired" to `require` with the tag\'s `name` set to `false`');
1020
+ }
1021
+
1022
+ if (typeOrNameRequired && type === false) {
1023
+ throw new Error('Cannot add "typeOrNameRequired" to `require` with the tag\'s `type` set to `false`');
1024
+ }
1025
+
1026
+ tagStruct.set('typeOrNameRequired', typeOrNameRequired);
1027
+ }
1028
+ };
1029
+
1030
+ /**
1031
+ * @param {ParserMode} mode
1032
+ * @param {import('./iterateJsdoc.js').StructuredTags} structuredTags
1033
+ * @returns {import('./getDefaultTagStructureForMode.js').TagStructure}
1034
+ */
1035
+ const getTagStructureForMode = (mode, structuredTags) => {
1036
+ const tagStruct = getDefaultTagStructureForMode(mode);
1037
+
1038
+ try {
1039
+ overrideTagStructure(structuredTags, tagStruct);
1040
+ /* c8 ignore next 3 */
1041
+ } catch {
1042
+ //
1043
+ }
1044
+
1045
+ return tagStruct;
1046
+ };
1047
+
1048
+ /**
1049
+ * @param {string} tag
1050
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
1051
+ * @returns {boolean}
1052
+ */
1053
+ const isNamepathDefiningTag = (tag, tagMap = tagStructure) => {
1054
+ const tagStruct = ensureMap(tagMap, tag);
1055
+
1056
+ return tagStruct.get('namepathRole') === 'namepath-defining';
1057
+ };
1058
+
1059
+ /**
1060
+ * @param {string} tag
1061
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
1062
+ * @returns {boolean}
1063
+ */
1064
+ const isNamepathReferencingTag = (tag, tagMap = tagStructure) => {
1065
+ const tagStruct = ensureMap(tagMap, tag);
1066
+ return tagStruct.get('namepathRole') === 'namepath-referencing';
1067
+ };
1068
+
1069
+ /**
1070
+ * @param {string} tag
1071
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
1072
+ * @returns {boolean}
1073
+ */
1074
+ const isNamepathOrUrlReferencingTag = (tag, tagMap = tagStructure) => {
1075
+ const tagStruct = ensureMap(tagMap, tag);
1076
+ return tagStruct.get('namepathRole') === 'namepath-or-url-referencing';
1077
+ };
1078
+
1079
+ /**
1080
+ * @param {string} tag
1081
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
1082
+ * @returns {boolean|undefined}
1083
+ */
1084
+ const tagMustHaveTypePosition = (tag, tagMap = tagStructure) => {
1085
+ const tagStruct = ensureMap(tagMap, tag);
1086
+
1087
+ return /** @type {boolean|undefined} */ (tagStruct.get('typeRequired'));
1088
+ };
1089
+
1090
+ /**
1091
+ * @param {string} tag
1092
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
1093
+ * @returns {boolean|string}
1094
+ */
1095
+ const tagMightHaveTypePosition = (tag, tagMap = tagStructure) => {
1096
+ if (tagMustHaveTypePosition(tag, tagMap)) {
1097
+ return true;
1098
+ }
1099
+
1100
+ const tagStruct = ensureMap(tagMap, tag);
1101
+
1102
+ const ret = /** @type {boolean|undefined} */ (tagStruct.get('typeAllowed'));
1103
+
1104
+ return ret === undefined ? true : ret;
1105
+ };
1106
+
1107
+ const namepathTypes = new Set([
1108
+ 'namepath-defining', 'namepath-referencing',
1109
+ ]);
1110
+
1111
+ /**
1112
+ * @param {string} tag
1113
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
1114
+ * @returns {boolean}
1115
+ */
1116
+ const tagMightHaveNamePosition = (tag, tagMap = tagStructure) => {
1117
+ const tagStruct = ensureMap(tagMap, tag);
1118
+
1119
+ const ret = tagStruct.get('namepathRole');
1120
+
1121
+ return ret === undefined ? true : Boolean(ret);
1122
+ };
1123
+
1124
+ /**
1125
+ * @param {string} tag
1126
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
1127
+ * @returns {boolean}
1128
+ */
1129
+ const tagMightHaveNamepath = (tag, tagMap = tagStructure) => {
1130
+ const tagStruct = ensureMap(tagMap, tag);
1131
+
1132
+ const nampathRole = tagStruct.get('namepathRole');
1133
+
1134
+ return nampathRole !== false &&
1135
+ namepathTypes.has(/** @type {string} */ (nampathRole));
1136
+ };
1137
+
1138
+ /**
1139
+ * @param {string} tag
1140
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
1141
+ * @returns {boolean|undefined}
1142
+ */
1143
+ const tagMustHaveNamePosition = (tag, tagMap = tagStructure) => {
1144
+ const tagStruct = ensureMap(tagMap, tag);
1145
+
1146
+ return /** @type {boolean|undefined} */ (tagStruct.get('nameRequired'));
1147
+ };
1148
+
1149
+ /**
1150
+ * @param {string} tag
1151
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
1152
+ * @returns {boolean}
1153
+ */
1154
+ const tagMightHaveEitherTypeOrNamePosition = (tag, tagMap) => {
1155
+ return Boolean(tagMightHaveTypePosition(tag, tagMap)) || tagMightHaveNamepath(tag, tagMap);
1156
+ };
1157
+
1158
+ /**
1159
+ * @param {string} tag
1160
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
1161
+ * @returns {boolean|undefined}
1162
+ */
1163
+ const tagMustHaveEitherTypeOrNamePosition = (tag, tagMap) => {
1164
+ const tagStruct = ensureMap(tagMap, tag);
1165
+
1166
+ return /** @type {boolean} */ (tagStruct.get('typeOrNameRequired'));
1167
+ };
1168
+
1169
+ /**
1170
+ * @param {import('comment-parser').Spec} tag
1171
+ * @param {import('./getDefaultTagStructureForMode.js').TagStructure} tagMap
1172
+ * @returns {boolean|undefined}
1173
+ */
1174
+ const tagMissingRequiredTypeOrNamepath = (tag, tagMap = tagStructure) => {
1175
+ const mustHaveTypePosition = tagMustHaveTypePosition(tag.tag, tagMap);
1176
+ const mightHaveTypePosition = tagMightHaveTypePosition(tag.tag, tagMap);
1177
+ const hasTypePosition = mightHaveTypePosition && Boolean(tag.type);
1178
+ const hasNameOrNamepathPosition = (
1179
+ tagMustHaveNamePosition(tag.tag, tagMap) ||
1180
+ tagMightHaveNamepath(tag.tag, tagMap)
1181
+ ) && Boolean(tag.name);
1182
+ const mustHaveEither = tagMustHaveEitherTypeOrNamePosition(tag.tag, tagMap);
1183
+ const hasEither = tagMightHaveEitherTypeOrNamePosition(tag.tag, tagMap) &&
1184
+ (hasTypePosition || hasNameOrNamepathPosition);
1185
+
1186
+ return mustHaveEither && !hasEither && !mustHaveTypePosition;
1187
+ };
1188
+
1189
+ /* eslint-disable complexity -- Temporary */
1190
+ /**
1191
+ * @param {ESTreeOrTypeScriptNode|null|undefined} node
1192
+ * @param {boolean} [checkYieldReturnValue]
1193
+ * @returns {boolean}
1194
+ */
1195
+ const hasNonFunctionYield = (node, checkYieldReturnValue) => {
1196
+ /* eslint-enable complexity -- Temporary */
1197
+ if (!node) {
1198
+ return false;
1199
+ }
1200
+
1201
+ switch (node.type) {
1202
+ case 'ArrayExpression':
1203
+
1204
+ case 'ArrayPattern':
1205
+ return node.elements.some((element) => {
1206
+ return hasNonFunctionYield(element, checkYieldReturnValue);
1207
+ });
1208
+ case 'AssignmentExpression':
1209
+ case 'BinaryExpression':
1210
+ case 'LogicalExpression': {
1211
+ return hasNonFunctionYield(node.left, checkYieldReturnValue) ||
1212
+ hasNonFunctionYield(node.right, checkYieldReturnValue);
1213
+ }
1214
+
1215
+ case 'AssignmentPattern':
1216
+ return hasNonFunctionYield(node.right, checkYieldReturnValue);
1217
+ case 'BlockStatement': {
1218
+ return node.body.some((bodyNode) => {
1219
+ return ![
1220
+ 'ArrowFunctionExpression',
1221
+ 'FunctionDeclaration',
1222
+ 'FunctionExpression',
1223
+ ].includes(bodyNode.type) && hasNonFunctionYield(
1224
+ bodyNode, checkYieldReturnValue,
1225
+ );
1226
+ });
1227
+ }
1228
+
1229
+ /* c8 ignore next 2 -- In Babel? */
1230
+ case 'CallExpression':
1231
+ // @ts-expect-error In Babel?
1232
+ case 'OptionalCallExpression':
1233
+ return node.arguments.some((element) => {
1234
+ return hasNonFunctionYield(element, checkYieldReturnValue);
1235
+ });
1236
+ case 'ChainExpression':
1237
+ case 'ExpressionStatement': {
1238
+ return hasNonFunctionYield(node.expression, checkYieldReturnValue);
1239
+ }
1240
+
1241
+ /* c8 ignore next 2 -- In Babel? */
1242
+ // @ts-expect-error In Babel?
1243
+ case 'ClassProperty':
1244
+
1245
+ /* c8 ignore next 2 -- In Babel? */
1246
+ // @ts-expect-error In Babel?
1247
+ case 'ObjectProperty':
1248
+ /* c8 ignore next 2 -- In Babel? */
1249
+ case 'Property':
1250
+
1251
+ case 'PropertyDefinition':
1252
+ return node.computed && hasNonFunctionYield(node.key, checkYieldReturnValue) ||
1253
+ hasNonFunctionYield(node.value, checkYieldReturnValue);
1254
+
1255
+ case 'ConditionalExpression':
1256
+
1257
+ case 'IfStatement': {
1258
+ return hasNonFunctionYield(node.test, checkYieldReturnValue) ||
1259
+ hasNonFunctionYield(node.consequent, checkYieldReturnValue) ||
1260
+ hasNonFunctionYield(node.alternate, checkYieldReturnValue);
1261
+ }
1262
+
1263
+ case 'DoWhileStatement':
1264
+ case 'ForInStatement':
1265
+
1266
+ case 'ForOfStatement':
1267
+
1268
+ case 'ForStatement':
1269
+
1270
+ case 'LabeledStatement':
1271
+ case 'WhileStatement':
1272
+ case 'WithStatement': {
1273
+ return hasNonFunctionYield(node.body, checkYieldReturnValue);
1274
+ }
1275
+
1276
+ /* c8 ignore next 2 -- In Babel? */
1277
+ // @ts-expect-error In Babel?
1278
+ case 'Import':
1279
+ case 'ImportExpression':
1280
+ return hasNonFunctionYield(node.source, checkYieldReturnValue);
1281
+
1282
+ // ?.
1283
+ /* c8 ignore next 2 -- In Babel? */
1284
+ case 'MemberExpression':
1285
+ // @ts-expect-error In Babel?
1286
+ case 'OptionalMemberExpression':
1287
+ return hasNonFunctionYield(node.object, checkYieldReturnValue) ||
1288
+ hasNonFunctionYield(node.property, checkYieldReturnValue);
1289
+
1290
+ case 'ObjectExpression':
1291
+ /* eslint-disable no-fallthrough */
1292
+ case 'ObjectPattern':
1293
+ /* eslint-enable no-fallthrough */
1294
+ return node.properties.some((property) => {
1295
+ return hasNonFunctionYield(property, checkYieldReturnValue);
1296
+ });
1297
+ /* c8 ignore next 2 -- In Babel? */
1298
+ // @ts-expect-error In Babel?
1299
+ case 'ObjectMethod':
1300
+ /* c8 ignore next 6 -- In Babel? */
1301
+ // @ts-expect-error In Babel?
1302
+ return node.computed && hasNonFunctionYield(node.key, checkYieldReturnValue) ||
1303
+ // @ts-expect-error In Babel?
1304
+ node.arguments.some((nde) => {
1305
+ return hasNonFunctionYield(nde, checkYieldReturnValue);
1306
+ });
1307
+ case 'ReturnStatement': {
1308
+ if (node.argument === null) {
1309
+ return false;
1310
+ }
1311
+
1312
+ return hasNonFunctionYield(node.argument, checkYieldReturnValue);
1313
+ }
1314
+
1315
+ // Comma
1316
+ case 'SequenceExpression':
1317
+
1318
+ case 'TemplateLiteral':
1319
+ return node.expressions.some((subExpression) => {
1320
+ return hasNonFunctionYield(subExpression, checkYieldReturnValue);
1321
+ });
1322
+ case 'SpreadElement':
1323
+
1324
+ case 'UnaryExpression':
1325
+ return hasNonFunctionYield(node.argument, checkYieldReturnValue);
1326
+
1327
+ case 'SwitchStatement': {
1328
+ return node.cases.some(
1329
+ (someCase) => {
1330
+ return someCase.consequent.some((nde) => {
1331
+ return hasNonFunctionYield(nde, checkYieldReturnValue);
1332
+ });
1333
+ },
1334
+ );
1335
+ }
1336
+
1337
+ case 'TaggedTemplateExpression':
1338
+ return hasNonFunctionYield(node.quasi, checkYieldReturnValue);
1339
+
1340
+ case 'TryStatement': {
1341
+ return hasNonFunctionYield(node.block, checkYieldReturnValue) ||
1342
+ hasNonFunctionYield(
1343
+ node.handler && node.handler.body, checkYieldReturnValue,
1344
+ ) ||
1345
+ hasNonFunctionYield(
1346
+ /** @type {import('@typescript-eslint/types').TSESTree.BlockStatement} */
1347
+ (node.finalizer),
1348
+ checkYieldReturnValue,
1349
+ );
1350
+ }
1351
+
1352
+ case 'VariableDeclaration': {
1353
+ return node.declarations.some((nde) => {
1354
+ return hasNonFunctionYield(nde, checkYieldReturnValue);
1355
+ });
1356
+ }
1357
+
1358
+ case 'VariableDeclarator': {
1359
+ return hasNonFunctionYield(node.id, checkYieldReturnValue) ||
1360
+ hasNonFunctionYield(node.init, checkYieldReturnValue);
1361
+ }
1362
+
1363
+ case 'YieldExpression': {
1364
+ if (checkYieldReturnValue) {
1365
+ if (
1366
+ /** @type {import('eslint').Rule.Node} */ (
1367
+ node
1368
+ ).parent.type === 'VariableDeclarator'
1369
+ ) {
1370
+ return true;
1371
+ }
1372
+
1373
+ return false;
1374
+ }
1375
+
1376
+ // void return does not count.
1377
+ if (node.argument === null) {
1378
+ return false;
1379
+ }
1380
+
1381
+ return true;
1382
+ }
1383
+
1384
+ default: {
1385
+ return false;
1386
+ }
1387
+ }
1388
+ };
1389
+
1390
+ /**
1391
+ * Checks if a node has a return statement. Void return does not count.
1392
+ * @param {ESTreeOrTypeScriptNode} node
1393
+ * @param {boolean} [checkYieldReturnValue]
1394
+ * @returns {boolean}
1395
+ */
1396
+ const hasYieldValue = (node, checkYieldReturnValue) => {
1397
+ return /** @type {import('@typescript-eslint/types').TSESTree.FunctionDeclaration} */ (
1398
+ node
1399
+ ).generator && (
1400
+ /** @type {import('@typescript-eslint/types').TSESTree.FunctionDeclaration} */ (
1401
+ node
1402
+ ).expression || hasNonFunctionYield(
1403
+ /** @type {import('@typescript-eslint/types').TSESTree.FunctionDeclaration} */
1404
+ (node).body,
1405
+ checkYieldReturnValue,
1406
+ )
1407
+ );
1408
+ };
1409
+
1410
+ /**
1411
+ * Checks if a node has a throws statement.
1412
+ * @param {ESTreeOrTypeScriptNode|null|undefined} node
1413
+ * @param {boolean} [innerFunction]
1414
+ * @returns {boolean}
1415
+ */
1416
+ // eslint-disable-next-line complexity
1417
+ const hasThrowValue = (node, innerFunction) => {
1418
+ if (!node) {
1419
+ return false;
1420
+ }
1421
+
1422
+ // There are cases where a function may execute its inner function which
1423
+ // throws, but we're treating functions atomically rather than trying to
1424
+ // follow them
1425
+ switch (node.type) {
1426
+ case 'ArrowFunctionExpression':
1427
+ case 'FunctionDeclaration':
1428
+ case 'FunctionExpression': {
1429
+ return !innerFunction && !node.async && hasThrowValue(node.body, true);
1430
+ }
1431
+
1432
+ case 'BlockStatement': {
1433
+ return node.body.some((bodyNode) => {
1434
+ return bodyNode.type !== 'FunctionDeclaration' && hasThrowValue(bodyNode);
1435
+ });
1436
+ }
1437
+
1438
+ case 'DoWhileStatement':
1439
+ case 'ForInStatement':
1440
+ case 'ForOfStatement':
1441
+ case 'ForStatement':
1442
+ case 'LabeledStatement':
1443
+ case 'WhileStatement':
1444
+ case 'WithStatement': {
1445
+ return hasThrowValue(node.body);
1446
+ }
1447
+
1448
+ case 'IfStatement': {
1449
+ return hasThrowValue(node.consequent) || hasThrowValue(node.alternate);
1450
+ }
1451
+
1452
+ case 'SwitchStatement': {
1453
+ return node.cases.some(
1454
+ (someCase) => {
1455
+ return someCase.consequent.some((nde) => {
1456
+ return hasThrowValue(nde);
1457
+ });
1458
+ },
1459
+ );
1460
+ }
1461
+
1462
+ case 'ThrowStatement': {
1463
+ return true;
1464
+ }
1465
+
1466
+ // We only consider it to throw an error if the catch or finally blocks throw an error.
1467
+ case 'TryStatement': {
1468
+ return hasThrowValue(node.handler && node.handler.body) ||
1469
+ hasThrowValue(node.finalizer);
1470
+ }
1471
+
1472
+ default: {
1473
+ return false;
1474
+ }
1475
+ }
1476
+ };
1477
+
1478
+ /**
1479
+ * @param {string} tag
1480
+ */
1481
+ /*
1482
+ const isInlineTag = (tag) => {
1483
+ return /^(@link|@linkcode|@linkplain|@tutorial) /v.test(tag);
1484
+ };
1485
+ */
1486
+
1487
+ /**
1488
+ * Parses GCC Generic/Template types
1489
+ * @see {@link https://github.com/google/closure-compiler/wiki/Generic-Types}
1490
+ * @see {@link https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#template}
1491
+ * @param {import('comment-parser').Spec} tag
1492
+ * @returns {string[]}
1493
+ */
1494
+ const parseClosureTemplateTag = (tag) => {
1495
+ return tag.name
1496
+ .split(',')
1497
+ .map((type) => {
1498
+ return type.trim().replace(/^\[?(?<name>.*?)=.*$/v, '$<name>');
1499
+ });
1500
+ };
1501
+
1502
+ /**
1503
+ * @typedef {true|string[]} DefaultContexts
1504
+ */
1505
+
1506
+ /**
1507
+ * Checks user option for `contexts` array, defaulting to
1508
+ * contexts designated by the rule. Returns an array of
1509
+ * ESTree AST types, indicating allowable contexts.
1510
+ * @param {import('eslint').Rule.RuleContext} context
1511
+ * @param {DefaultContexts|undefined} defaultContexts
1512
+ * @param {{
1513
+ * contexts?: import('./iterateJsdoc.js').Context[]
1514
+ * }} settings
1515
+ * @returns {(string|import('./iterateJsdoc.js').ContextObject)[]}
1516
+ */
1517
+ const enforcedContexts = (context, defaultContexts, settings) => {
1518
+ const contexts = context.options[0]?.contexts || settings.contexts || (defaultContexts === true ? [
1519
+ 'ArrowFunctionExpression',
1520
+ 'FunctionDeclaration',
1521
+ 'FunctionExpression',
1522
+ 'TSDeclareFunction',
1523
+ ] : defaultContexts);
1524
+
1525
+ return contexts;
1526
+ };
1527
+
1528
+ /**
1529
+ * @param {import('./iterateJsdoc.js').Context[]} contexts
1530
+ * @param {import('./iterateJsdoc.js').CheckJsdoc} checkJsdoc
1531
+ * @param {import('@es-joy/jsdoccomment').CommentHandler} [handler]
1532
+ * @returns {import('eslint').Rule.RuleListener}
1533
+ */
1534
+ const getContextObject = (contexts, checkJsdoc, handler) => {
1535
+ /** @type {import('eslint').Rule.RuleListener} */
1536
+ const properties = {};
1537
+
1538
+ for (const [
1539
+ idx,
1540
+ prop,
1541
+ ] of contexts.entries()) {
1542
+ /** @type {string} */
1543
+ let property;
1544
+
1545
+ /** @type {(node: import('eslint').Rule.Node) => void} */
1546
+ let value;
1547
+
1548
+ if (typeof prop === 'object') {
1549
+ const selInfo = {
1550
+ lastIndex: idx,
1551
+ selector: prop.context,
1552
+ };
1553
+ if (prop.comment) {
1554
+ property = /** @type {string} */ (prop.context);
1555
+ value = checkJsdoc.bind(
1556
+ null,
1557
+ {
1558
+ ...selInfo,
1559
+ comment: prop.comment,
1560
+ },
1561
+ /**
1562
+ * @type {(jsdoc: import('@es-joy/jsdoccomment').JsdocBlockWithInline) => boolean}
1563
+ */
1564
+ (/** @type {import('@es-joy/jsdoccomment').CommentHandler} */ (
1565
+ handler
1566
+ ).bind(null, prop.comment)),
1567
+ );
1568
+ } else {
1569
+ property = /** @type {string} */ (prop.context);
1570
+ value = checkJsdoc.bind(null, selInfo, null);
1571
+ }
1572
+ } else {
1573
+ const selInfo = {
1574
+ lastIndex: idx,
1575
+ selector: prop,
1576
+ };
1577
+ property = prop;
1578
+ value = checkJsdoc.bind(null, selInfo, null);
1579
+ }
1580
+
1581
+ const old = /**
1582
+ * @type {((node: import('eslint').Rule.Node) => void)}
1583
+ */ (properties[property]);
1584
+ properties[property] = old ?
1585
+ /**
1586
+ * @type {((node: import('eslint').Rule.Node) => void)}
1587
+ */
1588
+ function (node) {
1589
+ old(node);
1590
+ value(node);
1591
+ } :
1592
+ value;
1593
+ }
1594
+
1595
+ return properties;
1596
+ };
1597
+
1598
+ const tagsWithNamesAndDescriptions = new Set([
1599
+ 'arg', 'argument', 'param', 'prop', 'property',
1600
+ 'return',
1601
+
1602
+ // These two are parsed by our custom parser as though having a `name`
1603
+ 'returns', 'template',
1604
+ ]);
1605
+
1606
+ /**
1607
+ * @typedef {{
1608
+ * [key: string]: false|string|
1609
+ * {message: string, replacement?: string}
1610
+ * }} TagNamePreference
1611
+ */
1612
+
1613
+ /**
1614
+ * @param {import('eslint').Rule.RuleContext} context
1615
+ * @param {ParserMode|undefined} mode
1616
+ * @param {import('comment-parser').Spec[]} tags
1617
+ * @returns {{
1618
+ * tagsWithNames: import('comment-parser').Spec[],
1619
+ * tagsWithoutNames: import('comment-parser').Spec[]
1620
+ * }}
1621
+ */
1622
+ const getTagsByType = (context, mode, tags) => {
1623
+ /**
1624
+ * @type {import('comment-parser').Spec[]}
1625
+ */
1626
+ const tagsWithoutNames = [];
1627
+ const tagsWithNames = tags.filter((tag) => {
1628
+ const {
1629
+ tag: tagName,
1630
+ } = tag;
1631
+ const tagWithName = tagsWithNamesAndDescriptions.has(tagName);
1632
+ if (!tagWithName) {
1633
+ tagsWithoutNames.push(tag);
1634
+ }
1635
+
1636
+ return tagWithName;
1637
+ });
1638
+
1639
+ return {
1640
+ tagsWithNames,
1641
+ tagsWithoutNames,
1642
+ };
1643
+ };
1644
+
1645
+ /**
1646
+ * @param {import('eslint').SourceCode|{
1647
+ * text: string
1648
+ * }} sourceCode
1649
+ * @returns {string}
1650
+ */
1651
+ const getIndent = (sourceCode) => {
1652
+ return (sourceCode.text.match(/^\n*([ \t]+)/v)?.[1] ?? '') + ' ';
1653
+ };
1654
+
1655
+ /**
1656
+ * @param {import('eslint').Rule.Node|null} node
1657
+ * @returns {boolean}
1658
+ */
1659
+ const isConstructor = (node) => {
1660
+ return node?.type === 'MethodDefinition' && node.kind === 'constructor' ||
1661
+ /** @type {import('@typescript-eslint/types').TSESTree.MethodDefinition} */ (
1662
+ node?.parent
1663
+ )?.kind === 'constructor';
1664
+ };
1665
+
1666
+ /**
1667
+ * @param {import('eslint').Rule.Node|null} node
1668
+ * @returns {boolean}
1669
+ */
1670
+ const isGetter = (node) => {
1671
+ return node !== null &&
1672
+ /**
1673
+ * @type {import('@typescript-eslint/types').TSESTree.MethodDefinition|
1674
+ * import('@typescript-eslint/types').TSESTree.Property}
1675
+ */ (
1676
+ node.parent
1677
+ )?.kind === 'get';
1678
+ };
1679
+
1680
+ /**
1681
+ * @param {import('eslint').Rule.Node|null} node
1682
+ * @returns {boolean}
1683
+ */
1684
+ const isSetter = (node) => {
1685
+ return node !== null &&
1686
+ /**
1687
+ * @type {import('@typescript-eslint/types').TSESTree.MethodDefinition|
1688
+ * import('@typescript-eslint/types').TSESTree.Property}
1689
+ */(
1690
+ node.parent
1691
+ )?.kind === 'set';
1692
+ };
1693
+
1694
+ /**
1695
+ * @param {import('eslint').Rule.Node} node
1696
+ * @returns {boolean}
1697
+ */
1698
+ const hasAccessorPair = (node) => {
1699
+ const {
1700
+ key,
1701
+ kind: sourceKind,
1702
+ type,
1703
+ } =
1704
+ /**
1705
+ * @type {import('@typescript-eslint/types').TSESTree.MethodDefinition|
1706
+ * import('@typescript-eslint/types').TSESTree.Property}
1707
+ */ (node);
1708
+
1709
+ const sourceName =
1710
+ /** @type {import('@typescript-eslint/types').TSESTree.Identifier} */ (
1711
+ key
1712
+ ).name;
1713
+
1714
+ const oppositeKind = sourceKind === 'get' ? 'set' : 'get';
1715
+
1716
+ const sibling = type === 'MethodDefinition' ?
1717
+ /** @type {import('@typescript-eslint/types').TSESTree.ClassBody} */ (
1718
+ node.parent
1719
+ ).body :
1720
+ /** @type {import('@typescript-eslint/types').TSESTree.ObjectExpression} */ (
1721
+ node.parent
1722
+ ).properties;
1723
+
1724
+ return (
1725
+ sibling.some((child) => {
1726
+ const {
1727
+ key: ky,
1728
+ kind,
1729
+ } = /**
1730
+ * @type {import('@typescript-eslint/types').TSESTree.MethodDefinition|
1731
+ * import('@typescript-eslint/types').TSESTree.Property}
1732
+ */ (child);
1733
+
1734
+ const name =
1735
+ /** @type {import('@typescript-eslint/types').TSESTree.Identifier} */ (
1736
+ ky
1737
+ ).name;
1738
+
1739
+ return kind === oppositeKind && name === sourceName;
1740
+ })
1741
+ );
1742
+ };
1743
+
1744
+ /**
1745
+ * @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc
1746
+ * @param {import('eslint').Rule.Node|null} node
1747
+ * @param {import('eslint').Rule.RuleContext} context
1748
+ * @param {import('json-schema').JSONSchema4} schema
1749
+ * @returns {boolean}
1750
+ */
1751
+ const exemptSpeciaMethods = (jsdoc, node, context, schema) => {
1752
+ /**
1753
+ * @param {"checkGetters"|"checkSetters"|"checkConstructors"} prop
1754
+ * @returns {boolean|"no-setter"|"no-getter"}
1755
+ */
1756
+ const hasSchemaOption = (prop) => {
1757
+ const schemaProperties = schema[0].properties;
1758
+
1759
+ return context.options[0]?.[prop] ??
1760
+ (schemaProperties[prop] && schemaProperties[prop].default);
1761
+ };
1762
+
1763
+ const checkGetters = hasSchemaOption('checkGetters');
1764
+ const checkSetters = hasSchemaOption('checkSetters');
1765
+
1766
+ return !hasSchemaOption('checkConstructors') &&
1767
+ (
1768
+ isConstructor(node) ||
1769
+ hasATag(jsdoc, [
1770
+ 'class',
1771
+ 'constructor',
1772
+ ])) ||
1773
+ isGetter(node) && (
1774
+ !checkGetters ||
1775
+ checkGetters === 'no-setter' && hasAccessorPair(/** @type {import('./iterateJsdoc.js').Node} */ (node).parent)
1776
+ ) ||
1777
+ isSetter(node) && (
1778
+ !checkSetters ||
1779
+ checkSetters === 'no-getter' && hasAccessorPair(/** @type {import('./iterateJsdoc.js').Node} */ (node).parent)
1780
+ );
1781
+ };
1782
+
1783
+ /**
1784
+ * Since path segments may be unquoted (if matching a reserved word,
1785
+ * identifier or numeric literal) or single or double quoted, in either
1786
+ * the `@param` or in source, we need to strip the quotes to give a fair
1787
+ * comparison.
1788
+ * @param {string} str
1789
+ * @returns {string}
1790
+ */
1791
+ const dropPathSegmentQuotes = (str) => {
1792
+ return str.replaceAll(/\.(['"])(.*)\1/gv, '.$2');
1793
+ };
1794
+
1795
+ /**
1796
+ * @param {string} name
1797
+ * @returns {(otherPathName: string) => boolean}
1798
+ */
1799
+ const comparePaths = (name) => {
1800
+ return (otherPathName) => {
1801
+ return otherPathName === name ||
1802
+ dropPathSegmentQuotes(otherPathName) === dropPathSegmentQuotes(name);
1803
+ };
1804
+ };
1805
+
1806
+ /**
1807
+ * @callback PathDoesNotBeginWith
1808
+ * @param {string} name
1809
+ * @param {string} otherPathName
1810
+ * @returns {boolean}
1811
+ */
1812
+
1813
+ /** @type {PathDoesNotBeginWith} */
1814
+ const pathDoesNotBeginWith = (name, otherPathName) => {
1815
+ return !name.startsWith(otherPathName) &&
1816
+ !dropPathSegmentQuotes(name).startsWith(dropPathSegmentQuotes(otherPathName));
1817
+ };
1818
+
1819
+ /**
1820
+ * @param {string} regexString
1821
+ * @param {string} [requiredFlags]
1822
+ * @returns {RegExp}
1823
+ */
1824
+ const getRegexFromString = (regexString, requiredFlags) => {
1825
+ const match = regexString.match(/^\/(.*)\/([gimyvus]*)$/vs);
1826
+ let flags = 'v';
1827
+ let regex = regexString;
1828
+ if (match) {
1829
+ [
1830
+ , regex,
1831
+ flags,
1832
+ ] = match;
1833
+ if (!flags) {
1834
+ flags = 'v';
1835
+ }
1836
+ }
1837
+
1838
+ const uniqueFlags = [
1839
+ ...new Set(flags + (requiredFlags || '')),
1840
+ ];
1841
+ flags = uniqueFlags.join('');
1842
+
1843
+ return new RegExp(regex, flags);
1844
+ };
1845
+
1846
+ export {
1847
+ comparePaths,
1848
+ dropPathSegmentQuotes,
1849
+ enforcedContexts,
1850
+ exemptSpeciaMethods,
1851
+ filterTags,
1852
+ flattenRoots,
1853
+ forEachPreferredTag,
1854
+ getAllTags,
1855
+ getContextObject,
1856
+ getFunctionParameterNames,
1857
+ getIndent,
1858
+ getJsdocTagsDeep,
1859
+ getPreferredTagName,
1860
+ getPreferredTagNameSimple,
1861
+ getRegexFromString,
1862
+ getTagDescription,
1863
+ getTags,
1864
+ getTagsByType,
1865
+ getTagStructureForMode,
1866
+ hasATag,
1867
+ hasParams,
1868
+
1869
+ hasTag,
1870
+ hasThrowValue,
1871
+
1872
+ hasYieldValue,
1873
+ isConstructor,
1874
+ isGetter,
1875
+ isNamepathDefiningTag,
1876
+ isNamepathOrUrlReferencingTag,
1877
+ isNamepathReferencingTag,
1878
+ isSetter,
1879
+ isValidTag,
1880
+ mayBeUndefinedTypeTag,
1881
+ overrideTagStructure,
1882
+ parseClosureTemplateTag,
1883
+ pathDoesNotBeginWith,
1884
+ setTagStructure,
1885
+ tagMightHaveEitherTypeOrNamePosition,
1886
+ tagMightHaveNamepath,
1887
+ tagMightHaveNamePosition,
1888
+ tagMightHaveTypePosition,
1889
+ tagMissingRequiredTypeOrNamepath,
1890
+ tagMustHaveNamePosition,
1891
+ tagMustHaveTypePosition,
1892
+ };
1893
+ export {
1894
+ hasReturnValue,
1895
+ hasValueOrExecutorHasNonEmptyResolveValue,
1896
+ } from './utils/hasReturnValue.js';