eslint-plugin-jsdoc 47.0.2 → 48.0.1

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 (257) hide show
  1. package/dist/{WarnSettings.js → WarnSettings.cjs} +2 -2
  2. package/dist/WarnSettings.cjs.map +1 -0
  3. package/dist/{alignTransform.js → alignTransform.cjs} +2 -2
  4. package/dist/alignTransform.cjs.map +1 -0
  5. package/dist/{defaultTagOrder.js → defaultTagOrder.cjs} +1 -1
  6. package/dist/defaultTagOrder.cjs.map +1 -0
  7. package/dist/{exportParser.js → exportParser.cjs} +32 -36
  8. package/dist/exportParser.cjs.map +1 -0
  9. package/dist/{generateRule.js → generateRule.cjs} +7 -4
  10. package/dist/generateRule.cjs.map +1 -0
  11. package/dist/{getDefaultTagStructureForMode.js → getDefaultTagStructureForMode.cjs} +1 -1
  12. package/dist/getDefaultTagStructureForMode.cjs.map +1 -0
  13. package/dist/{index.js → index.cjs} +55 -55
  14. package/dist/index.cjs.map +1 -0
  15. package/dist/{iterateJsdoc.js → iterateJsdoc.cjs} +16 -21
  16. package/dist/iterateJsdoc.cjs.map +1 -0
  17. package/dist/{jsdocUtils.js → jsdocUtils.cjs} +17 -17
  18. package/dist/jsdocUtils.cjs.map +1 -0
  19. package/dist/rules/{checkAccess.js → checkAccess.cjs} +2 -2
  20. package/dist/rules/checkAccess.cjs.map +1 -0
  21. package/dist/rules/{checkAlignment.js → checkAlignment.cjs} +2 -2
  22. package/dist/rules/checkAlignment.cjs.map +1 -0
  23. package/dist/rules/{checkExamples.js → checkExamples.cjs} +2 -2
  24. package/dist/rules/checkExamples.cjs.map +1 -0
  25. package/dist/rules/{checkIndentation.js → checkIndentation.cjs} +2 -2
  26. package/dist/rules/checkIndentation.cjs.map +1 -0
  27. package/dist/rules/{checkLineAlignment.js → checkLineAlignment.cjs} +3 -3
  28. package/dist/rules/checkLineAlignment.cjs.map +1 -0
  29. package/dist/rules/{checkParamNames.js → checkParamNames.cjs} +2 -2
  30. package/dist/rules/checkParamNames.cjs.map +1 -0
  31. package/dist/rules/{checkPropertyNames.js → checkPropertyNames.cjs} +2 -2
  32. package/dist/rules/checkPropertyNames.cjs.map +1 -0
  33. package/dist/rules/{checkSyntax.js → checkSyntax.cjs} +2 -2
  34. package/dist/rules/checkSyntax.cjs.map +1 -0
  35. package/dist/rules/{checkTagNames.js → checkTagNames.cjs} +2 -2
  36. package/dist/rules/checkTagNames.cjs.map +1 -0
  37. package/dist/rules/{checkTypes.js → checkTypes.cjs} +2 -2
  38. package/dist/rules/checkTypes.cjs.map +1 -0
  39. package/dist/rules/{checkValues.js → checkValues.cjs} +2 -2
  40. package/dist/rules/checkValues.cjs.map +1 -0
  41. package/dist/rules/{emptyTags.js → emptyTags.cjs} +2 -2
  42. package/dist/rules/emptyTags.cjs.map +1 -0
  43. package/dist/rules/{implementsOnClasses.js → implementsOnClasses.cjs} +2 -2
  44. package/dist/rules/implementsOnClasses.cjs.map +1 -0
  45. package/dist/rules/{importsAsDependencies.js → importsAsDependencies.cjs} +10 -12
  46. package/dist/rules/importsAsDependencies.cjs.map +1 -0
  47. package/dist/rules/{informativeDocs.js → informativeDocs.cjs} +2 -2
  48. package/dist/rules/informativeDocs.cjs.map +1 -0
  49. package/dist/rules/{matchDescription.js → matchDescription.cjs} +2 -2
  50. package/dist/rules/matchDescription.cjs.map +1 -0
  51. package/dist/rules/{matchName.js → matchName.cjs} +2 -2
  52. package/dist/rules/matchName.cjs.map +1 -0
  53. package/dist/rules/{multilineBlocks.js → multilineBlocks.cjs} +2 -2
  54. package/dist/rules/multilineBlocks.cjs.map +1 -0
  55. package/dist/rules/{noBadBlocks.js → noBadBlocks.cjs} +2 -2
  56. package/dist/rules/noBadBlocks.cjs.map +1 -0
  57. package/dist/rules/{noBlankBlockDescriptions.js → noBlankBlockDescriptions.cjs} +2 -2
  58. package/dist/rules/noBlankBlockDescriptions.cjs.map +1 -0
  59. package/dist/rules/{noBlankBlocks.js → noBlankBlocks.cjs} +2 -2
  60. package/dist/rules/noBlankBlocks.cjs.map +1 -0
  61. package/dist/rules/{noDefaults.js → noDefaults.cjs} +2 -2
  62. package/dist/rules/noDefaults.cjs.map +1 -0
  63. package/dist/rules/{noMissingSyntax.js → noMissingSyntax.cjs} +2 -2
  64. package/dist/rules/noMissingSyntax.cjs.map +1 -0
  65. package/dist/rules/{noMultiAsterisks.js → noMultiAsterisks.cjs} +2 -2
  66. package/dist/rules/noMultiAsterisks.cjs.map +1 -0
  67. package/dist/rules/{noRestrictedSyntax.js → noRestrictedSyntax.cjs} +2 -2
  68. package/dist/rules/noRestrictedSyntax.cjs.map +1 -0
  69. package/dist/rules/{noTypes.js → noTypes.cjs} +2 -2
  70. package/dist/rules/noTypes.cjs.map +1 -0
  71. package/dist/rules/{noUndefinedTypes.js → noUndefinedTypes.cjs} +5 -5
  72. package/dist/rules/noUndefinedTypes.cjs.map +1 -0
  73. package/dist/rules/{requireAsteriskPrefix.js → requireAsteriskPrefix.cjs} +2 -2
  74. package/dist/rules/requireAsteriskPrefix.cjs.map +1 -0
  75. package/dist/rules/{requireDescription.js → requireDescription.cjs} +2 -2
  76. package/dist/rules/requireDescription.cjs.map +1 -0
  77. package/dist/rules/{requireDescriptionCompleteSentence.js → requireDescriptionCompleteSentence.cjs} +2 -2
  78. package/dist/rules/requireDescriptionCompleteSentence.cjs.map +1 -0
  79. package/dist/rules/{requireExample.js → requireExample.cjs} +2 -2
  80. package/dist/rules/requireExample.cjs.map +1 -0
  81. package/dist/rules/{requireFileOverview.js → requireFileOverview.cjs} +2 -2
  82. package/dist/rules/requireFileOverview.cjs.map +1 -0
  83. package/dist/rules/{requireHyphenBeforeParamDescription.js → requireHyphenBeforeParamDescription.cjs} +2 -2
  84. package/dist/rules/requireHyphenBeforeParamDescription.cjs.map +1 -0
  85. package/dist/rules/{requireJsdoc.js → requireJsdoc.cjs} +5 -5
  86. package/dist/rules/requireJsdoc.cjs.map +1 -0
  87. package/dist/rules/{requireParam.js → requireParam.cjs} +2 -2
  88. package/dist/rules/requireParam.cjs.map +1 -0
  89. package/dist/rules/{requireParamDescription.js → requireParamDescription.cjs} +2 -2
  90. package/dist/rules/requireParamDescription.cjs.map +1 -0
  91. package/dist/rules/{requireParamName.js → requireParamName.cjs} +2 -2
  92. package/dist/rules/requireParamName.cjs.map +1 -0
  93. package/dist/rules/{requireParamType.js → requireParamType.cjs} +2 -2
  94. package/dist/rules/requireParamType.cjs.map +1 -0
  95. package/dist/rules/{requireProperty.js → requireProperty.cjs} +2 -2
  96. package/dist/rules/requireProperty.cjs.map +1 -0
  97. package/dist/rules/{requirePropertyDescription.js → requirePropertyDescription.cjs} +2 -2
  98. package/dist/rules/requirePropertyDescription.cjs.map +1 -0
  99. package/dist/rules/{requirePropertyName.js → requirePropertyName.cjs} +2 -2
  100. package/dist/rules/requirePropertyName.cjs.map +1 -0
  101. package/dist/rules/{requirePropertyType.js → requirePropertyType.cjs} +2 -2
  102. package/dist/rules/requirePropertyType.cjs.map +1 -0
  103. package/dist/rules/{requireReturns.js → requireReturns.cjs} +4 -4
  104. package/dist/rules/requireReturns.cjs.map +1 -0
  105. package/dist/rules/{requireReturnsCheck.js → requireReturnsCheck.cjs} +2 -2
  106. package/dist/rules/requireReturnsCheck.cjs.map +1 -0
  107. package/dist/rules/{requireReturnsDescription.js → requireReturnsDescription.cjs} +2 -2
  108. package/dist/rules/requireReturnsDescription.cjs.map +1 -0
  109. package/dist/rules/{requireReturnsType.js → requireReturnsType.cjs} +2 -2
  110. package/dist/rules/requireReturnsType.cjs.map +1 -0
  111. package/dist/rules/{requireThrows.js → requireThrows.cjs} +2 -2
  112. package/dist/rules/requireThrows.cjs.map +1 -0
  113. package/dist/rules/{requireYields.js → requireYields.cjs} +2 -2
  114. package/dist/rules/requireYields.cjs.map +1 -0
  115. package/dist/rules/{requireYieldsCheck.js → requireYieldsCheck.cjs} +2 -2
  116. package/dist/rules/requireYieldsCheck.cjs.map +1 -0
  117. package/dist/rules/{sortTags.js → sortTags.cjs} +4 -4
  118. package/dist/rules/sortTags.cjs.map +1 -0
  119. package/dist/rules/{tagLines.js → tagLines.cjs} +2 -2
  120. package/dist/rules/tagLines.cjs.map +1 -0
  121. package/dist/rules/{textEscaping.js → textEscaping.cjs} +2 -2
  122. package/dist/rules/textEscaping.cjs.map +1 -0
  123. package/dist/rules/{validTypes.js → validTypes.cjs} +2 -2
  124. package/dist/rules/validTypes.cjs.map +1 -0
  125. package/dist/{tagNames.js → tagNames.cjs} +1 -1
  126. package/dist/tagNames.cjs.map +1 -0
  127. package/dist/utils/{hasReturnValue.js → hasReturnValue.cjs} +14 -17
  128. package/dist/utils/hasReturnValue.cjs.map +1 -0
  129. package/{eslint.config.mjs → eslint.config.js} +34 -28
  130. package/package.json +15 -15
  131. package/src/WarnSettings.js +34 -0
  132. package/src/alignTransform.js +356 -0
  133. package/src/defaultTagOrder.js +168 -0
  134. package/src/exportParser.js +957 -0
  135. package/src/getDefaultTagStructureForMode.js +969 -0
  136. package/src/index.js +266 -0
  137. package/src/iterateJsdoc.js +2555 -0
  138. package/src/jsdocUtils.js +1693 -0
  139. package/src/rules/checkAccess.js +45 -0
  140. package/src/rules/checkAlignment.js +63 -0
  141. package/src/rules/checkExamples.js +594 -0
  142. package/src/rules/checkIndentation.js +75 -0
  143. package/src/rules/checkLineAlignment.js +364 -0
  144. package/src/rules/checkParamNames.js +404 -0
  145. package/src/rules/checkPropertyNames.js +152 -0
  146. package/src/rules/checkSyntax.js +30 -0
  147. package/src/rules/checkTagNames.js +314 -0
  148. package/src/rules/checkTypes.js +535 -0
  149. package/src/rules/checkValues.js +220 -0
  150. package/src/rules/emptyTags.js +88 -0
  151. package/src/rules/implementsOnClasses.js +64 -0
  152. package/src/rules/importsAsDependencies.js +131 -0
  153. package/src/rules/informativeDocs.js +182 -0
  154. package/src/rules/matchDescription.js +286 -0
  155. package/src/rules/matchName.js +147 -0
  156. package/src/rules/multilineBlocks.js +333 -0
  157. package/src/rules/noBadBlocks.js +109 -0
  158. package/src/rules/noBlankBlockDescriptions.js +69 -0
  159. package/src/rules/noBlankBlocks.js +53 -0
  160. package/src/rules/noDefaults.js +85 -0
  161. package/src/rules/noMissingSyntax.js +195 -0
  162. package/src/rules/noMultiAsterisks.js +134 -0
  163. package/src/rules/noRestrictedSyntax.js +91 -0
  164. package/src/rules/noTypes.js +73 -0
  165. package/src/rules/noUndefinedTypes.js +328 -0
  166. package/src/rules/requireAsteriskPrefix.js +189 -0
  167. package/src/rules/requireDescription.js +161 -0
  168. package/src/rules/requireDescriptionCompleteSentence.js +333 -0
  169. package/src/rules/requireExample.js +118 -0
  170. package/src/rules/requireFileOverview.js +154 -0
  171. package/src/rules/requireHyphenBeforeParamDescription.js +178 -0
  172. package/src/rules/requireJsdoc.js +629 -0
  173. package/src/rules/requireParam.js +592 -0
  174. package/src/rules/requireParamDescription.js +89 -0
  175. package/src/rules/requireParamName.js +55 -0
  176. package/src/rules/requireParamType.js +89 -0
  177. package/src/rules/requireProperty.js +48 -0
  178. package/src/rules/requirePropertyDescription.js +25 -0
  179. package/src/rules/requirePropertyName.js +25 -0
  180. package/src/rules/requirePropertyType.js +25 -0
  181. package/src/rules/requireReturns.js +238 -0
  182. package/src/rules/requireReturnsCheck.js +141 -0
  183. package/src/rules/requireReturnsDescription.js +59 -0
  184. package/src/rules/requireReturnsType.js +51 -0
  185. package/src/rules/requireThrows.js +111 -0
  186. package/src/rules/requireYields.js +216 -0
  187. package/src/rules/requireYieldsCheck.js +208 -0
  188. package/src/rules/sortTags.js +557 -0
  189. package/src/rules/tagLines.js +359 -0
  190. package/src/rules/textEscaping.js +146 -0
  191. package/src/rules/validTypes.js +368 -0
  192. package/src/tagNames.js +234 -0
  193. package/src/utils/hasReturnValue.js +549 -0
  194. package/dist/WarnSettings.js.map +0 -1
  195. package/dist/alignTransform.js.map +0 -1
  196. package/dist/defaultTagOrder.js.map +0 -1
  197. package/dist/exportParser.js.map +0 -1
  198. package/dist/generateRule.js.map +0 -1
  199. package/dist/getDefaultTagStructureForMode.js.map +0 -1
  200. package/dist/index.js.map +0 -1
  201. package/dist/iterateJsdoc.js.map +0 -1
  202. package/dist/jsdocUtils.js.map +0 -1
  203. package/dist/rules/checkAccess.js.map +0 -1
  204. package/dist/rules/checkAlignment.js.map +0 -1
  205. package/dist/rules/checkExamples.js.map +0 -1
  206. package/dist/rules/checkIndentation.js.map +0 -1
  207. package/dist/rules/checkLineAlignment.js.map +0 -1
  208. package/dist/rules/checkParamNames.js.map +0 -1
  209. package/dist/rules/checkPropertyNames.js.map +0 -1
  210. package/dist/rules/checkSyntax.js.map +0 -1
  211. package/dist/rules/checkTagNames.js.map +0 -1
  212. package/dist/rules/checkTypes.js.map +0 -1
  213. package/dist/rules/checkValues.js.map +0 -1
  214. package/dist/rules/emptyTags.js.map +0 -1
  215. package/dist/rules/implementsOnClasses.js.map +0 -1
  216. package/dist/rules/importsAsDependencies.js.map +0 -1
  217. package/dist/rules/informativeDocs.js.map +0 -1
  218. package/dist/rules/matchDescription.js.map +0 -1
  219. package/dist/rules/matchName.js.map +0 -1
  220. package/dist/rules/multilineBlocks.js.map +0 -1
  221. package/dist/rules/noBadBlocks.js.map +0 -1
  222. package/dist/rules/noBlankBlockDescriptions.js.map +0 -1
  223. package/dist/rules/noBlankBlocks.js.map +0 -1
  224. package/dist/rules/noDefaults.js.map +0 -1
  225. package/dist/rules/noMissingSyntax.js.map +0 -1
  226. package/dist/rules/noMultiAsterisks.js.map +0 -1
  227. package/dist/rules/noRestrictedSyntax.js.map +0 -1
  228. package/dist/rules/noTypes.js.map +0 -1
  229. package/dist/rules/noUndefinedTypes.js.map +0 -1
  230. package/dist/rules/requireAsteriskPrefix.js.map +0 -1
  231. package/dist/rules/requireDescription.js.map +0 -1
  232. package/dist/rules/requireDescriptionCompleteSentence.js.map +0 -1
  233. package/dist/rules/requireExample.js.map +0 -1
  234. package/dist/rules/requireFileOverview.js.map +0 -1
  235. package/dist/rules/requireHyphenBeforeParamDescription.js.map +0 -1
  236. package/dist/rules/requireJsdoc.js.map +0 -1
  237. package/dist/rules/requireParam.js.map +0 -1
  238. package/dist/rules/requireParamDescription.js.map +0 -1
  239. package/dist/rules/requireParamName.js.map +0 -1
  240. package/dist/rules/requireParamType.js.map +0 -1
  241. package/dist/rules/requireProperty.js.map +0 -1
  242. package/dist/rules/requirePropertyDescription.js.map +0 -1
  243. package/dist/rules/requirePropertyName.js.map +0 -1
  244. package/dist/rules/requirePropertyType.js.map +0 -1
  245. package/dist/rules/requireReturns.js.map +0 -1
  246. package/dist/rules/requireReturnsCheck.js.map +0 -1
  247. package/dist/rules/requireReturnsDescription.js.map +0 -1
  248. package/dist/rules/requireReturnsType.js.map +0 -1
  249. package/dist/rules/requireThrows.js.map +0 -1
  250. package/dist/rules/requireYields.js.map +0 -1
  251. package/dist/rules/requireYieldsCheck.js.map +0 -1
  252. package/dist/rules/sortTags.js.map +0 -1
  253. package/dist/rules/tagLines.js.map +0 -1
  254. package/dist/rules/textEscaping.js.map +0 -1
  255. package/dist/rules/validTypes.js.map +0 -1
  256. package/dist/tagNames.js.map +0 -1
  257. package/dist/utils/hasReturnValue.js.map +0 -1
