eslint-plugin-jsdoc 48.0.0 → 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.
- package/package.json +1 -1
- package/src/WarnSettings.js +34 -0
- package/src/alignTransform.js +356 -0
- package/src/defaultTagOrder.js +168 -0
- package/src/exportParser.js +957 -0
- package/src/getDefaultTagStructureForMode.js +969 -0
- package/src/index.js +266 -0
- package/src/iterateJsdoc.js +2555 -0
- package/src/jsdocUtils.js +1693 -0
- package/src/rules/checkAccess.js +45 -0
- package/src/rules/checkAlignment.js +63 -0
- package/src/rules/checkExamples.js +594 -0
- package/src/rules/checkIndentation.js +75 -0
- package/src/rules/checkLineAlignment.js +364 -0
- package/src/rules/checkParamNames.js +404 -0
- package/src/rules/checkPropertyNames.js +152 -0
- package/src/rules/checkSyntax.js +30 -0
- package/src/rules/checkTagNames.js +314 -0
- package/src/rules/checkTypes.js +535 -0
- package/src/rules/checkValues.js +220 -0
- package/src/rules/emptyTags.js +88 -0
- package/src/rules/implementsOnClasses.js +64 -0
- package/src/rules/importsAsDependencies.js +131 -0
- package/src/rules/informativeDocs.js +182 -0
- package/src/rules/matchDescription.js +286 -0
- package/src/rules/matchName.js +147 -0
- package/src/rules/multilineBlocks.js +333 -0
- package/src/rules/noBadBlocks.js +109 -0
- package/src/rules/noBlankBlockDescriptions.js +69 -0
- package/src/rules/noBlankBlocks.js +53 -0
- package/src/rules/noDefaults.js +85 -0
- package/src/rules/noMissingSyntax.js +195 -0
- package/src/rules/noMultiAsterisks.js +134 -0
- package/src/rules/noRestrictedSyntax.js +91 -0
- package/src/rules/noTypes.js +73 -0
- package/src/rules/noUndefinedTypes.js +328 -0
- package/src/rules/requireAsteriskPrefix.js +189 -0
- package/src/rules/requireDescription.js +161 -0
- package/src/rules/requireDescriptionCompleteSentence.js +333 -0
- package/src/rules/requireExample.js +118 -0
- package/src/rules/requireFileOverview.js +154 -0
- package/src/rules/requireHyphenBeforeParamDescription.js +178 -0
- package/src/rules/requireJsdoc.js +629 -0
- package/src/rules/requireParam.js +592 -0
- package/src/rules/requireParamDescription.js +89 -0
- package/src/rules/requireParamName.js +55 -0
- package/src/rules/requireParamType.js +89 -0
- package/src/rules/requireProperty.js +48 -0
- package/src/rules/requirePropertyDescription.js +25 -0
- package/src/rules/requirePropertyName.js +25 -0
- package/src/rules/requirePropertyType.js +25 -0
- package/src/rules/requireReturns.js +238 -0
- package/src/rules/requireReturnsCheck.js +141 -0
- package/src/rules/requireReturnsDescription.js +59 -0
- package/src/rules/requireReturnsType.js +51 -0
- package/src/rules/requireThrows.js +111 -0
- package/src/rules/requireYields.js +216 -0
- package/src/rules/requireYieldsCheck.js +208 -0
- package/src/rules/sortTags.js +557 -0
- package/src/rules/tagLines.js +359 -0
- package/src/rules/textEscaping.js +146 -0
- package/src/rules/validTypes.js +368 -0
- package/src/tagNames.js +234 -0
- package/src/utils/hasReturnValue.js +549 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import iterateJsdoc from '../iterateJsdoc.js';
|
|
2
|
+
import escapeStringRegexp from 'escape-string-regexp';
|
|
3
|
+
|
|
4
|
+
// https://babeljs.io/docs/en/babel-plugin-transform-react-jsx/
|
|
5
|
+
const jsxTagNames = new Set([
|
|
6
|
+
'jsx',
|
|
7
|
+
'jsxFrag',
|
|
8
|
+
'jsxImportSource',
|
|
9
|
+
'jsxRuntime',
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
const typedTagsAlwaysUnnecessary = new Set([
|
|
13
|
+
'augments',
|
|
14
|
+
'callback',
|
|
15
|
+
'class',
|
|
16
|
+
'enum',
|
|
17
|
+
'implements',
|
|
18
|
+
'private',
|
|
19
|
+
'property',
|
|
20
|
+
'protected',
|
|
21
|
+
'public',
|
|
22
|
+
'readonly',
|
|
23
|
+
'this',
|
|
24
|
+
'type',
|
|
25
|
+
'typedef',
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
const typedTagsNeedingName = new Set([
|
|
29
|
+
'template',
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
const typedTagsUnnecessaryOutsideDeclare = new Set([
|
|
33
|
+
'abstract',
|
|
34
|
+
'access',
|
|
35
|
+
'class',
|
|
36
|
+
'constant',
|
|
37
|
+
'constructs',
|
|
38
|
+
'default',
|
|
39
|
+
'enum',
|
|
40
|
+
'export',
|
|
41
|
+
'exports',
|
|
42
|
+
'function',
|
|
43
|
+
'global',
|
|
44
|
+
'inherits',
|
|
45
|
+
'instance',
|
|
46
|
+
'interface',
|
|
47
|
+
'member',
|
|
48
|
+
'memberof',
|
|
49
|
+
'memberOf',
|
|
50
|
+
'method',
|
|
51
|
+
'mixes',
|
|
52
|
+
'mixin',
|
|
53
|
+
'module',
|
|
54
|
+
'name',
|
|
55
|
+
'namespace',
|
|
56
|
+
'override',
|
|
57
|
+
'property',
|
|
58
|
+
'requires',
|
|
59
|
+
'static',
|
|
60
|
+
'this',
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
export default iterateJsdoc(({
|
|
64
|
+
sourceCode,
|
|
65
|
+
jsdoc,
|
|
66
|
+
report,
|
|
67
|
+
utils,
|
|
68
|
+
context,
|
|
69
|
+
node,
|
|
70
|
+
settings,
|
|
71
|
+
jsdocNode,
|
|
72
|
+
}) => {
|
|
73
|
+
const
|
|
74
|
+
/**
|
|
75
|
+
* @type {{
|
|
76
|
+
* definedTags: string[],
|
|
77
|
+
* enableFixer: boolean,
|
|
78
|
+
* jsxTags: boolean,
|
|
79
|
+
* typed: boolean
|
|
80
|
+
}} */ {
|
|
81
|
+
definedTags = [],
|
|
82
|
+
enableFixer = true,
|
|
83
|
+
jsxTags,
|
|
84
|
+
typed,
|
|
85
|
+
} = context.options[0] || {};
|
|
86
|
+
|
|
87
|
+
/** @type {(string|undefined)[]} */
|
|
88
|
+
let definedPreferredTags = [];
|
|
89
|
+
const {
|
|
90
|
+
tagNamePreference,
|
|
91
|
+
structuredTags,
|
|
92
|
+
} = settings;
|
|
93
|
+
const definedStructuredTags = Object.keys(structuredTags);
|
|
94
|
+
const definedNonPreferredTags = Object.keys(tagNamePreference);
|
|
95
|
+
if (definedNonPreferredTags.length) {
|
|
96
|
+
definedPreferredTags = Object.values(tagNamePreference).map((preferredTag) => {
|
|
97
|
+
if (typeof preferredTag === 'string') {
|
|
98
|
+
// May become an empty string but will be filtered out below
|
|
99
|
+
return preferredTag;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!preferredTag) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (typeof preferredTag !== 'object') {
|
|
107
|
+
utils.reportSettings(
|
|
108
|
+
'Invalid `settings.jsdoc.tagNamePreference`. Values must be falsy, a string, or an object.',
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return preferredTag.replacement;
|
|
113
|
+
})
|
|
114
|
+
.filter(Boolean);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @param {import('eslint').Rule.Node} subNode
|
|
119
|
+
* @returns {boolean}
|
|
120
|
+
*/
|
|
121
|
+
const isInAmbientContext = (subNode) => {
|
|
122
|
+
return subNode.type === 'Program' ?
|
|
123
|
+
context.getFilename().endsWith('.d.ts') :
|
|
124
|
+
Boolean(
|
|
125
|
+
/** @type {import('@typescript-eslint/types').TSESTree.VariableDeclaration} */ (
|
|
126
|
+
subNode
|
|
127
|
+
).declare,
|
|
128
|
+
) || isInAmbientContext(subNode.parent);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {import('comment-parser').Spec} jsdocTag
|
|
133
|
+
* @returns {boolean}
|
|
134
|
+
*/
|
|
135
|
+
const tagIsRedundantWhenTyped = (jsdocTag) => {
|
|
136
|
+
if (!typedTagsUnnecessaryOutsideDeclare.has(jsdocTag.tag)) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (jsdocTag.tag === 'default') {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (node === null) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (context.getFilename().endsWith('.d.ts') && [
|
|
149
|
+
'Program', null, undefined,
|
|
150
|
+
].includes(node?.parent?.type)) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (isInAmbientContext(/** @type {import('eslint').Rule.Node} */ (node))) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return true;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @param {string} message
|
|
163
|
+
* @param {import('comment-parser').Spec} jsdocTag
|
|
164
|
+
* @param {import('../iterateJsdoc.js').Integer} tagIndex
|
|
165
|
+
* @param {Partial<import('comment-parser').Tokens>} [additionalTagChanges]
|
|
166
|
+
* @returns {void}
|
|
167
|
+
*/
|
|
168
|
+
const reportWithTagRemovalFixer = (message, jsdocTag, tagIndex, additionalTagChanges) => {
|
|
169
|
+
utils.reportJSDoc(message, jsdocTag, enableFixer ? () => {
|
|
170
|
+
if (jsdocTag.description.trim()) {
|
|
171
|
+
utils.changeTag(jsdocTag, {
|
|
172
|
+
postType: '',
|
|
173
|
+
type: '',
|
|
174
|
+
...additionalTagChanges,
|
|
175
|
+
});
|
|
176
|
+
} else {
|
|
177
|
+
utils.removeTag(tagIndex, {
|
|
178
|
+
removeEmptyBlock: true,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
} : null, true);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @param {import('comment-parser').Spec} jsdocTag
|
|
186
|
+
* @param {import('../iterateJsdoc.js').Integer} tagIndex
|
|
187
|
+
* @returns {boolean}
|
|
188
|
+
*/
|
|
189
|
+
const checkTagForTypedValidity = (jsdocTag, tagIndex) => {
|
|
190
|
+
if (typedTagsAlwaysUnnecessary.has(jsdocTag.tag)) {
|
|
191
|
+
reportWithTagRemovalFixer(
|
|
192
|
+
`'@${jsdocTag.tag}' is redundant when using a type system.`,
|
|
193
|
+
jsdocTag,
|
|
194
|
+
tagIndex,
|
|
195
|
+
{
|
|
196
|
+
postTag: '',
|
|
197
|
+
tag: '',
|
|
198
|
+
},
|
|
199
|
+
);
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (tagIsRedundantWhenTyped(jsdocTag)) {
|
|
204
|
+
reportWithTagRemovalFixer(
|
|
205
|
+
`'@${jsdocTag.tag}' is redundant outside of ambient (\`declare\`/\`.d.ts\`) contexts when using a type system.`,
|
|
206
|
+
jsdocTag,
|
|
207
|
+
tagIndex,
|
|
208
|
+
);
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (typedTagsNeedingName.has(jsdocTag.tag) && !jsdocTag.name) {
|
|
213
|
+
reportWithTagRemovalFixer(
|
|
214
|
+
`'@${jsdocTag.tag}' without a name is redundant when using a type system.`,
|
|
215
|
+
jsdocTag,
|
|
216
|
+
tagIndex,
|
|
217
|
+
);
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return false;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
for (let tagIndex = 0; tagIndex < jsdoc.tags.length; tagIndex += 1) {
|
|
225
|
+
const jsdocTag = jsdoc.tags[tagIndex];
|
|
226
|
+
const tagName = jsdocTag.tag;
|
|
227
|
+
if (jsxTags && jsxTagNames.has(tagName)) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (typed && checkTagForTypedValidity(jsdocTag, tagIndex)) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const validTags = [
|
|
236
|
+
...definedTags,
|
|
237
|
+
...(/** @type {string[]} */ (definedPreferredTags)),
|
|
238
|
+
...definedNonPreferredTags,
|
|
239
|
+
...definedStructuredTags,
|
|
240
|
+
...typed ? typedTagsNeedingName : [],
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
if (utils.isValidTag(tagName, validTags)) {
|
|
244
|
+
let preferredTagName = utils.getPreferredTagName({
|
|
245
|
+
allowObjectReturn: true,
|
|
246
|
+
defaultMessage: `Blacklisted tag found (\`@${tagName}\`)`,
|
|
247
|
+
tagName,
|
|
248
|
+
});
|
|
249
|
+
if (!preferredTagName) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
let message;
|
|
254
|
+
if (typeof preferredTagName === 'object') {
|
|
255
|
+
({
|
|
256
|
+
message,
|
|
257
|
+
replacement: preferredTagName,
|
|
258
|
+
} = /** @type {{message: string; replacement?: string | undefined;}} */ (
|
|
259
|
+
preferredTagName
|
|
260
|
+
));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (!message) {
|
|
264
|
+
message = `Invalid JSDoc tag (preference). Replace "${tagName}" JSDoc tag with "${preferredTagName}".`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (preferredTagName !== tagName) {
|
|
268
|
+
report(message, (fixer) => {
|
|
269
|
+
const replacement = sourceCode.getText(jsdocNode).replace(
|
|
270
|
+
new RegExp(`@${escapeStringRegexp(tagName)}\\b`, 'u'),
|
|
271
|
+
`@${preferredTagName}`,
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
return fixer.replaceText(jsdocNode, replacement);
|
|
275
|
+
}, jsdocTag);
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
report(`Invalid JSDoc tag name "${tagName}".`, null, jsdocTag);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}, {
|
|
282
|
+
iterateAllJsdocs: true,
|
|
283
|
+
meta: {
|
|
284
|
+
docs: {
|
|
285
|
+
description: 'Reports invalid block tag names.',
|
|
286
|
+
url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-tag-names.md#repos-sticky-header',
|
|
287
|
+
},
|
|
288
|
+
fixable: 'code',
|
|
289
|
+
schema: [
|
|
290
|
+
{
|
|
291
|
+
additionalProperties: false,
|
|
292
|
+
properties: {
|
|
293
|
+
definedTags: {
|
|
294
|
+
items: {
|
|
295
|
+
type: 'string',
|
|
296
|
+
},
|
|
297
|
+
type: 'array',
|
|
298
|
+
},
|
|
299
|
+
enableFixer: {
|
|
300
|
+
type: 'boolean',
|
|
301
|
+
},
|
|
302
|
+
jsxTags: {
|
|
303
|
+
type: 'boolean',
|
|
304
|
+
},
|
|
305
|
+
typed: {
|
|
306
|
+
type: 'boolean',
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
type: 'object',
|
|
310
|
+
},
|
|
311
|
+
],
|
|
312
|
+
type: 'suggestion',
|
|
313
|
+
},
|
|
314
|
+
});
|