eslint-plugin-jsdoc 63.0.1 → 63.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.
- 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 +3 -12
- 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 +6 -21
- package/src/rules/requireReturnsCheck.js +110 -1
|
@@ -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,
|