eslint-plugin-jsdoc 63.0.1 → 63.0.3
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/dist/cjs/jsdocUtils.d.ts +10 -0
- package/dist/jsdocUtils.cjs +30 -2
- package/dist/jsdocUtils.cjs.map +1 -1
- package/dist/jsdocUtils.d.ts +10 -0
- package/dist/rules/noUndefinedTypes.cjs +14 -13
- package/dist/rules/noUndefinedTypes.cjs.map +1 -1
- package/dist/rules/requireReturnsCheck.cjs +86 -1
- package/dist/rules/requireReturnsCheck.cjs.map +1 -1
- package/package.json +9 -9
- package/src/jsdocUtils.js +38 -0
- package/src/rules/noUndefinedTypes.js +18 -21
- package/src/rules/requireReturnsCheck.js +110 -1
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import iterateJsdoc, {
|
|
2
2
|
parseComment,
|
|
3
3
|
} from '../iterateJsdoc.js';
|
|
4
|
+
import {
|
|
5
|
+
getDocumentNamepathDefiningTags,
|
|
6
|
+
getJSDocCommentBlocks,
|
|
7
|
+
} from '../jsdocUtils.js';
|
|
4
8
|
import {
|
|
5
9
|
getJSDocComment,
|
|
6
10
|
parse as parseType,
|
|
@@ -123,13 +127,7 @@ export default iterateJsdoc(({
|
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
const allComments = sourceCode.getAllComments();
|
|
126
|
-
const comments =
|
|
127
|
-
.filter((comment) => {
|
|
128
|
-
return (/^\*(?!\*)/v).test(comment.value);
|
|
129
|
-
})
|
|
130
|
-
.map((commentNode) => {
|
|
131
|
-
return parseComment(commentNode, '');
|
|
132
|
-
});
|
|
130
|
+
const comments = getJSDocCommentBlocks(sourceCode);
|
|
133
131
|
|
|
134
132
|
const globals = allComments
|
|
135
133
|
.filter((comment) => {
|
|
@@ -138,20 +136,7 @@ export default iterateJsdoc(({
|
|
|
138
136
|
return commentNode.value.replace(/^\s*globals/v, '').trim().split(/,\s*/v);
|
|
139
137
|
}).concat(Object.keys(context.languageOptions.globals ?? []));
|
|
140
138
|
|
|
141
|
-
const typedefs =
|
|
142
|
-
.flatMap((doc) => {
|
|
143
|
-
return doc.tags.filter(({
|
|
144
|
-
tag,
|
|
145
|
-
}) => {
|
|
146
|
-
return utils.isNameOrNamepathDefiningTag(tag) && ![
|
|
147
|
-
'arg',
|
|
148
|
-
'argument',
|
|
149
|
-
'param',
|
|
150
|
-
'prop',
|
|
151
|
-
'property',
|
|
152
|
-
].includes(tag);
|
|
153
|
-
});
|
|
154
|
-
});
|
|
139
|
+
const typedefs = getDocumentNamepathDefiningTags(sourceCode);
|
|
155
140
|
|
|
156
141
|
const typedefDeclarations = typedefs
|
|
157
142
|
.map((tag) => {
|
|
@@ -355,6 +340,17 @@ export default iterateJsdoc(({
|
|
|
355
340
|
/** @type {Set<string>} */
|
|
356
341
|
const closedTypes = new Set();
|
|
357
342
|
|
|
343
|
+
const tsModuleVariables = scopeManager.scopes.find(({
|
|
344
|
+
type,
|
|
345
|
+
}) => {
|
|
346
|
+
// @ts-expect-error TS
|
|
347
|
+
return type === 'tsModule';
|
|
348
|
+
})?.variables.map(({
|
|
349
|
+
name,
|
|
350
|
+
}) => {
|
|
351
|
+
return name;
|
|
352
|
+
}) ?? [];
|
|
353
|
+
|
|
358
354
|
const allDefinedTypes = new Set(globalScope.variables.map(({
|
|
359
355
|
name,
|
|
360
356
|
}) => {
|
|
@@ -446,6 +442,7 @@ export default iterateJsdoc(({
|
|
|
446
442
|
.concat(typedefDeclarations)
|
|
447
443
|
.concat(importTags)
|
|
448
444
|
.concat(definedTypes)
|
|
445
|
+
.concat(tsModuleVariables)
|
|
449
446
|
.concat(/** @type {string[]} */ (definedPreferredTypes))
|
|
450
447
|
.concat((() => {
|
|
451
448
|
// Other methods are not in scope, but we need them, and we grab them here
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import iterateJsdoc from '../iterateJsdoc.js';
|
|
2
2
|
import {
|
|
3
|
+
getDocumentNamepathDefiningTags,
|
|
3
4
|
strictNativeTypes,
|
|
4
5
|
} from '../jsdocUtils.js';
|
|
6
|
+
import {
|
|
7
|
+
traverse,
|
|
8
|
+
tryParse as tryParseType,
|
|
9
|
+
} from '@es-joy/jsdoccomment';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @type {Partial<Record<import('../jsdocUtils.js').ParserMode, import('jsdoc-type-pratt-parser').ParseMode[]>>}
|
|
13
|
+
*/
|
|
14
|
+
const parseTypeModes = {
|
|
15
|
+
closure: [
|
|
16
|
+
'closure',
|
|
17
|
+
],
|
|
18
|
+
jsdoc: [
|
|
19
|
+
'jsdoc',
|
|
20
|
+
],
|
|
21
|
+
typescript: [
|
|
22
|
+
'typescript',
|
|
23
|
+
],
|
|
24
|
+
};
|
|
5
25
|
|
|
6
26
|
/**
|
|
7
27
|
* @param {import('../iterateJsdoc.js').Utils} utils
|
|
@@ -36,11 +56,35 @@ const canSkip = (utils, settings) => {
|
|
|
36
56
|
settings.mode === 'closure' && utils.classHasTag('record');
|
|
37
57
|
};
|
|
38
58
|
|
|
59
|
+
/**
|
|
60
|
+
* @param {import('jsdoc-type-pratt-parser').RootResult} parsedType
|
|
61
|
+
* @returns {import('jsdoc-type-pratt-parser').RootResult}
|
|
62
|
+
*/
|
|
63
|
+
const getReturnTypeLevelNode = (parsedType) => {
|
|
64
|
+
return parsedType.type === 'JsdocTypeParenthesis' ?
|
|
65
|
+
parsedType.element :
|
|
66
|
+
parsedType;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @param {import('eslint').Rule.RuleContext} context
|
|
71
|
+
* @param {import('../jsdocUtils.js').ParserMode} mode
|
|
72
|
+
* @returns {import('../jsdocUtils.js').ParserMode}
|
|
73
|
+
*/
|
|
74
|
+
const getParseMode = (context, mode) => {
|
|
75
|
+
const {
|
|
76
|
+
jsdoc,
|
|
77
|
+
} = /** @type {{jsdoc?: {mode?: import('../jsdocUtils.js').ParserMode}}} */ (context.settings);
|
|
78
|
+
|
|
79
|
+
return jsdoc?.mode ?? mode;
|
|
80
|
+
};
|
|
81
|
+
|
|
39
82
|
export default iterateJsdoc(({
|
|
40
83
|
context,
|
|
41
84
|
node,
|
|
42
85
|
report,
|
|
43
86
|
settings,
|
|
87
|
+
sourceCode,
|
|
44
88
|
utils,
|
|
45
89
|
}) => {
|
|
46
90
|
const {
|
|
@@ -49,6 +93,10 @@ export default iterateJsdoc(({
|
|
|
49
93
|
noNativeTypes = true,
|
|
50
94
|
reportMissingReturnForUndefinedTypes = false,
|
|
51
95
|
} = context.options[0] || {};
|
|
96
|
+
const {
|
|
97
|
+
mode,
|
|
98
|
+
} = settings;
|
|
99
|
+
const parseMode = getParseMode(context, mode);
|
|
52
100
|
|
|
53
101
|
if (canSkip(utils, settings)) {
|
|
54
102
|
return;
|
|
@@ -90,6 +138,67 @@ export default iterateJsdoc(({
|
|
|
90
138
|
}
|
|
91
139
|
|
|
92
140
|
const returnNever = type === 'never';
|
|
141
|
+
const typedefs = getDocumentNamepathDefiningTags(sourceCode);
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {import('comment-parser').Spec} returnTag
|
|
145
|
+
* @returns {boolean}
|
|
146
|
+
*/
|
|
147
|
+
const mayReturnUndefined = (returnTag) => {
|
|
148
|
+
if (utils.mayBeUndefinedTypeTag(returnTag)) {
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const returnType = returnTag.type.trim();
|
|
153
|
+
let parsedType;
|
|
154
|
+
try {
|
|
155
|
+
parsedType = tryParseType(returnType, parseTypeModes[parseMode]);
|
|
156
|
+
} catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const returnTypeLevelNode = getReturnTypeLevelNode(parsedType);
|
|
161
|
+
let returnIsUndefined = false;
|
|
162
|
+
traverse(returnTypeLevelNode, (nde, parentNode) => {
|
|
163
|
+
const isReturnLevelNode = !parentNode ||
|
|
164
|
+
returnTypeLevelNode.type === 'JsdocTypeUnion' && parentNode === returnTypeLevelNode;
|
|
165
|
+
if (!isReturnLevelNode) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const {
|
|
170
|
+
type: nodeType,
|
|
171
|
+
} = /** @type {import('jsdoc-type-pratt-parser').RootResult} */ (nde);
|
|
172
|
+
|
|
173
|
+
if (nodeType === 'JsdocTypeUndefined') {
|
|
174
|
+
returnIsUndefined = true;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (nodeType !== 'JsdocTypeName') {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const {
|
|
183
|
+
value,
|
|
184
|
+
} = /** @type {import('jsdoc-type-pratt-parser').NameResult} */ (nde);
|
|
185
|
+
|
|
186
|
+
if (value === 'void') {
|
|
187
|
+
returnIsUndefined = true;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const referencedTypedef = typedefs.find((typedefTag) => {
|
|
192
|
+
return typedefTag.name === value;
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
if (referencedTypedef && utils.mayBeUndefinedTypeTag(referencedTypedef)) {
|
|
196
|
+
returnIsUndefined = true;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return returnIsUndefined;
|
|
201
|
+
};
|
|
93
202
|
|
|
94
203
|
if (returnNever && utils.hasValueOrExecutorHasNonEmptyResolveValue(false)) {
|
|
95
204
|
report(`JSDoc @${tagName} declaration set with "never" but return expression is present in function.`);
|
|
@@ -107,7 +216,7 @@ export default iterateJsdoc(({
|
|
|
107
216
|
!returnNever &&
|
|
108
217
|
(
|
|
109
218
|
reportMissingReturnForUndefinedTypes ||
|
|
110
|
-
!
|
|
219
|
+
!mayReturnUndefined(tag)
|
|
111
220
|
) &&
|
|
112
221
|
(tag.type === '' && !utils.hasValueOrExecutorHasNonEmptyResolveValue(
|
|
113
222
|
exemptAsync,
|