eslint-plugin-jsdoc 48.0.0 → 48.0.2

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 (64) hide show
  1. package/package.json +2 -2
  2. package/src/WarnSettings.js +34 -0
  3. package/src/alignTransform.js +356 -0
  4. package/src/defaultTagOrder.js +168 -0
  5. package/src/exportParser.js +957 -0
  6. package/src/getDefaultTagStructureForMode.js +969 -0
  7. package/src/index.js +266 -0
  8. package/src/iterateJsdoc.js +2555 -0
  9. package/src/jsdocUtils.js +1693 -0
  10. package/src/rules/checkAccess.js +45 -0
  11. package/src/rules/checkAlignment.js +63 -0
  12. package/src/rules/checkExamples.js +594 -0
  13. package/src/rules/checkIndentation.js +75 -0
  14. package/src/rules/checkLineAlignment.js +364 -0
  15. package/src/rules/checkParamNames.js +404 -0
  16. package/src/rules/checkPropertyNames.js +152 -0
  17. package/src/rules/checkSyntax.js +30 -0
  18. package/src/rules/checkTagNames.js +314 -0
  19. package/src/rules/checkTypes.js +535 -0
  20. package/src/rules/checkValues.js +220 -0
  21. package/src/rules/emptyTags.js +88 -0
  22. package/src/rules/implementsOnClasses.js +64 -0
  23. package/src/rules/importsAsDependencies.js +131 -0
  24. package/src/rules/informativeDocs.js +182 -0
  25. package/src/rules/matchDescription.js +286 -0
  26. package/src/rules/matchName.js +147 -0
  27. package/src/rules/multilineBlocks.js +333 -0
  28. package/src/rules/noBadBlocks.js +109 -0
  29. package/src/rules/noBlankBlockDescriptions.js +69 -0
  30. package/src/rules/noBlankBlocks.js +53 -0
  31. package/src/rules/noDefaults.js +85 -0
  32. package/src/rules/noMissingSyntax.js +195 -0
  33. package/src/rules/noMultiAsterisks.js +134 -0
  34. package/src/rules/noRestrictedSyntax.js +91 -0
  35. package/src/rules/noTypes.js +73 -0
  36. package/src/rules/noUndefinedTypes.js +328 -0
  37. package/src/rules/requireAsteriskPrefix.js +189 -0
  38. package/src/rules/requireDescription.js +161 -0
  39. package/src/rules/requireDescriptionCompleteSentence.js +333 -0
  40. package/src/rules/requireExample.js +118 -0
  41. package/src/rules/requireFileOverview.js +154 -0
  42. package/src/rules/requireHyphenBeforeParamDescription.js +178 -0
  43. package/src/rules/requireJsdoc.js +629 -0
  44. package/src/rules/requireParam.js +592 -0
  45. package/src/rules/requireParamDescription.js +89 -0
  46. package/src/rules/requireParamName.js +55 -0
  47. package/src/rules/requireParamType.js +89 -0
  48. package/src/rules/requireProperty.js +48 -0
  49. package/src/rules/requirePropertyDescription.js +25 -0
  50. package/src/rules/requirePropertyName.js +25 -0
  51. package/src/rules/requirePropertyType.js +25 -0
  52. package/src/rules/requireReturns.js +238 -0
  53. package/src/rules/requireReturnsCheck.js +141 -0
  54. package/src/rules/requireReturnsDescription.js +59 -0
  55. package/src/rules/requireReturnsType.js +51 -0
  56. package/src/rules/requireThrows.js +111 -0
  57. package/src/rules/requireYields.js +216 -0
  58. package/src/rules/requireYieldsCheck.js +208 -0
  59. package/src/rules/sortTags.js +557 -0
  60. package/src/rules/tagLines.js +359 -0
  61. package/src/rules/textEscaping.js +146 -0
  62. package/src/rules/validTypes.js +368 -0
  63. package/src/tagNames.js +234 -0
  64. package/src/utils/hasReturnValue.js +549 -0
