eslint-plugin-jsdoc 61.0.1 → 61.1.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.
- package/README.md +8 -0
- package/dist/cjs/jsdocUtils.d.ts +8 -0
- package/dist/cjs/rules/tsMethodSignatureStyle.d.ts +2 -0
- package/dist/cjs/rules/tsNoEmptyObjectType.d.ts +2 -0
- package/dist/cjs/rules/tsNoUnnecessaryTemplateExpression.d.ts +2 -0
- package/dist/cjs/rules/tsPreferFunctionType.d.ts +2 -0
- package/dist/index-cjs.cjs +12 -0
- package/dist/index-cjs.cjs.map +1 -1
- package/dist/index.cjs +12 -0
- package/dist/index.cjs.map +1 -1
- package/dist/jsdocUtils.cjs +158 -1
- package/dist/jsdocUtils.cjs.map +1 -1
- package/dist/jsdocUtils.d.ts +8 -0
- package/dist/rules/tsMethodSignatureStyle.cjs +240 -0
- package/dist/rules/tsMethodSignatureStyle.cjs.map +1 -0
- package/dist/rules/tsMethodSignatureStyle.d.ts +3 -0
- package/dist/rules/tsNoEmptyObjectType.cjs +62 -0
- package/dist/rules/tsNoEmptyObjectType.cjs.map +1 -0
- package/dist/rules/tsNoEmptyObjectType.d.ts +3 -0
- package/dist/rules/tsNoUnnecessaryTemplateExpression.cjs +104 -0
- package/dist/rules/tsNoUnnecessaryTemplateExpression.cjs.map +1 -0
- package/dist/rules/tsNoUnnecessaryTemplateExpression.d.ts +3 -0
- package/dist/rules/tsPreferFunctionType.cjs +110 -0
- package/dist/rules/tsPreferFunctionType.cjs.map +1 -0
- package/dist/rules/tsPreferFunctionType.d.ts +3 -0
- package/dist/rules/typeFormatting.cjs +2 -128
- package/dist/rules/typeFormatting.cjs.map +1 -1
- package/dist/rules.d.ts +41 -0
- package/package.json +3 -3
- package/src/index-cjs.js +12 -0
- package/src/index.js +12 -0
- package/src/jsdocUtils.js +181 -0
- package/src/rules/tsMethodSignatureStyle.js +300 -0
- package/src/rules/tsNoEmptyObjectType.js +61 -0
- package/src/rules/tsNoUnnecessaryTemplateExpression.js +130 -0
- package/src/rules/tsPreferFunctionType.js +127 -0
- package/src/rules/typeFormatting.js +4 -150
- package/src/rules.d.ts +41 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import iterateJsdoc from '../iterateJsdoc.js';
|
|
2
|
+
import {
|
|
3
|
+
rewireByParsedType,
|
|
4
|
+
} from '../jsdocUtils.js';
|
|
5
|
+
import {
|
|
6
|
+
parse as parseType,
|
|
7
|
+
traverse,
|
|
8
|
+
} from '@es-joy/jsdoccomment';
|
|
9
|
+
|
|
10
|
+
export default iterateJsdoc(({
|
|
11
|
+
context,
|
|
12
|
+
indent,
|
|
13
|
+
jsdoc,
|
|
14
|
+
utils,
|
|
15
|
+
}) => {
|
|
16
|
+
const {
|
|
17
|
+
enableFixer = true,
|
|
18
|
+
} = context.options[0] || {};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {import('@es-joy/jsdoccomment').JsdocTagWithInline} tag
|
|
22
|
+
*/
|
|
23
|
+
const checkType = (tag) => {
|
|
24
|
+
const potentialType = tag.type;
|
|
25
|
+
|
|
26
|
+
/** @type {import('jsdoc-type-pratt-parser').RootResult} */
|
|
27
|
+
let parsedType;
|
|
28
|
+
try {
|
|
29
|
+
parsedType = parseType(
|
|
30
|
+
/** @type {string} */ (potentialType), 'typescript',
|
|
31
|
+
);
|
|
32
|
+
} catch {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
traverse(parsedType, (nde, parentNode) => {
|
|
37
|
+
// @ts-expect-error Adding our own property for use below
|
|
38
|
+
nde.parentNode = parentNode;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
traverse(parsedType, (nde, parentNode, property, index) => {
|
|
42
|
+
switch (nde.type) {
|
|
43
|
+
case 'JsdocTypeCallSignature': {
|
|
44
|
+
const object = /** @type {import('jsdoc-type-pratt-parser').ObjectResult} */ (
|
|
45
|
+
parentNode
|
|
46
|
+
);
|
|
47
|
+
if (typeof index === 'number' && object.elements.length === 1) {
|
|
48
|
+
utils.reportJSDoc(
|
|
49
|
+
'Call signature found; function type preferred.',
|
|
50
|
+
tag,
|
|
51
|
+
enableFixer ? () => {
|
|
52
|
+
const func = /** @type {import('jsdoc-type-pratt-parser').FunctionResult} */ ({
|
|
53
|
+
arrow: true,
|
|
54
|
+
constructor: false,
|
|
55
|
+
meta: /** @type {Required<import('jsdoc-type-pratt-parser').MethodSignatureResult['meta']>} */ (
|
|
56
|
+
nde.meta
|
|
57
|
+
),
|
|
58
|
+
parameters: nde.parameters,
|
|
59
|
+
parenthesis: true,
|
|
60
|
+
returnType: nde.returnType,
|
|
61
|
+
type: 'JsdocTypeFunction',
|
|
62
|
+
typeParameters: nde.typeParameters,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (property && 'parentNode' in object && object.parentNode) {
|
|
66
|
+
if (typeof object.parentNode === 'object' &&
|
|
67
|
+
'elements' in object.parentNode &&
|
|
68
|
+
Array.isArray(object.parentNode.elements)
|
|
69
|
+
) {
|
|
70
|
+
const idx = object.parentNode.elements.indexOf(object);
|
|
71
|
+
object.parentNode.elements[idx] = func;
|
|
72
|
+
/* c8 ignore next 6 -- Guard */
|
|
73
|
+
} else {
|
|
74
|
+
throw new Error(
|
|
75
|
+
// @ts-expect-error Ok
|
|
76
|
+
`Rule currently unable to handle type ${object.parentNode.type}`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
parsedType = func;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
rewireByParsedType(jsdoc, tag, parsedType, indent);
|
|
84
|
+
} : null,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const tags = utils.filterTags(({
|
|
95
|
+
tag,
|
|
96
|
+
}) => {
|
|
97
|
+
return Boolean(tag !== 'import' && utils.tagMightHaveTypePosition(tag));
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
for (const tag of tags) {
|
|
101
|
+
if (tag.type) {
|
|
102
|
+
checkType(tag);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}, {
|
|
106
|
+
iterateAllJsdocs: true,
|
|
107
|
+
meta: {
|
|
108
|
+
docs: {
|
|
109
|
+
description: 'Prefers function types over call signatures when there are no other properties.',
|
|
110
|
+
url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/ts-prefer-function-type.md#repos-sticky-header',
|
|
111
|
+
},
|
|
112
|
+
fixable: 'code',
|
|
113
|
+
schema: [
|
|
114
|
+
{
|
|
115
|
+
additionalProperties: false,
|
|
116
|
+
properties: {
|
|
117
|
+
enableFixer: {
|
|
118
|
+
description: 'Whether to enable the fixer or not',
|
|
119
|
+
type: 'boolean',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
type: 'object',
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
type: 'suggestion',
|
|
126
|
+
},
|
|
127
|
+
});
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import iterateJsdoc from '../iterateJsdoc.js';
|
|
2
|
+
import {
|
|
3
|
+
rewireByParsedType,
|
|
4
|
+
} from '../jsdocUtils.js';
|
|
2
5
|
import {
|
|
3
6
|
parse as parseType,
|
|
4
7
|
stringify,
|
|
@@ -67,156 +70,7 @@ export default iterateJsdoc(({
|
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
const fix = () => {
|
|
70
|
-
|
|
71
|
-
const firstTypeLine = typeLines.shift();
|
|
72
|
-
const lastTypeLine = typeLines.pop();
|
|
73
|
-
|
|
74
|
-
const beginNameOrDescIdx = tag.source.findIndex(({
|
|
75
|
-
tokens,
|
|
76
|
-
}) => {
|
|
77
|
-
return tokens.name || tokens.description;
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
const nameAndDesc = beginNameOrDescIdx === -1 ?
|
|
81
|
-
null :
|
|
82
|
-
tag.source.slice(beginNameOrDescIdx);
|
|
83
|
-
|
|
84
|
-
const initialNumber = tag.source[0].number;
|
|
85
|
-
const src = [
|
|
86
|
-
// Get inevitably present tag from first `tag.source`
|
|
87
|
-
{
|
|
88
|
-
number: initialNumber,
|
|
89
|
-
source: '',
|
|
90
|
-
tokens: {
|
|
91
|
-
...tag.source[0].tokens,
|
|
92
|
-
...(typeLines.length || lastTypeLine ? {
|
|
93
|
-
end: '',
|
|
94
|
-
name: '',
|
|
95
|
-
postName: '',
|
|
96
|
-
postType: '',
|
|
97
|
-
} : {}),
|
|
98
|
-
type: '{' + typeBracketSpacing + firstTypeLine + (!typeLines.length && lastTypeLine === undefined ? typeBracketSpacing + '}' : ''),
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
// Get any intervening type lines
|
|
102
|
-
...(typeLines.length ? typeLines.map((typeLine, idx) => {
|
|
103
|
-
return {
|
|
104
|
-
number: initialNumber + idx + 1,
|
|
105
|
-
source: '',
|
|
106
|
-
tokens: {
|
|
107
|
-
// Grab any delimiter info from first item
|
|
108
|
-
...tag.source[0].tokens,
|
|
109
|
-
delimiter: tag.source[0].tokens.delimiter === '/**' ? '*' : tag.source[0].tokens.delimiter,
|
|
110
|
-
end: '',
|
|
111
|
-
name: '',
|
|
112
|
-
postName: '',
|
|
113
|
-
postTag: '',
|
|
114
|
-
postType: '',
|
|
115
|
-
start: indent + ' ',
|
|
116
|
-
tag: '',
|
|
117
|
-
type: typeLine,
|
|
118
|
-
},
|
|
119
|
-
};
|
|
120
|
-
}) : []),
|
|
121
|
-
];
|
|
122
|
-
|
|
123
|
-
// Merge any final type line and name and description
|
|
124
|
-
if (
|
|
125
|
-
// Name and description may be already included if present with the tag
|
|
126
|
-
nameAndDesc && beginNameOrDescIdx > 0
|
|
127
|
-
) {
|
|
128
|
-
src.push({
|
|
129
|
-
number: src.length + 1,
|
|
130
|
-
source: '',
|
|
131
|
-
tokens: {
|
|
132
|
-
...nameAndDesc[0].tokens,
|
|
133
|
-
type: lastTypeLine + typeBracketSpacing + '}',
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
if (
|
|
138
|
-
// Get any remaining description lines
|
|
139
|
-
nameAndDesc.length > 1
|
|
140
|
-
) {
|
|
141
|
-
src.push(
|
|
142
|
-
...nameAndDesc.slice(1).map(({
|
|
143
|
-
source,
|
|
144
|
-
tokens,
|
|
145
|
-
}, idx) => {
|
|
146
|
-
return {
|
|
147
|
-
number: src.length + idx + 2,
|
|
148
|
-
source,
|
|
149
|
-
tokens,
|
|
150
|
-
};
|
|
151
|
-
}),
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
} else if (nameAndDesc) {
|
|
155
|
-
if (lastTypeLine) {
|
|
156
|
-
src.push({
|
|
157
|
-
number: src.length + 1,
|
|
158
|
-
source: '',
|
|
159
|
-
tokens: {
|
|
160
|
-
...nameAndDesc[0].tokens,
|
|
161
|
-
delimiter: nameAndDesc[0].tokens.delimiter === '/**' ? '*' : nameAndDesc[0].tokens.delimiter,
|
|
162
|
-
postTag: '',
|
|
163
|
-
start: indent + ' ',
|
|
164
|
-
tag: '',
|
|
165
|
-
type: lastTypeLine + typeBracketSpacing + '}',
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (
|
|
171
|
-
// Get any remaining description lines
|
|
172
|
-
nameAndDesc.length > 1
|
|
173
|
-
) {
|
|
174
|
-
src.push(
|
|
175
|
-
...nameAndDesc.slice(1).map(({
|
|
176
|
-
source,
|
|
177
|
-
tokens,
|
|
178
|
-
}, idx) => {
|
|
179
|
-
return {
|
|
180
|
-
number: src.length + idx + 2,
|
|
181
|
-
source,
|
|
182
|
-
tokens,
|
|
183
|
-
};
|
|
184
|
-
}),
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
tag.source = src;
|
|
190
|
-
|
|
191
|
-
// Properly rewire `jsdoc.source`
|
|
192
|
-
const firstTagIdx = jsdoc.source.findIndex(({
|
|
193
|
-
tokens: {
|
|
194
|
-
tag: tg,
|
|
195
|
-
},
|
|
196
|
-
}) => {
|
|
197
|
-
return tg;
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
const initialEndSource = jsdoc.source.find(({
|
|
201
|
-
tokens: {
|
|
202
|
-
end,
|
|
203
|
-
},
|
|
204
|
-
}) => {
|
|
205
|
-
return end;
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
jsdoc.source = [
|
|
209
|
-
...jsdoc.source.slice(0, firstTagIdx),
|
|
210
|
-
...jsdoc.tags.flatMap(({
|
|
211
|
-
source,
|
|
212
|
-
}) => {
|
|
213
|
-
return source;
|
|
214
|
-
}),
|
|
215
|
-
];
|
|
216
|
-
|
|
217
|
-
if (initialEndSource && !jsdoc.source.at(-1)?.tokens?.end) {
|
|
218
|
-
jsdoc.source.push(initialEndSource);
|
|
219
|
-
}
|
|
73
|
+
rewireByParsedType(jsdoc, tag, parsedType, indent, typeBracketSpacing);
|
|
220
74
|
};
|
|
221
75
|
|
|
222
76
|
/** @type {string[]} */
|
package/src/rules.d.ts
CHANGED
|
@@ -2938,6 +2938,47 @@ export interface Rules {
|
|
|
2938
2938
|
}
|
|
2939
2939
|
];
|
|
2940
2940
|
|
|
2941
|
+
/** Prefers either function properties or method signatures */
|
|
2942
|
+
"jsdoc/ts-method-signature-style":
|
|
2943
|
+
| []
|
|
2944
|
+
| ["method" | "property"]
|
|
2945
|
+
| [
|
|
2946
|
+
"method" | "property",
|
|
2947
|
+
{
|
|
2948
|
+
/**
|
|
2949
|
+
* Whether to enable the fixer. Defaults to `true`.
|
|
2950
|
+
*/
|
|
2951
|
+
enableFixer?: boolean;
|
|
2952
|
+
}
|
|
2953
|
+
];
|
|
2954
|
+
|
|
2955
|
+
/** Warns against use of the empty object type */
|
|
2956
|
+
"jsdoc/ts-no-empty-object-type": [];
|
|
2957
|
+
|
|
2958
|
+
/** Catches unnecessary template expressions such as string expressions within a template literal. */
|
|
2959
|
+
"jsdoc/ts-no-unnecessary-template-expression":
|
|
2960
|
+
| []
|
|
2961
|
+
| [
|
|
2962
|
+
{
|
|
2963
|
+
/**
|
|
2964
|
+
* Whether to enable the fixer. Defaults to `true`.
|
|
2965
|
+
*/
|
|
2966
|
+
enableFixer?: boolean;
|
|
2967
|
+
}
|
|
2968
|
+
];
|
|
2969
|
+
|
|
2970
|
+
/** Prefers function types over call signatures when there are no other properties. */
|
|
2971
|
+
"jsdoc/ts-prefer-function-type":
|
|
2972
|
+
| []
|
|
2973
|
+
| [
|
|
2974
|
+
{
|
|
2975
|
+
/**
|
|
2976
|
+
* Whether to enable the fixer or not
|
|
2977
|
+
*/
|
|
2978
|
+
enableFixer?: boolean;
|
|
2979
|
+
}
|
|
2980
|
+
];
|
|
2981
|
+
|
|
2941
2982
|
/** Formats JSDoc type values. */
|
|
2942
2983
|
"jsdoc/type-formatting":
|
|
2943
2984
|
| []
|