@so1ve/eslint-plugin 0.75.0 → 0.77.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/dist/index.cjs +150 -116
- package/dist/index.d.ts +3 -2
- package/dist/index.mjs +150 -116
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const utils = require('@typescript-eslint/utils');
|
|
4
|
+
const types = require('@typescript-eslint/types');
|
|
4
5
|
|
|
5
6
|
const createEslintRule = utils.ESLintUtils.RuleCreator((ruleName) => ruleName);
|
|
6
7
|
|
|
7
|
-
const RULE_NAME$
|
|
8
|
+
const RULE_NAME$3 = "import-dedupe";
|
|
8
9
|
const importDedupe = createEslintRule({
|
|
9
|
-
name: RULE_NAME$
|
|
10
|
+
name: RULE_NAME$3,
|
|
10
11
|
meta: {
|
|
11
12
|
type: "problem",
|
|
12
13
|
docs: {
|
|
@@ -20,43 +21,41 @@ const importDedupe = createEslintRule({
|
|
|
20
21
|
}
|
|
21
22
|
},
|
|
22
23
|
defaultOptions: [],
|
|
23
|
-
create: (context) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
e += 1;
|
|
45
|
-
}
|
|
46
|
-
return fixer.removeRange([s, e]);
|
|
24
|
+
create: (context) => ({
|
|
25
|
+
ImportDeclaration(node) {
|
|
26
|
+
if (node.specifiers.length <= 1) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const names = /* @__PURE__ */ new Set();
|
|
30
|
+
for (const n of node.specifiers) {
|
|
31
|
+
const id = n.local.name;
|
|
32
|
+
if (names.has(id)) {
|
|
33
|
+
context.report({
|
|
34
|
+
node,
|
|
35
|
+
loc: {
|
|
36
|
+
start: n.loc.end,
|
|
37
|
+
end: n.loc.start
|
|
38
|
+
},
|
|
39
|
+
messageId: "importDedupe",
|
|
40
|
+
fix(fixer) {
|
|
41
|
+
const s = n.range[0];
|
|
42
|
+
let e = n.range[1];
|
|
43
|
+
if (context.getSourceCode().text[e] === ",") {
|
|
44
|
+
e += 1;
|
|
47
45
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
return fixer.removeRange([s, e]);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
51
49
|
}
|
|
50
|
+
names.add(id);
|
|
52
51
|
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
52
|
+
}
|
|
53
|
+
})
|
|
55
54
|
});
|
|
56
55
|
|
|
57
|
-
const RULE_NAME$
|
|
56
|
+
const RULE_NAME$2 = "no-inline-type-import";
|
|
58
57
|
const noInlineTypeImport = createEslintRule({
|
|
59
|
-
name: RULE_NAME$
|
|
58
|
+
name: RULE_NAME$2,
|
|
60
59
|
meta: {
|
|
61
60
|
type: "layout",
|
|
62
61
|
docs: {
|
|
@@ -76,10 +75,13 @@ const noInlineTypeImport = createEslintRule({
|
|
|
76
75
|
ImportDeclaration: (node) => {
|
|
77
76
|
const specifiers = node.specifiers;
|
|
78
77
|
const typeSpecifiers = specifiers.filter(
|
|
79
|
-
(s) => s.type ===
|
|
78
|
+
(s) => s.type === types.AST_NODE_TYPES.ImportSpecifier && s.importKind === "type"
|
|
80
79
|
);
|
|
81
80
|
const valueSpecifiers = specifiers.filter(
|
|
82
|
-
(s) => s.type ===
|
|
81
|
+
(s) => s.type === types.AST_NODE_TYPES.ImportSpecifier && s.importKind === "value"
|
|
82
|
+
);
|
|
83
|
+
const defaultImportSpecifier = specifiers.find(
|
|
84
|
+
(s) => s.type === types.AST_NODE_TYPES.ImportDefaultSpecifier
|
|
83
85
|
);
|
|
84
86
|
if (typeSpecifiers.length > 0 && valueSpecifiers.length > 0) {
|
|
85
87
|
context.report({
|
|
@@ -88,11 +90,15 @@ const noInlineTypeImport = createEslintRule({
|
|
|
88
90
|
*fix(fixer) {
|
|
89
91
|
const typeSpecifiersText = typeSpecifiers.map((s) => sourceCode.getText(s).replace("type ", "")).join(", ");
|
|
90
92
|
const valueSpecifiersText = valueSpecifiers.map((s) => sourceCode.getText(s)).join(", ");
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
`import type { ${typeSpecifiersText} } from "${node.source.value}";
|
|
94
|
-
import { ${valueSpecifiersText} } from "${node.source.value}";`
|
|
93
|
+
const defaultImportSpecifierText = sourceCode.getText(
|
|
94
|
+
defaultImportSpecifier
|
|
95
95
|
);
|
|
96
|
+
const valueSpecifiersTextWithDefaultImport = defaultImportSpecifier ? `import ${defaultImportSpecifierText}, { ${valueSpecifiersText} } from "${node.source.value}";` : `import { ${valueSpecifiersText} } from "${node.source.value}";`;
|
|
97
|
+
const texts = [
|
|
98
|
+
`import type { ${typeSpecifiersText} } from "${node.source.value}";`,
|
|
99
|
+
valueSpecifiersTextWithDefaultImport
|
|
100
|
+
];
|
|
101
|
+
yield fixer.replaceText(node, texts.join("\n"));
|
|
96
102
|
}
|
|
97
103
|
});
|
|
98
104
|
} else if (typeSpecifiers.length > 0) {
|
|
@@ -113,9 +119,9 @@ import { ${valueSpecifiersText} } from "${node.source.value}";`
|
|
|
113
119
|
}
|
|
114
120
|
});
|
|
115
121
|
|
|
116
|
-
const RULE_NAME$
|
|
122
|
+
const RULE_NAME$1 = "no-useless-template-string";
|
|
117
123
|
const noUselessTemplateString = createEslintRule({
|
|
118
|
-
name: RULE_NAME$
|
|
124
|
+
name: RULE_NAME$1,
|
|
119
125
|
meta: {
|
|
120
126
|
type: "problem",
|
|
121
127
|
docs: {
|
|
@@ -129,32 +135,44 @@ const noUselessTemplateString = createEslintRule({
|
|
|
129
135
|
}
|
|
130
136
|
},
|
|
131
137
|
defaultOptions: [],
|
|
132
|
-
create: (context) => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
});
|
|
149
|
-
}
|
|
138
|
+
create: (context) => ({
|
|
139
|
+
TemplateLiteral(node) {
|
|
140
|
+
const hasNewline = node.quasis.some((n) => n.value.raw.includes("\n"));
|
|
141
|
+
if (node.expressions.length === 0 && !hasNewline) {
|
|
142
|
+
context.report({
|
|
143
|
+
node,
|
|
144
|
+
messageId: "noUselessTemplateString",
|
|
145
|
+
fix(fixer) {
|
|
146
|
+
const s = node.range[0];
|
|
147
|
+
const e = node.range[1];
|
|
148
|
+
return fixer.replaceTextRange(
|
|
149
|
+
[s, e],
|
|
150
|
+
`"${node.quasis[0].value.raw}"`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
150
154
|
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
155
|
+
}
|
|
156
|
+
})
|
|
153
157
|
});
|
|
154
158
|
|
|
155
|
-
const RULE_NAME
|
|
156
|
-
const
|
|
157
|
-
|
|
159
|
+
const RULE_NAME = "function-style";
|
|
160
|
+
const START_RETURN = /^return /;
|
|
161
|
+
const END_SEMICOLON = /;$/;
|
|
162
|
+
function getBeforeNode(node) {
|
|
163
|
+
const { parent } = node;
|
|
164
|
+
if (!parent)
|
|
165
|
+
return;
|
|
166
|
+
const { body } = parent;
|
|
167
|
+
if (!body)
|
|
168
|
+
return;
|
|
169
|
+
const index = body.indexOf(node);
|
|
170
|
+
if (index === 0)
|
|
171
|
+
return;
|
|
172
|
+
return body[index - 1];
|
|
173
|
+
}
|
|
174
|
+
const functionStyle = createEslintRule({
|
|
175
|
+
name: RULE_NAME,
|
|
158
176
|
meta: {
|
|
159
177
|
type: "problem",
|
|
160
178
|
docs: {
|
|
@@ -164,71 +182,88 @@ const padAfterLastImport = createEslintRule({
|
|
|
164
182
|
fixable: "code",
|
|
165
183
|
schema: [],
|
|
166
184
|
messages: {
|
|
167
|
-
|
|
185
|
+
arrow: "Expected an arrow function.",
|
|
186
|
+
arrowShorthand: "Expected an arrow function shorthand.",
|
|
187
|
+
declaration: "Expected a function declaration."
|
|
168
188
|
}
|
|
169
189
|
},
|
|
170
190
|
defaultOptions: [],
|
|
171
191
|
create: (context) => {
|
|
172
192
|
const sourceCode = context.getSourceCode();
|
|
173
|
-
|
|
193
|
+
const text = sourceCode.getText();
|
|
194
|
+
const getStatementRaw = (statement) => `(${text.slice(statement.range[0], statement.range[1]).replace(START_RETURN, "").replace(END_SEMICOLON, "")})`;
|
|
195
|
+
function getLonelyReturnStatement(node) {
|
|
196
|
+
const { body } = node;
|
|
197
|
+
if (body.type === types.AST_NODE_TYPES.BlockStatement) {
|
|
198
|
+
const { body: blockBody } = body;
|
|
199
|
+
if (blockBody.length === 1) {
|
|
200
|
+
const [statement] = blockBody;
|
|
201
|
+
if (statement?.type === types.AST_NODE_TYPES.ReturnStatement) {
|
|
202
|
+
return statement;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function generateFunction(node, type) {
|
|
208
|
+
const async = node.async ? "async " : "";
|
|
209
|
+
const params = node.params.map((param) => sourceCode.getText(param)).join(", ");
|
|
210
|
+
const generics = node.typeParameters ? sourceCode.getText(node.typeParameters) : "";
|
|
211
|
+
const body = sourceCode.getText(node.body);
|
|
212
|
+
return type === "arrow" ? `const ${node.id.name} = ${async}${generics}(${params}) => ${body};` : `${async}function ${node.parent.id.name}${generics}(${params}) ${body}`;
|
|
213
|
+
}
|
|
174
214
|
return {
|
|
175
|
-
|
|
176
|
-
|
|
215
|
+
FunctionDeclaration(node) {
|
|
216
|
+
if (!node.id?.name)
|
|
217
|
+
return;
|
|
218
|
+
const statement = getLonelyReturnStatement(node);
|
|
219
|
+
if (!statement || node.generator || getBeforeNode(node)?.type === types.AST_NODE_TYPES.TSDeclareFunction)
|
|
220
|
+
return;
|
|
221
|
+
context.report({
|
|
222
|
+
node,
|
|
223
|
+
messageId: "arrow",
|
|
224
|
+
fix: (fixer) => {
|
|
225
|
+
const [start, end] = node.range;
|
|
226
|
+
return fixer.replaceTextRange(
|
|
227
|
+
[start, end],
|
|
228
|
+
generateFunction(node, "arrow")
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
177
232
|
},
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
233
|
+
ArrowFunctionExpression(node) {
|
|
234
|
+
const { body, parent } = node;
|
|
235
|
+
if (parent?.id?.typeAnnotation)
|
|
236
|
+
return;
|
|
237
|
+
if (body.type === types.AST_NODE_TYPES.BlockStatement) {
|
|
238
|
+
const { body: blockBody } = body;
|
|
239
|
+
if (blockBody.length > 1 && node.parent?.parent?.type === types.AST_NODE_TYPES.VariableDeclaration) {
|
|
240
|
+
const parent2 = node.parent.parent;
|
|
183
241
|
context.report({
|
|
184
|
-
node:
|
|
185
|
-
messageId: "
|
|
186
|
-
fix: (fixer) =>
|
|
242
|
+
node: parent2,
|
|
243
|
+
messageId: "declaration",
|
|
244
|
+
fix: (fixer) => {
|
|
245
|
+
const [start, end] = parent2.range;
|
|
246
|
+
return fixer.replaceTextRange(
|
|
247
|
+
[start, end],
|
|
248
|
+
generateFunction(node, "declaration")
|
|
249
|
+
);
|
|
250
|
+
}
|
|
187
251
|
});
|
|
188
252
|
}
|
|
189
253
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
const RULE_NAME = "no-beginning-newline";
|
|
196
|
-
const noBeginningNewline = createEslintRule({
|
|
197
|
-
name: RULE_NAME,
|
|
198
|
-
meta: {
|
|
199
|
-
type: "layout",
|
|
200
|
-
docs: {
|
|
201
|
-
description: "No beginning newline",
|
|
202
|
-
recommended: "error"
|
|
203
|
-
},
|
|
204
|
-
fixable: "whitespace",
|
|
205
|
-
schema: [],
|
|
206
|
-
messages: {
|
|
207
|
-
noBeginningNewline: "No beginning newline"
|
|
208
|
-
}
|
|
209
|
-
},
|
|
210
|
-
defaultOptions: [],
|
|
211
|
-
create: (context) => {
|
|
212
|
-
const text = context.getSourceCode().text;
|
|
213
|
-
return {
|
|
214
|
-
Program: (node) => {
|
|
215
|
-
const newlines = text.match(/([\n]*)/)[1];
|
|
216
|
-
if (newlines.length > 0) {
|
|
254
|
+
const statement = getLonelyReturnStatement(node);
|
|
255
|
+
if (statement)
|
|
217
256
|
context.report({
|
|
218
257
|
node,
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
messageId: "noBeginningNewline",
|
|
227
|
-
*fix(fixer) {
|
|
228
|
-
yield fixer.removeRange([0, node.range[0]]);
|
|
258
|
+
messageId: "arrowShorthand",
|
|
259
|
+
fix: (fixer) => {
|
|
260
|
+
const [start, end] = node.body.range;
|
|
261
|
+
return fixer.replaceTextRange(
|
|
262
|
+
[start, end],
|
|
263
|
+
getStatementRaw(statement)
|
|
264
|
+
);
|
|
229
265
|
}
|
|
230
266
|
});
|
|
231
|
-
}
|
|
232
267
|
}
|
|
233
268
|
};
|
|
234
269
|
}
|
|
@@ -239,8 +274,7 @@ const index = {
|
|
|
239
274
|
"import-dedupe": importDedupe,
|
|
240
275
|
"no-inline-type-import": noInlineTypeImport,
|
|
241
276
|
"no-useless-template-string": noUselessTemplateString,
|
|
242
|
-
"
|
|
243
|
-
"pad-after-last-import": padAfterLastImport
|
|
277
|
+
"function-style": functionStyle
|
|
244
278
|
}
|
|
245
279
|
};
|
|
246
280
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import * as _typescript_eslint_utils_dist_ts_eslint_Rule from '@typescript-eslint/utils/dist/ts-eslint/Rule';
|
|
2
2
|
|
|
3
|
+
type MessageIds = "arrow" | "arrowShorthand" | "declaration";
|
|
4
|
+
|
|
3
5
|
declare const _default: {
|
|
4
6
|
rules: {
|
|
5
7
|
"import-dedupe": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"importDedupe", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
|
|
6
8
|
"no-inline-type-import": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"noInlineTypeImport", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
|
|
7
9
|
"no-useless-template-string": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"noUselessTemplateString", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
|
|
8
|
-
"
|
|
9
|
-
"pad-after-last-import": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"padAfterLastImport", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
|
|
10
|
+
"function-style": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<MessageIds, [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
|
|
10
11
|
};
|
|
11
12
|
};
|
|
12
13
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/types';
|
|
2
3
|
|
|
3
4
|
const createEslintRule = ESLintUtils.RuleCreator((ruleName) => ruleName);
|
|
4
5
|
|
|
5
|
-
const RULE_NAME$
|
|
6
|
+
const RULE_NAME$3 = "import-dedupe";
|
|
6
7
|
const importDedupe = createEslintRule({
|
|
7
|
-
name: RULE_NAME$
|
|
8
|
+
name: RULE_NAME$3,
|
|
8
9
|
meta: {
|
|
9
10
|
type: "problem",
|
|
10
11
|
docs: {
|
|
@@ -18,43 +19,41 @@ const importDedupe = createEslintRule({
|
|
|
18
19
|
}
|
|
19
20
|
},
|
|
20
21
|
defaultOptions: [],
|
|
21
|
-
create: (context) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
e += 1;
|
|
43
|
-
}
|
|
44
|
-
return fixer.removeRange([s, e]);
|
|
22
|
+
create: (context) => ({
|
|
23
|
+
ImportDeclaration(node) {
|
|
24
|
+
if (node.specifiers.length <= 1) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const names = /* @__PURE__ */ new Set();
|
|
28
|
+
for (const n of node.specifiers) {
|
|
29
|
+
const id = n.local.name;
|
|
30
|
+
if (names.has(id)) {
|
|
31
|
+
context.report({
|
|
32
|
+
node,
|
|
33
|
+
loc: {
|
|
34
|
+
start: n.loc.end,
|
|
35
|
+
end: n.loc.start
|
|
36
|
+
},
|
|
37
|
+
messageId: "importDedupe",
|
|
38
|
+
fix(fixer) {
|
|
39
|
+
const s = n.range[0];
|
|
40
|
+
let e = n.range[1];
|
|
41
|
+
if (context.getSourceCode().text[e] === ",") {
|
|
42
|
+
e += 1;
|
|
45
43
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
return fixer.removeRange([s, e]);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
49
47
|
}
|
|
48
|
+
names.add(id);
|
|
50
49
|
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
50
|
+
}
|
|
51
|
+
})
|
|
53
52
|
});
|
|
54
53
|
|
|
55
|
-
const RULE_NAME$
|
|
54
|
+
const RULE_NAME$2 = "no-inline-type-import";
|
|
56
55
|
const noInlineTypeImport = createEslintRule({
|
|
57
|
-
name: RULE_NAME$
|
|
56
|
+
name: RULE_NAME$2,
|
|
58
57
|
meta: {
|
|
59
58
|
type: "layout",
|
|
60
59
|
docs: {
|
|
@@ -74,10 +73,13 @@ const noInlineTypeImport = createEslintRule({
|
|
|
74
73
|
ImportDeclaration: (node) => {
|
|
75
74
|
const specifiers = node.specifiers;
|
|
76
75
|
const typeSpecifiers = specifiers.filter(
|
|
77
|
-
(s) => s.type ===
|
|
76
|
+
(s) => s.type === AST_NODE_TYPES.ImportSpecifier && s.importKind === "type"
|
|
78
77
|
);
|
|
79
78
|
const valueSpecifiers = specifiers.filter(
|
|
80
|
-
(s) => s.type ===
|
|
79
|
+
(s) => s.type === AST_NODE_TYPES.ImportSpecifier && s.importKind === "value"
|
|
80
|
+
);
|
|
81
|
+
const defaultImportSpecifier = specifiers.find(
|
|
82
|
+
(s) => s.type === AST_NODE_TYPES.ImportDefaultSpecifier
|
|
81
83
|
);
|
|
82
84
|
if (typeSpecifiers.length > 0 && valueSpecifiers.length > 0) {
|
|
83
85
|
context.report({
|
|
@@ -86,11 +88,15 @@ const noInlineTypeImport = createEslintRule({
|
|
|
86
88
|
*fix(fixer) {
|
|
87
89
|
const typeSpecifiersText = typeSpecifiers.map((s) => sourceCode.getText(s).replace("type ", "")).join(", ");
|
|
88
90
|
const valueSpecifiersText = valueSpecifiers.map((s) => sourceCode.getText(s)).join(", ");
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
`import type { ${typeSpecifiersText} } from "${node.source.value}";
|
|
92
|
-
import { ${valueSpecifiersText} } from "${node.source.value}";`
|
|
91
|
+
const defaultImportSpecifierText = sourceCode.getText(
|
|
92
|
+
defaultImportSpecifier
|
|
93
93
|
);
|
|
94
|
+
const valueSpecifiersTextWithDefaultImport = defaultImportSpecifier ? `import ${defaultImportSpecifierText}, { ${valueSpecifiersText} } from "${node.source.value}";` : `import { ${valueSpecifiersText} } from "${node.source.value}";`;
|
|
95
|
+
const texts = [
|
|
96
|
+
`import type { ${typeSpecifiersText} } from "${node.source.value}";`,
|
|
97
|
+
valueSpecifiersTextWithDefaultImport
|
|
98
|
+
];
|
|
99
|
+
yield fixer.replaceText(node, texts.join("\n"));
|
|
94
100
|
}
|
|
95
101
|
});
|
|
96
102
|
} else if (typeSpecifiers.length > 0) {
|
|
@@ -111,9 +117,9 @@ import { ${valueSpecifiersText} } from "${node.source.value}";`
|
|
|
111
117
|
}
|
|
112
118
|
});
|
|
113
119
|
|
|
114
|
-
const RULE_NAME$
|
|
120
|
+
const RULE_NAME$1 = "no-useless-template-string";
|
|
115
121
|
const noUselessTemplateString = createEslintRule({
|
|
116
|
-
name: RULE_NAME$
|
|
122
|
+
name: RULE_NAME$1,
|
|
117
123
|
meta: {
|
|
118
124
|
type: "problem",
|
|
119
125
|
docs: {
|
|
@@ -127,32 +133,44 @@ const noUselessTemplateString = createEslintRule({
|
|
|
127
133
|
}
|
|
128
134
|
},
|
|
129
135
|
defaultOptions: [],
|
|
130
|
-
create: (context) => {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
});
|
|
147
|
-
}
|
|
136
|
+
create: (context) => ({
|
|
137
|
+
TemplateLiteral(node) {
|
|
138
|
+
const hasNewline = node.quasis.some((n) => n.value.raw.includes("\n"));
|
|
139
|
+
if (node.expressions.length === 0 && !hasNewline) {
|
|
140
|
+
context.report({
|
|
141
|
+
node,
|
|
142
|
+
messageId: "noUselessTemplateString",
|
|
143
|
+
fix(fixer) {
|
|
144
|
+
const s = node.range[0];
|
|
145
|
+
const e = node.range[1];
|
|
146
|
+
return fixer.replaceTextRange(
|
|
147
|
+
[s, e],
|
|
148
|
+
`"${node.quasis[0].value.raw}"`
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
148
152
|
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
153
|
+
}
|
|
154
|
+
})
|
|
151
155
|
});
|
|
152
156
|
|
|
153
|
-
const RULE_NAME
|
|
154
|
-
const
|
|
155
|
-
|
|
157
|
+
const RULE_NAME = "function-style";
|
|
158
|
+
const START_RETURN = /^return /;
|
|
159
|
+
const END_SEMICOLON = /;$/;
|
|
160
|
+
function getBeforeNode(node) {
|
|
161
|
+
const { parent } = node;
|
|
162
|
+
if (!parent)
|
|
163
|
+
return;
|
|
164
|
+
const { body } = parent;
|
|
165
|
+
if (!body)
|
|
166
|
+
return;
|
|
167
|
+
const index = body.indexOf(node);
|
|
168
|
+
if (index === 0)
|
|
169
|
+
return;
|
|
170
|
+
return body[index - 1];
|
|
171
|
+
}
|
|
172
|
+
const functionStyle = createEslintRule({
|
|
173
|
+
name: RULE_NAME,
|
|
156
174
|
meta: {
|
|
157
175
|
type: "problem",
|
|
158
176
|
docs: {
|
|
@@ -162,71 +180,88 @@ const padAfterLastImport = createEslintRule({
|
|
|
162
180
|
fixable: "code",
|
|
163
181
|
schema: [],
|
|
164
182
|
messages: {
|
|
165
|
-
|
|
183
|
+
arrow: "Expected an arrow function.",
|
|
184
|
+
arrowShorthand: "Expected an arrow function shorthand.",
|
|
185
|
+
declaration: "Expected a function declaration."
|
|
166
186
|
}
|
|
167
187
|
},
|
|
168
188
|
defaultOptions: [],
|
|
169
189
|
create: (context) => {
|
|
170
190
|
const sourceCode = context.getSourceCode();
|
|
171
|
-
|
|
191
|
+
const text = sourceCode.getText();
|
|
192
|
+
const getStatementRaw = (statement) => `(${text.slice(statement.range[0], statement.range[1]).replace(START_RETURN, "").replace(END_SEMICOLON, "")})`;
|
|
193
|
+
function getLonelyReturnStatement(node) {
|
|
194
|
+
const { body } = node;
|
|
195
|
+
if (body.type === AST_NODE_TYPES.BlockStatement) {
|
|
196
|
+
const { body: blockBody } = body;
|
|
197
|
+
if (blockBody.length === 1) {
|
|
198
|
+
const [statement] = blockBody;
|
|
199
|
+
if (statement?.type === AST_NODE_TYPES.ReturnStatement) {
|
|
200
|
+
return statement;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function generateFunction(node, type) {
|
|
206
|
+
const async = node.async ? "async " : "";
|
|
207
|
+
const params = node.params.map((param) => sourceCode.getText(param)).join(", ");
|
|
208
|
+
const generics = node.typeParameters ? sourceCode.getText(node.typeParameters) : "";
|
|
209
|
+
const body = sourceCode.getText(node.body);
|
|
210
|
+
return type === "arrow" ? `const ${node.id.name} = ${async}${generics}(${params}) => ${body};` : `${async}function ${node.parent.id.name}${generics}(${params}) ${body}`;
|
|
211
|
+
}
|
|
172
212
|
return {
|
|
173
|
-
|
|
174
|
-
|
|
213
|
+
FunctionDeclaration(node) {
|
|
214
|
+
if (!node.id?.name)
|
|
215
|
+
return;
|
|
216
|
+
const statement = getLonelyReturnStatement(node);
|
|
217
|
+
if (!statement || node.generator || getBeforeNode(node)?.type === AST_NODE_TYPES.TSDeclareFunction)
|
|
218
|
+
return;
|
|
219
|
+
context.report({
|
|
220
|
+
node,
|
|
221
|
+
messageId: "arrow",
|
|
222
|
+
fix: (fixer) => {
|
|
223
|
+
const [start, end] = node.range;
|
|
224
|
+
return fixer.replaceTextRange(
|
|
225
|
+
[start, end],
|
|
226
|
+
generateFunction(node, "arrow")
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
175
230
|
},
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
231
|
+
ArrowFunctionExpression(node) {
|
|
232
|
+
const { body, parent } = node;
|
|
233
|
+
if (parent?.id?.typeAnnotation)
|
|
234
|
+
return;
|
|
235
|
+
if (body.type === AST_NODE_TYPES.BlockStatement) {
|
|
236
|
+
const { body: blockBody } = body;
|
|
237
|
+
if (blockBody.length > 1 && node.parent?.parent?.type === AST_NODE_TYPES.VariableDeclaration) {
|
|
238
|
+
const parent2 = node.parent.parent;
|
|
181
239
|
context.report({
|
|
182
|
-
node:
|
|
183
|
-
messageId: "
|
|
184
|
-
fix: (fixer) =>
|
|
240
|
+
node: parent2,
|
|
241
|
+
messageId: "declaration",
|
|
242
|
+
fix: (fixer) => {
|
|
243
|
+
const [start, end] = parent2.range;
|
|
244
|
+
return fixer.replaceTextRange(
|
|
245
|
+
[start, end],
|
|
246
|
+
generateFunction(node, "declaration")
|
|
247
|
+
);
|
|
248
|
+
}
|
|
185
249
|
});
|
|
186
250
|
}
|
|
187
251
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
const RULE_NAME = "no-beginning-newline";
|
|
194
|
-
const noBeginningNewline = createEslintRule({
|
|
195
|
-
name: RULE_NAME,
|
|
196
|
-
meta: {
|
|
197
|
-
type: "layout",
|
|
198
|
-
docs: {
|
|
199
|
-
description: "No beginning newline",
|
|
200
|
-
recommended: "error"
|
|
201
|
-
},
|
|
202
|
-
fixable: "whitespace",
|
|
203
|
-
schema: [],
|
|
204
|
-
messages: {
|
|
205
|
-
noBeginningNewline: "No beginning newline"
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
defaultOptions: [],
|
|
209
|
-
create: (context) => {
|
|
210
|
-
const text = context.getSourceCode().text;
|
|
211
|
-
return {
|
|
212
|
-
Program: (node) => {
|
|
213
|
-
const newlines = text.match(/([\n]*)/)[1];
|
|
214
|
-
if (newlines.length > 0) {
|
|
252
|
+
const statement = getLonelyReturnStatement(node);
|
|
253
|
+
if (statement)
|
|
215
254
|
context.report({
|
|
216
255
|
node,
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
messageId: "noBeginningNewline",
|
|
225
|
-
*fix(fixer) {
|
|
226
|
-
yield fixer.removeRange([0, node.range[0]]);
|
|
256
|
+
messageId: "arrowShorthand",
|
|
257
|
+
fix: (fixer) => {
|
|
258
|
+
const [start, end] = node.body.range;
|
|
259
|
+
return fixer.replaceTextRange(
|
|
260
|
+
[start, end],
|
|
261
|
+
getStatementRaw(statement)
|
|
262
|
+
);
|
|
227
263
|
}
|
|
228
264
|
});
|
|
229
|
-
}
|
|
230
265
|
}
|
|
231
266
|
};
|
|
232
267
|
}
|
|
@@ -237,8 +272,7 @@ const index = {
|
|
|
237
272
|
"import-dedupe": importDedupe,
|
|
238
273
|
"no-inline-type-import": noInlineTypeImport,
|
|
239
274
|
"no-useless-template-string": noUselessTemplateString,
|
|
240
|
-
"
|
|
241
|
-
"pad-after-last-import": padAfterLastImport
|
|
275
|
+
"function-style": functionStyle
|
|
242
276
|
}
|
|
243
277
|
};
|
|
244
278
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@so1ve/eslint-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.77.0",
|
|
4
4
|
"author": "Anthony Fu <anthonyfu117@hotmail.com> (https://github.com/antfu/)",
|
|
5
5
|
"contributors": [
|
|
6
6
|
{
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"access": "public"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@typescript-eslint/utils": "^5.
|
|
34
|
+
"@typescript-eslint/utils": "^5.59.2",
|
|
35
35
|
"@vue/reactivity": "^3.2.47"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@types/node": "^18.
|
|
39
|
-
"@typescript-eslint/types": "^5.
|
|
38
|
+
"@types/node": "^18.16.5",
|
|
39
|
+
"@typescript-eslint/types": "^5.59.2"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "unbuild",
|