@@ -0,0 +1,286 @@
1
+ import iterateJsdoc from '../iterateJsdoc.js';
2
+
3
+ // If supporting Node >= 10, we could loosen the default to this for the
4
+ // initial letter: \\p{Upper}
5
+ const matchDescriptionDefault = '^\n?([A-Z`\\d_][\\s\\S]*[.?!`]\\s*)?$';
6
+
7
+ /**
8
+ * @param {string} value
9
+ * @param {string} userDefault
10
+ * @returns {string}
11
+ */
12
+ const stringOrDefault = (value, userDefault) => {
13
+ return typeof value === 'string' ?
14
+ value :
15
+ userDefault || matchDescriptionDefault;
16
+ };
17
+
18
+ export default iterateJsdoc(({
19
+ jsdoc,
20
+ report,
21
+ context,
22
+ utils,
23
+ }) => {
24
+ const {
25
+ mainDescription,
26
+ matchDescription,
27
+ message,
28
+ nonemptyTags = true,
29
+ tags = {},
30
+ } = context.options[0] || {};
31
+
32
+ /**
33
+ * @param {string} desc
34
+ * @param {import('comment-parser').Spec} [tag]
35
+ * @returns {void}
36
+ */
37
+ const validateDescription = (desc, tag) => {
38
+ let mainDescriptionMatch = mainDescription;
39
+ let errorMessage = message;
40
+ if (typeof mainDescription === 'object') {
41
+ mainDescriptionMatch = mainDescription.match;
42
+ errorMessage = mainDescription.message;
43
+ }
44
+
45
+ if (mainDescriptionMatch === false && (
46
+ !tag || !Object.prototype.hasOwnProperty.call(tags, tag.tag))
47
+ ) {
48
+ return;
49
+ }
50
+
51
+ let tagValue = mainDescriptionMatch;
52
+ if (tag) {
53
+ const tagName = tag.tag;
54
+ if (typeof tags[tagName] === 'object') {
55
+ tagValue = tags[tagName].match;
56
+ errorMessage = tags[tagName].message;
57
+ } else {
58
+ tagValue = tags[tagName];
59
+ }
60
+ }
61
+
62
+ const regex = utils.getRegexFromString(
63
+ stringOrDefault(tagValue, matchDescription),
64
+ );
65
+
66
+ if (!regex.test(desc)) {
67
+ report(
68
+ errorMessage || 'JSDoc description does not satisfy the regex pattern.',
69
+ null,
70
+ tag || {
71
+ // Add one as description would typically be into block
72
+ line: jsdoc.source[0].number + 1,
73
+ },
74
+ );
75
+ }
76
+ };
77
+
78
+ const {
79
+ description,
80
+ } = utils.getDescription();
81
+ if (description) {
82
+ validateDescription(description);
83
+ }
84
+
85
+ /**
86
+ * @param {string} tagName
87
+ * @returns {boolean}
88
+ */
89
+ const hasNoTag = (tagName) => {
90
+ return !tags[tagName];
91
+ };
92
+
93
+ for (const tag of [
94
+ 'description',
95
+ 'summary',
96
+ 'file',
97
+ 'classdesc',
98
+ ]) {
99
+ utils.forEachPreferredTag(tag, (matchingJsdocTag, targetTagName) => {
100
+ const desc = (matchingJsdocTag.name + ' ' + utils.getTagDescription(matchingJsdocTag)).trim();
101
+ if (hasNoTag(targetTagName)) {
102
+ validateDescription(desc, matchingJsdocTag);
103
+ }
104
+ }, true);
105
+ }
106
+
107
+ if (nonemptyTags) {
108
+ for (const tag of [
109
+ 'copyright',
110
+ 'example',
111
+ 'see',
112
+ 'todo',
113
+ ]) {
114
+ utils.forEachPreferredTag(tag, (matchingJsdocTag, targetTagName) => {
115
+ const desc = (matchingJsdocTag.name + ' ' + utils.getTagDescription(matchingJsdocTag)).trim();
116
+
117
+ if (hasNoTag(targetTagName) && !(/.+/u).test(desc)) {
118
+ report(
119
+ 'JSDoc description must not be empty.',
120
+ null,
121
+ matchingJsdocTag,
122
+ );
123
+ }
124
+ });
125
+ }
126
+ }
127
+
128
+ if (!Object.keys(tags).length) {
129
+ return;
130
+ }
131
+
132
+ /**
133
+ * @param {string} tagName
134
+ * @returns {boolean}
135
+ */
136
+ const hasOptionTag = (tagName) => {
137
+ return Boolean(tags[tagName]);
138
+ };
139
+
140
+ const whitelistedTags = utils.filterTags(({
141
+ tag: tagName,
142
+ }) => {
143
+ return hasOptionTag(tagName);
144
+ });
145
+ const {
146
+ tagsWithNames,
147
+ tagsWithoutNames,
148
+ } = utils.getTagsByType(whitelistedTags);
149
+
150
+ tagsWithNames.some((tag) => {
151
+ const desc = /** @type {string} */ (
152
+ utils.getTagDescription(tag)
153
+ ).replace(/^[- ]*/u, '')
154
+ .trim();
155
+
156
+ return validateDescription(desc, tag);
157
+ });
158
+
159
+ tagsWithoutNames.some((tag) => {
160
+ const desc = (tag.name + ' ' + utils.getTagDescription(tag)).trim();
161
+
162
+ return validateDescription(desc, tag);
163
+ });
164
+ }, {
165
+ contextDefaults: true,
166
+ meta: {
167
+ docs: {
168
+ description: 'Enforces a regular expression pattern on descriptions.',
169
+ url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/match-description.md#repos-sticky-header',
170
+ },
171
+ schema: [
172
+ {
173
+ additionalProperties: false,
174
+ properties: {
175
+ contexts: {
176
+ items: {
177
+ anyOf: [
178
+ {
179
+ type: 'string',
180
+ },
181
+ {
182
+ additionalProperties: false,
183
+ properties: {
184
+ comment: {
185
+ type: 'string',
186
+ },
187
+ context: {
188
+ type: 'string',
189
+ },
190
+ },
191
+ type: 'object',
192
+ },
193
+ ],
194
+ },
195
+ type: 'array',
196
+ },
197
+ mainDescription: {
198
+ oneOf: [
199
+ {
200
+ format: 'regex',
201
+ type: 'string',
202
+ },
203
+ {
204
+ type: 'boolean',
205
+ },
206
+ {
207
+ additionalProperties: false,
208
+ properties: {
209
+ match: {
210
+ oneOf: [
211
+ {
212
+ format: 'regex',
213
+ type: 'string',
214
+ },
215
+ {
216
+ type: 'boolean',
217
+ },
218
+ ],
219
+ },
220
+ message: {
221
+ type: 'string',
222
+ },
223
+ },
224
+ type: 'object',
225
+ },
226
+ ],
227
+ },
228
+ matchDescription: {
229
+ format: 'regex',
230
+ type: 'string',
231
+ },
232
+ message: {
233
+ type: 'string',
234
+ },
235
+ nonemptyTags: {
236
+ type: 'boolean',
237
+ },
238
+ tags: {
239
+ patternProperties: {
240
+ '.*': {
241
+ oneOf: [
242
+ {
243
+ format: 'regex',
244
+ type: 'string',
245
+ },
246
+ {
247
+ enum: [
248
+ true,
249
+ ],
250
+ type: 'boolean',
251
+ },
252
+ {
253
+ additionalProperties: false,
254
+ properties: {
255
+ match: {
256
+ oneOf: [
257
+ {
258
+ format: 'regex',
259
+ type: 'string',
260
+ },
261
+ {
262
+ enum: [
263
+ true,
264
+ ],
265
+ type: 'boolean',
266
+ },
267
+ ],
268
+ },
269
+ message: {
270
+ type: 'string',
271
+ },
272
+ },
273
+ type: 'object',
274
+ },
275
+ ],
276
+ },
277
+ },
278
+ type: 'object',
279
+ },
280
+ },
281
+ type: 'object',
282
+ },
283
+ ],
284
+ type: 'suggestion',
285
+ },
286
+ });
@@ -0,0 +1,147 @@
1
+ import iterateJsdoc from '../iterateJsdoc.js';
2
+
3
+ // eslint-disable-next-line complexity
4
+ export default iterateJsdoc(({
5
+ context,
6
+ jsdoc,
7
+ report,
8
+ info: {
9
+ lastIndex,
10
+ },
11
+ utils,
12
+ }) => {
13
+ const {
14
+ match,
15
+ } = context.options[0] || {};
16
+ if (!match) {
17
+ report('Rule `no-restricted-syntax` is missing a `match` option.');
18
+
19
+ return;
20
+ }
21
+
22
+ const {
23
+ allowName,
24
+ disallowName,
25
+ replacement,
26
+ tags = [
27
+ '*',
28
+ ],
29
+ } = match[/** @type {import('../iterateJsdoc.js').Integer} */ (lastIndex)];
30
+
31
+ const allowNameRegex = allowName && utils.getRegexFromString(allowName);
32
+ const disallowNameRegex = disallowName && utils.getRegexFromString(disallowName);
33
+
34
+ let applicableTags = jsdoc.tags;
35
+ if (!tags.includes('*')) {
36
+ applicableTags = utils.getPresentTags(tags);
37
+ }
38
+
39
+ let reported = false;
40
+ for (const tag of applicableTags) {
41
+ const allowed = !allowNameRegex || allowNameRegex.test(tag.name);
42
+ const disallowed = disallowNameRegex && disallowNameRegex.test(tag.name);
43
+ const hasRegex = allowNameRegex || disallowNameRegex;
44
+ if (hasRegex && allowed && !disallowed) {
45
+ continue;
46
+ }
47
+
48
+ if (!hasRegex && reported) {
49
+ continue;
50
+ }
51
+
52
+ const fixer = () => {
53
+ for (const src of tag.source) {
54
+ if (src.tokens.name) {
55
+ src.tokens.name = src.tokens.name.replace(
56
+ disallowNameRegex, replacement,
57
+ );
58
+ break;
59
+ }
60
+ }
61
+ };
62
+
63
+ let {
64
+ message,
65
+ } = match[/** @type {import('../iterateJsdoc.js').Integer} */ (lastIndex)];
66
+ if (!message) {
67
+ if (hasRegex) {
68
+ message = disallowed ?
69
+ `Only allowing names not matching \`${disallowNameRegex}\` but found "${tag.name}".` :
70
+ `Only allowing names matching \`${allowNameRegex}\` but found "${tag.name}".`;
71
+ } else {
72
+ message = `Prohibited context for "${tag.name}".`;
73
+ }
74
+ }
75
+
76
+ utils.reportJSDoc(
77
+ message,
78
+ hasRegex ? tag : null,
79
+
80
+ // We could match up
81
+ disallowNameRegex && replacement !== undefined ?
82
+ fixer :
83
+ null,
84
+ false,
85
+ {
86
+ // Could also supply `context`, `comment`, `tags`
87
+ allowName,
88
+ disallowName,
89
+ name: tag.name,
90
+ },
91
+ );
92
+ if (!hasRegex) {
93
+ reported = true;
94
+ }
95
+ }
96
+ }, {
97
+ matchContext: true,
98
+ meta: {
99
+ docs: {
100
+ description: 'Reports the name portion of a JSDoc tag if matching or not matching a given regular expression.',
101
+ url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/match-name.md#repos-sticky-header',
102
+ },
103
+ fixable: 'code',
104
+ schema: [
105
+ {
106
+ additionalProperties: false,
107
+ properties: {
108
+ match: {
109
+ additionalProperties: false,
110
+ items: {
111
+ properties: {
112
+ allowName: {
113
+ type: 'string',
114
+ },
115
+ comment: {
116
+ type: 'string',
117
+ },
118
+ context: {
119
+ type: 'string',
120
+ },
121
+ disallowName: {
122
+ type: 'string',
123
+ },
124
+ message: {
125
+ type: 'string',
126
+ },
127
+ tags: {
128
+ items: {
129
+ type: 'string',
130
+ },
131
+ type: 'array',
132
+ },
133
+ },
134
+ type: 'object',
135
+ },
136
+ type: 'array',
137
+ },
138
+ },
139
+ required: [
140
+ 'match',
141
+ ],
142
+ type: 'object',
143
+ },
144
+ ],
145
+ type: 'suggestion',
146
+ },
147
+ });