eslint-plugin-jsdoc 55.3.0 → 56.0.0

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