@@ -0,0 +1,404 @@
1
+ import iterateJsdoc from '../iterateJsdoc.js';
2
+
3
+ /**
4
+ * @param {string} targetTagName
5
+ * @param {boolean} allowExtraTrailingParamDocs
6
+ * @param {boolean} checkDestructured
7
+ * @param {boolean} checkRestProperty
8
+ * @param {RegExp} checkTypesRegex
9
+ * @param {boolean} disableExtraPropertyReporting
10
+ * @param {boolean} enableFixer
11
+ * @param {import('../jsdocUtils.js').ParamNameInfo[]} functionParameterNames
12
+ * @param {import('comment-parser').Block} jsdoc
13
+ * @param {import('../iterateJsdoc.js').Utils} utils
14
+ * @param {import('../iterateJsdoc.js').Report} report
15
+ * @returns {boolean}
16
+ */
17
+ const validateParameterNames = (
18
+ targetTagName,
19
+ allowExtraTrailingParamDocs,
20
+ checkDestructured,
21
+ checkRestProperty,
22
+ checkTypesRegex,
23
+ disableExtraPropertyReporting,
24
+ enableFixer,
25
+ functionParameterNames, jsdoc, utils, report,
26
+ ) => {
27
+ const paramTags = Object.entries(jsdoc.tags).filter(([
28
+ , tag,
29
+ ]) => {
30
+ return tag.tag === targetTagName;
31
+ });
32
+ const paramTagsNonNested = paramTags.filter(([
33
+ , tag,
34
+ ]) => {
35
+ return !tag.name.includes('.');
36
+ });
37
+
38
+ let dotted = 0;
39
+ let thisOffset = 0;
40
+
41
+ // eslint-disable-next-line complexity
42
+ return paramTags.some(([
43
+ , tag,
44
+ ], index) => {
45
+ /** @type {import('../iterateJsdoc.js').Integer} */
46
+ let tagsIndex;
47
+ const dupeTagInfo = paramTags.find(([
48
+ tgsIndex,
49
+ tg,
50
+ ], idx) => {
51
+ tagsIndex = Number(tgsIndex);
52
+
53
+ return tg.name === tag.name && idx !== index;
54
+ });
55
+ if (dupeTagInfo) {
56
+ utils.reportJSDoc(`Duplicate @${targetTagName} "${tag.name}"`, dupeTagInfo[1], enableFixer ? () => {
57
+ utils.removeTag(tagsIndex);
58
+ } : null);
59
+
60
+ return true;
61
+ }
62
+
63
+ if (tag.name.includes('.')) {
64
+ dotted++;
65
+
66
+ return false;
67
+ }
68
+
69
+ let functionParameterName = functionParameterNames[index - dotted + thisOffset];
70
+ if (functionParameterName === 'this' && tag.name.trim() !== 'this') {
71
+ ++thisOffset;
72
+ functionParameterName = functionParameterNames[index - dotted + thisOffset];
73
+ }
74
+
75
+ if (!functionParameterName) {
76
+ if (allowExtraTrailingParamDocs) {
77
+ return false;
78
+ }
79
+
80
+ report(
81
+ `@${targetTagName} "${tag.name}" does not match an existing function parameter.`,
82
+ null,
83
+ tag,
84
+ );
85
+
86
+ return true;
87
+ }
88
+
89
+ if (Array.isArray(functionParameterName)) {
90
+ if (!checkDestructured) {
91
+ return false;
92
+ }
93
+
94
+ if (tag.type && tag.type.search(checkTypesRegex) === -1) {
95
+ return false;
96
+ }
97
+
98
+ const [
99
+ parameterName,
100
+ {
101
+ names: properties,
102
+ hasPropertyRest,
103
+ rests,
104
+ annotationParamName,
105
+ },
106
+ ] =
107
+ /**
108
+ * @type {[string | undefined, import('../jsdocUtils.js').FlattendRootInfo & {
109
+ * annotationParamName?: string | undefined;
110
+ }]} */ (functionParameterName);
111
+ if (annotationParamName !== undefined) {
112
+ const name = tag.name.trim();
113
+ if (name !== annotationParamName) {
114
+ report(`@${targetTagName} "${name}" does not match parameter name "${annotationParamName}"`, null, tag);
115
+ }
116
+ }
117
+
118
+ const tagName = parameterName === undefined ? tag.name.trim() : parameterName;
119
+ const expectedNames = properties.map((name) => {
120
+ return `${tagName}.${name}`;
121
+ });
122
+ const actualNames = paramTags.map(([
123
+ , paramTag,
124
+ ]) => {
125
+ return paramTag.name.trim();
126
+ });
127
+ const actualTypes = paramTags.map(([
128
+ , paramTag,
129
+ ]) => {
130
+ return paramTag.type;
131
+ });
132
+
133
+ const missingProperties = [];
134
+
135
+ /** @type {string[]} */
136
+ const notCheckingNames = [];
137
+
138
+ for (const [
139
+ idx,
140
+ name,
141
+ ] of expectedNames.entries()) {
142
+ if (notCheckingNames.some((notCheckingName) => {
143
+ return name.startsWith(notCheckingName);
144
+ })) {
145
+ continue;
146
+ }
147
+
148
+ const actualNameIdx = actualNames.findIndex((actualName) => {
149
+ return utils.comparePaths(name)(actualName);
150
+ });
151
+ if (actualNameIdx === -1) {
152
+ if (!checkRestProperty && rests[idx]) {
153
+ continue;
154
+ }
155
+
156
+ const missingIndex = actualNames.findIndex((actualName) => {
157
+ return utils.pathDoesNotBeginWith(name, actualName);
158
+ });
159
+ const line = tag.source[0].number - 1 + (missingIndex > -1 ? missingIndex : actualNames.length);
160
+ missingProperties.push({
161
+ name,
162
+ tagPlacement: {
163
+ line: line === 0 ? 1 : line,
164
+ },
165
+ });
166
+ } else if (actualTypes[actualNameIdx].search(checkTypesRegex) === -1 && actualTypes[actualNameIdx] !== '') {
167
+ notCheckingNames.push(name);
168
+ }
169
+ }
170
+
171
+ const hasMissing = missingProperties.length;
172
+ if (hasMissing) {
173
+ for (const {
174
+ tagPlacement,
175
+ name: missingProperty,
176
+ } of missingProperties) {
177
+ report(`Missing @${targetTagName} "${missingProperty}"`, null, tagPlacement);
178
+ }
179
+ }
180
+
181
+ if (!hasPropertyRest || checkRestProperty) {
182
+ /** @type {[string, import('comment-parser').Spec][]} */
183
+ const extraProperties = [];
184
+ for (const [
185
+ idx,
186
+ name,
187
+ ] of actualNames.entries()) {
188
+ const match = name.startsWith(tag.name.trim() + '.');
189
+ if (
190
+ match && !expectedNames.some(
191
+ utils.comparePaths(name),
192
+ ) && !utils.comparePaths(name)(tag.name) &&
193
+ (!disableExtraPropertyReporting || properties.some((prop) => {
194
+ return prop.split('.').length >= name.split('.').length - 1;
195
+ }))
196
+ ) {
197
+ extraProperties.push([
198
+ name, paramTags[idx][1],
199
+ ]);
200
+ }
201
+ }
202
+
203
+ if (extraProperties.length) {
204
+ for (const [
205
+ extraProperty,
206
+ tg,
207
+ ] of extraProperties) {
208
+ report(`@${targetTagName} "${extraProperty}" does not exist on ${tag.name}`, null, tg);
209
+ }
210
+
211
+ return true;
212
+ }
213
+ }
214
+
215
+ return hasMissing;
216
+ }
217
+
218
+ let funcParamName;
219
+ if (typeof functionParameterName === 'object') {
220
+ const {
221
+ name,
222
+ } = functionParameterName;
223
+ funcParamName = name;
224
+ } else {
225
+ funcParamName = functionParameterName;
226
+ }
227
+
228
+ if (funcParamName !== tag.name.trim()) {
229
+ // Todo: Improve for array or object child items
230
+ const actualNames = paramTagsNonNested.map(([
231
+ , {
232
+ name,
233
+ },
234
+ ]) => {
235
+ return name.trim();
236
+ });
237
+ const expectedNames = functionParameterNames.map((item, idx) => {
238
+ if (/**
239
+ * @type {[string|undefined, (import('../jsdocUtils.js').FlattendRootInfo & {
240
+ * annotationParamName?: string,
241
+ })]} */ (item)?.[1]?.names) {
242
+ return actualNames[idx];
243
+ }
244
+
245
+ return item;
246
+ }).filter((item) => {
247
+ return item !== 'this';
248
+ }).join(', ');
249
+
250
+ report(
251
+ `Expected @${targetTagName} names to be "${expectedNames}". Got "${actualNames.join(', ')}".`,
252
+ null,
253
+ tag,
254
+ );
255
+
256
+ return true;
257
+ }
258
+
259
+ return false;
260
+ });
261
+ };
262
+
263
+ /**
264
+ * @param {string} targetTagName
265
+ * @param {boolean} _allowExtraTrailingParamDocs
266
+ * @param {{
267
+ * name: string,
268
+ * idx: import('../iterateJsdoc.js').Integer
269
+ * }[]} jsdocParameterNames
270
+ * @param {import('comment-parser').Block} jsdoc
271
+ * @param {Function} report
272
+ * @returns {boolean}
273
+ */
274
+ const validateParameterNamesDeep = (
275
+ targetTagName, _allowExtraTrailingParamDocs,
276
+ jsdocParameterNames, jsdoc, report,
277
+ ) => {
278
+ /** @type {string} */
279
+ let lastRealParameter;
280
+
281
+ return jsdocParameterNames.some(({
282
+ name: jsdocParameterName,
283
+ idx,
284
+ }) => {
285
+ const isPropertyPath = jsdocParameterName.includes('.');
286
+
287
+ if (isPropertyPath) {
288
+ if (!lastRealParameter) {
289
+ report(`@${targetTagName} path declaration ("${jsdocParameterName}") appears before any real parameter.`, null, jsdoc.tags[idx]);
290
+
291
+ return true;
292
+ }
293
+
294
+ let pathRootNodeName = jsdocParameterName.slice(0, jsdocParameterName.indexOf('.'));
295
+
296
+ if (pathRootNodeName.endsWith('[]')) {
297
+ pathRootNodeName = pathRootNodeName.slice(0, -2);
298
+ }
299
+
300
+ if (pathRootNodeName !== lastRealParameter) {
301
+ report(
302
+ `@${targetTagName} path declaration ("${jsdocParameterName}") root node name ("${pathRootNodeName}") ` +
303
+ `does not match previous real parameter name ("${lastRealParameter}").`,
304
+ null,
305
+ jsdoc.tags[idx],
306
+ );
307
+
308
+ return true;
309
+ }
310
+ } else {
311
+ lastRealParameter = jsdocParameterName;
312
+ }
313
+
314
+ return false;
315
+ });
316
+ };
317
+
318
+ export default iterateJsdoc(({
319
+ context,
320
+ jsdoc,
321
+ report,
322
+ utils,
323
+ }) => {
324
+ const {
325
+ allowExtraTrailingParamDocs,
326
+ checkDestructured = true,
327
+ checkRestProperty = false,
328
+ checkTypesPattern = '/^(?:[oO]bject|[aA]rray|PlainObject|Generic(?:Object|Array))$/',
329
+ enableFixer = false,
330
+ useDefaultObjectProperties = false,
331
+ disableExtraPropertyReporting = false,
332
+ } = context.options[0] || {};
333
+
334
+ const checkTypesRegex = utils.getRegexFromString(checkTypesPattern);
335
+
336
+ const jsdocParameterNamesDeep = utils.getJsdocTagsDeep('param');
337
+ if (!jsdocParameterNamesDeep || !jsdocParameterNamesDeep.length) {
338
+ return;
339
+ }
340
+
341
+ const functionParameterNames = utils.getFunctionParameterNames(useDefaultObjectProperties);
342
+ const targetTagName = /** @type {string} */ (utils.getPreferredTagName({
343
+ tagName: 'param',
344
+ }));
345
+ const isError = validateParameterNames(
346
+ targetTagName,
347
+ allowExtraTrailingParamDocs,
348
+ checkDestructured,
349
+ checkRestProperty,
350
+ checkTypesRegex,
351
+ disableExtraPropertyReporting,
352
+ enableFixer,
353
+ functionParameterNames,
354
+ jsdoc,
355
+ utils,
356
+ report,
357
+ );
358
+
359
+ if (isError || !checkDestructured) {
360
+ return;
361
+ }
362
+
363
+ validateParameterNamesDeep(
364
+ targetTagName, allowExtraTrailingParamDocs, jsdocParameterNamesDeep, jsdoc, report,
365
+ );
366
+ }, {
367
+ meta: {
368
+ docs: {
369
+ description: 'Ensures that parameter names in JSDoc match those in the function declaration.',
370
+ url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-param-names.md#repos-sticky-header',
371
+ },
372
+ fixable: 'code',
373
+ schema: [
374
+ {
375
+ additionalProperties: false,
376
+ properties: {
377
+ allowExtraTrailingParamDocs: {
378
+ type: 'boolean',
379
+ },
380
+ checkDestructured: {
381
+ type: 'boolean',
382
+ },
383
+ checkRestProperty: {
384
+ type: 'boolean',
385
+ },
386
+ checkTypesPattern: {
387
+ type: 'string',
388
+ },
389
+ disableExtraPropertyReporting: {
390
+ type: 'boolean',
391
+ },
392
+ enableFixer: {
393
+ type: 'boolean',
394
+ },
395
+ useDefaultObjectProperties: {
396
+ type: 'boolean',
397
+ },
398
+ },
399
+ type: 'object',
400
+ },
401
+ ],
402
+ type: 'suggestion',
403
+ },
404
+ });
@@ -0,0 +1,152 @@
1
+ import iterateJsdoc from '../iterateJsdoc.js';
2
+
3
+ /**
4
+ * @param {string} targetTagName
5
+ * @param {boolean} enableFixer
6
+ * @param {import('comment-parser').Block} jsdoc
7
+ * @param {import('../iterateJsdoc.js').Utils} utils
8
+ * @returns {boolean}
9
+ */
10
+ const validatePropertyNames = (
11
+ targetTagName,
12
+ enableFixer,
13
+ jsdoc, utils,
14
+ ) => {
15
+ const propertyTags = Object.entries(jsdoc.tags).filter(([
16
+ , tag,
17
+ ]) => {
18
+ return tag.tag === targetTagName;
19
+ });
20
+
21
+ return propertyTags.some(([
22
+ , tag,
23
+ ], index) => {
24
+ /** @type {import('../iterateJsdoc.js').Integer} */
25
+ let tagsIndex;
26
+ const dupeTagInfo = propertyTags.find(([
27
+ tgsIndex,
28
+ tg,
29
+ ], idx) => {
30
+ tagsIndex = Number(tgsIndex);
31
+
32
+ return tg.name === tag.name && idx !== index;
33
+ });
34
+ if (dupeTagInfo) {
35
+ utils.reportJSDoc(`Duplicate @${targetTagName} "${tag.name}"`, dupeTagInfo[1], enableFixer ? () => {
36
+ utils.removeTag(tagsIndex);
37
+ } : null);
38
+
39
+ return true;
40
+ }
41
+
42
+ return false;
43
+ });
44
+ };
45
+
46
+ /**
47
+ * @param {string} targetTagName
48
+ * @param {{
49
+ * idx: number;
50
+ * name: string;
51
+ * type: string;
52
+ * }[]} jsdocPropertyNames
53
+ * @param {import('comment-parser').Block} jsdoc
54
+ * @param {Function} report
55
+ */
56
+ const validatePropertyNamesDeep = (
57
+ targetTagName,
58
+ jsdocPropertyNames, jsdoc, report,
59
+ ) => {
60
+ /** @type {string} */
61
+ let lastRealProperty;
62
+
63
+ return jsdocPropertyNames.some(({
64
+ name: jsdocPropertyName,
65
+ idx,
66
+ }) => {
67
+ const isPropertyPath = jsdocPropertyName.includes('.');
68
+
69
+ if (isPropertyPath) {
70
+ if (!lastRealProperty) {
71
+ report(`@${targetTagName} path declaration ("${jsdocPropertyName}") appears before any real property.`, null, jsdoc.tags[idx]);
72
+
73
+ return true;
74
+ }
75
+
76
+ let pathRootNodeName = jsdocPropertyName.slice(0, jsdocPropertyName.indexOf('.'));
77
+
78
+ if (pathRootNodeName.endsWith('[]')) {
79
+ pathRootNodeName = pathRootNodeName.slice(0, -2);
80
+ }
81
+
82
+ if (pathRootNodeName !== lastRealProperty) {
83
+ report(
84
+ `@${targetTagName} path declaration ("${jsdocPropertyName}") root node name ("${pathRootNodeName}") ` +
85
+ `does not match previous real property name ("${lastRealProperty}").`,
86
+ null,
87
+ jsdoc.tags[idx],
88
+ );
89
+
90
+ return true;
91
+ }
92
+ } else {
93
+ lastRealProperty = jsdocPropertyName;
94
+ }
95
+
96
+ return false;
97
+ });
98
+ };
99
+
100
+ export default iterateJsdoc(({
101
+ context,
102
+ jsdoc,
103
+ report,
104
+ utils,
105
+ }) => {
106
+ const {
107
+ enableFixer = false,
108
+ } = context.options[0] || {};
109
+ const jsdocPropertyNamesDeep = utils.getJsdocTagsDeep('property');
110
+ if (!jsdocPropertyNamesDeep || !jsdocPropertyNamesDeep.length) {
111
+ return;
112
+ }
113
+
114
+ const targetTagName = /** @type {string} */ (utils.getPreferredTagName({
115
+ tagName: 'property',
116
+ }));
117
+ const isError = validatePropertyNames(
118
+ targetTagName,
119
+ enableFixer,
120
+ jsdoc,
121
+ utils,
122
+ );
123
+
124
+ if (isError) {
125
+ return;
126
+ }
127
+
128
+ validatePropertyNamesDeep(
129
+ targetTagName, jsdocPropertyNamesDeep, jsdoc, report,
130
+ );
131
+ }, {
132
+ iterateAllJsdocs: true,
133
+ meta: {
134
+ docs: {
135
+ description: 'Ensures that property names in JSDoc are not duplicated on the same block and that nested properties have defined roots.',
136
+ url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-property-names.md#repos-sticky-header',
137
+ },
138
+ fixable: 'code',
139
+ schema: [
140
+ {
141
+ additionalProperties: false,
142
+ properties: {
143
+ enableFixer: {
144
+ type: 'boolean',
145
+ },
146
+ },
147
+ type: 'object',
148
+ },
149
+ ],
150
+ type: 'suggestion',
151
+ },
152
+ });
@@ -0,0 +1,30 @@
1
+ import iterateJsdoc from '../iterateJsdoc.js';
2
+
3
+ export default iterateJsdoc(({
4
+ jsdoc,
5
+ report,
6
+ settings,
7
+ }) => {
8
+ const {
9
+ mode,
10
+ } = settings;
11
+
12
+ // Don't check for "permissive" and "closure"
13
+ if (mode === 'jsdoc' || mode === 'typescript') {
14
+ for (const tag of jsdoc.tags) {
15
+ if (tag.type.slice(-1) === '=') {
16
+ report('Syntax should not be Google Closure Compiler style.', null, tag);
17
+ break;
18
+ }
19
+ }
20
+ }
21
+ }, {
22
+ iterateAllJsdocs: true,
23
+ meta: {
24
+ docs: {
25
+ description: 'Reports against syntax not valid for the mode (e.g., Google Closure Compiler in non-Closure mode).',
26
+ url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-syntax.md#repos-sticky-header',
27
+ },
28
+ type: 'suggestion',
29
+ },
30
+ });