@so1ve/eslint-plugin 0.75.0 → 0.76.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 +174 -97
- package/dist/index.d.ts +3 -1
- package/dist/index.mjs +174 -97
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
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
|
|
|
@@ -20,38 +21,36 @@ 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
56
|
const RULE_NAME$3 = "no-inline-type-import";
|
|
@@ -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) {
|
|
@@ -129,72 +135,30 @@ 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
|
-
}
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
const RULE_NAME$1 = "pad-after-last-import";
|
|
156
|
-
const padAfterLastImport = createEslintRule({
|
|
157
|
-
name: RULE_NAME$1,
|
|
158
|
-
meta: {
|
|
159
|
-
type: "problem",
|
|
160
|
-
docs: {
|
|
161
|
-
description: "Pad after the last import.",
|
|
162
|
-
recommended: "error"
|
|
163
|
-
},
|
|
164
|
-
fixable: "code",
|
|
165
|
-
schema: [],
|
|
166
|
-
messages: {
|
|
167
|
-
padAfterLastImport: "Expected a blank line after the last import."
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
defaultOptions: [],
|
|
171
|
-
create: (context) => {
|
|
172
|
-
const sourceCode = context.getSourceCode();
|
|
173
|
-
let lastImportNode = null;
|
|
174
|
-
return {
|
|
175
|
-
ImportDeclaration(node) {
|
|
176
|
-
lastImportNode = node;
|
|
177
|
-
},
|
|
178
|
-
"Program:exit"() {
|
|
179
|
-
if (lastImportNode) {
|
|
180
|
-
const nextToken = sourceCode.getTokenAfter(lastImportNode);
|
|
181
|
-
if (nextToken && // Workaround: Vue
|
|
182
|
-
nextToken.value !== "<\/script>" && lastImportNode.loc.end.line + 1 === nextToken.loc.start.line) {
|
|
183
|
-
context.report({
|
|
184
|
-
node: lastImportNode,
|
|
185
|
-
messageId: "padAfterLastImport",
|
|
186
|
-
fix: (fixer) => fixer.insertTextAfter(lastImportNode, "\n")
|
|
187
|
-
});
|
|
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
|
+
);
|
|
188
152
|
}
|
|
189
|
-
}
|
|
153
|
+
});
|
|
190
154
|
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
155
|
+
}
|
|
156
|
+
})
|
|
193
157
|
});
|
|
194
158
|
|
|
195
|
-
const RULE_NAME = "no-beginning-newline";
|
|
159
|
+
const RULE_NAME$1 = "no-beginning-newline";
|
|
196
160
|
const noBeginningNewline = createEslintRule({
|
|
197
|
-
name: RULE_NAME,
|
|
161
|
+
name: RULE_NAME$1,
|
|
198
162
|
meta: {
|
|
199
163
|
type: "layout",
|
|
200
164
|
docs: {
|
|
@@ -234,13 +198,126 @@ const noBeginningNewline = createEslintRule({
|
|
|
234
198
|
}
|
|
235
199
|
});
|
|
236
200
|
|
|
201
|
+
const RULE_NAME = "function-style";
|
|
202
|
+
const START_RETURN = /^return /;
|
|
203
|
+
const END_SEMICOLON = /;$/;
|
|
204
|
+
function getBeforeNode(node) {
|
|
205
|
+
const { parent } = node;
|
|
206
|
+
if (!parent)
|
|
207
|
+
return;
|
|
208
|
+
const { body } = parent;
|
|
209
|
+
if (!body)
|
|
210
|
+
return;
|
|
211
|
+
const index = body.indexOf(node);
|
|
212
|
+
if (index === 0)
|
|
213
|
+
return;
|
|
214
|
+
return body[index - 1];
|
|
215
|
+
}
|
|
216
|
+
const functionStyle = createEslintRule({
|
|
217
|
+
name: RULE_NAME,
|
|
218
|
+
meta: {
|
|
219
|
+
type: "problem",
|
|
220
|
+
docs: {
|
|
221
|
+
description: "Pad after the last import.",
|
|
222
|
+
recommended: "error"
|
|
223
|
+
},
|
|
224
|
+
fixable: "code",
|
|
225
|
+
schema: [],
|
|
226
|
+
messages: {
|
|
227
|
+
arrow: "Expected an arrow function.",
|
|
228
|
+
arrowShorthand: "Expected an arrow function shorthand.",
|
|
229
|
+
declaration: "Expected a function declaration."
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
defaultOptions: [],
|
|
233
|
+
create: (context) => {
|
|
234
|
+
const sourceCode = context.getSourceCode();
|
|
235
|
+
const text = sourceCode.getText();
|
|
236
|
+
const getStatementRaw = (statement) => `(${text.slice(statement.range[0], statement.range[1]).replace(START_RETURN, "").replace(END_SEMICOLON, "")})`;
|
|
237
|
+
function getLonelyReturnStatement(node) {
|
|
238
|
+
const { body } = node;
|
|
239
|
+
if (body.type === types.AST_NODE_TYPES.BlockStatement) {
|
|
240
|
+
const { body: blockBody } = body;
|
|
241
|
+
if (blockBody.length === 1) {
|
|
242
|
+
const [statement] = blockBody;
|
|
243
|
+
if (statement?.type === types.AST_NODE_TYPES.ReturnStatement) {
|
|
244
|
+
return statement;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function generateFunction(node, type) {
|
|
250
|
+
const async = node.async ? "async " : "";
|
|
251
|
+
const params = node.params.map((param) => sourceCode.getText(param)).join(", ");
|
|
252
|
+
const generics = node.typeParameters ? sourceCode.getText(node.typeParameters) : "";
|
|
253
|
+
const body = sourceCode.getText(node.body);
|
|
254
|
+
return type === "arrow" ? `const ${node.id.name} = ${async}${generics}(${params}) => ${body}` : `${async}function ${node.parent.id.name}${generics}(${params}) ${body}`;
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
FunctionDeclaration(node) {
|
|
258
|
+
if (!node.id?.name)
|
|
259
|
+
return;
|
|
260
|
+
const statement = getLonelyReturnStatement(node);
|
|
261
|
+
if (!statement || node.generator || getBeforeNode(node)?.type === types.AST_NODE_TYPES.TSDeclareFunction)
|
|
262
|
+
return;
|
|
263
|
+
context.report({
|
|
264
|
+
node,
|
|
265
|
+
messageId: "arrow",
|
|
266
|
+
fix: (fixer) => {
|
|
267
|
+
const [start, end] = node.range;
|
|
268
|
+
return fixer.replaceTextRange(
|
|
269
|
+
[start, end],
|
|
270
|
+
generateFunction(node, "arrow")
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
},
|
|
275
|
+
ArrowFunctionExpression(node) {
|
|
276
|
+
const { body, parent } = node;
|
|
277
|
+
if (parent?.id?.typeAnnotation)
|
|
278
|
+
return;
|
|
279
|
+
if (body.type === types.AST_NODE_TYPES.BlockStatement) {
|
|
280
|
+
const { body: blockBody } = body;
|
|
281
|
+
if (blockBody.length > 1 && node.parent?.parent?.type === types.AST_NODE_TYPES.VariableDeclaration) {
|
|
282
|
+
const parent2 = node.parent.parent;
|
|
283
|
+
context.report({
|
|
284
|
+
node: parent2,
|
|
285
|
+
messageId: "declaration",
|
|
286
|
+
fix: (fixer) => {
|
|
287
|
+
const [start, end] = parent2.range;
|
|
288
|
+
return fixer.replaceTextRange(
|
|
289
|
+
[start, end],
|
|
290
|
+
generateFunction(node, "declaration")
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
const statement = getLonelyReturnStatement(node);
|
|
297
|
+
if (statement)
|
|
298
|
+
context.report({
|
|
299
|
+
node,
|
|
300
|
+
messageId: "arrowShorthand",
|
|
301
|
+
fix: (fixer) => {
|
|
302
|
+
const [start, end] = node.body.range;
|
|
303
|
+
return fixer.replaceTextRange(
|
|
304
|
+
[start, end],
|
|
305
|
+
getStatementRaw(statement)
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
237
314
|
const index = {
|
|
238
315
|
rules: {
|
|
239
316
|
"import-dedupe": importDedupe,
|
|
240
317
|
"no-inline-type-import": noInlineTypeImport,
|
|
241
318
|
"no-useless-template-string": noUselessTemplateString,
|
|
242
319
|
"no-beginning-newline": noBeginningNewline,
|
|
243
|
-
"
|
|
320
|
+
"function-style": functionStyle
|
|
244
321
|
}
|
|
245
322
|
};
|
|
246
323
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
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
10
|
"no-beginning-newline": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"noBeginningNewline", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
|
|
9
|
-
"
|
|
11
|
+
"function-style": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<MessageIds, [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
|
|
10
12
|
};
|
|
11
13
|
};
|
|
12
14
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
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
|
|
|
@@ -18,38 +19,36 @@ 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
54
|
const RULE_NAME$3 = "no-inline-type-import";
|
|
@@ -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) {
|
|
@@ -127,72 +133,30 @@ 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
|
-
}
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
const RULE_NAME$1 = "pad-after-last-import";
|
|
154
|
-
const padAfterLastImport = createEslintRule({
|
|
155
|
-
name: RULE_NAME$1,
|
|
156
|
-
meta: {
|
|
157
|
-
type: "problem",
|
|
158
|
-
docs: {
|
|
159
|
-
description: "Pad after the last import.",
|
|
160
|
-
recommended: "error"
|
|
161
|
-
},
|
|
162
|
-
fixable: "code",
|
|
163
|
-
schema: [],
|
|
164
|
-
messages: {
|
|
165
|
-
padAfterLastImport: "Expected a blank line after the last import."
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
defaultOptions: [],
|
|
169
|
-
create: (context) => {
|
|
170
|
-
const sourceCode = context.getSourceCode();
|
|
171
|
-
let lastImportNode = null;
|
|
172
|
-
return {
|
|
173
|
-
ImportDeclaration(node) {
|
|
174
|
-
lastImportNode = node;
|
|
175
|
-
},
|
|
176
|
-
"Program:exit"() {
|
|
177
|
-
if (lastImportNode) {
|
|
178
|
-
const nextToken = sourceCode.getTokenAfter(lastImportNode);
|
|
179
|
-
if (nextToken && // Workaround: Vue
|
|
180
|
-
nextToken.value !== "<\/script>" && lastImportNode.loc.end.line + 1 === nextToken.loc.start.line) {
|
|
181
|
-
context.report({
|
|
182
|
-
node: lastImportNode,
|
|
183
|
-
messageId: "padAfterLastImport",
|
|
184
|
-
fix: (fixer) => fixer.insertTextAfter(lastImportNode, "\n")
|
|
185
|
-
});
|
|
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
|
+
);
|
|
186
150
|
}
|
|
187
|
-
}
|
|
151
|
+
});
|
|
188
152
|
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
153
|
+
}
|
|
154
|
+
})
|
|
191
155
|
});
|
|
192
156
|
|
|
193
|
-
const RULE_NAME = "no-beginning-newline";
|
|
157
|
+
const RULE_NAME$1 = "no-beginning-newline";
|
|
194
158
|
const noBeginningNewline = createEslintRule({
|
|
195
|
-
name: RULE_NAME,
|
|
159
|
+
name: RULE_NAME$1,
|
|
196
160
|
meta: {
|
|
197
161
|
type: "layout",
|
|
198
162
|
docs: {
|
|
@@ -232,13 +196,126 @@ const noBeginningNewline = createEslintRule({
|
|
|
232
196
|
}
|
|
233
197
|
});
|
|
234
198
|
|
|
199
|
+
const RULE_NAME = "function-style";
|
|
200
|
+
const START_RETURN = /^return /;
|
|
201
|
+
const END_SEMICOLON = /;$/;
|
|
202
|
+
function getBeforeNode(node) {
|
|
203
|
+
const { parent } = node;
|
|
204
|
+
if (!parent)
|
|
205
|
+
return;
|
|
206
|
+
const { body } = parent;
|
|
207
|
+
if (!body)
|
|
208
|
+
return;
|
|
209
|
+
const index = body.indexOf(node);
|
|
210
|
+
if (index === 0)
|
|
211
|
+
return;
|
|
212
|
+
return body[index - 1];
|
|
213
|
+
}
|
|
214
|
+
const functionStyle = createEslintRule({
|
|
215
|
+
name: RULE_NAME,
|
|
216
|
+
meta: {
|
|
217
|
+
type: "problem",
|
|
218
|
+
docs: {
|
|
219
|
+
description: "Pad after the last import.",
|
|
220
|
+
recommended: "error"
|
|
221
|
+
},
|
|
222
|
+
fixable: "code",
|
|
223
|
+
schema: [],
|
|
224
|
+
messages: {
|
|
225
|
+
arrow: "Expected an arrow function.",
|
|
226
|
+
arrowShorthand: "Expected an arrow function shorthand.",
|
|
227
|
+
declaration: "Expected a function declaration."
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
defaultOptions: [],
|
|
231
|
+
create: (context) => {
|
|
232
|
+
const sourceCode = context.getSourceCode();
|
|
233
|
+
const text = sourceCode.getText();
|
|
234
|
+
const getStatementRaw = (statement) => `(${text.slice(statement.range[0], statement.range[1]).replace(START_RETURN, "").replace(END_SEMICOLON, "")})`;
|
|
235
|
+
function getLonelyReturnStatement(node) {
|
|
236
|
+
const { body } = node;
|
|
237
|
+
if (body.type === AST_NODE_TYPES.BlockStatement) {
|
|
238
|
+
const { body: blockBody } = body;
|
|
239
|
+
if (blockBody.length === 1) {
|
|
240
|
+
const [statement] = blockBody;
|
|
241
|
+
if (statement?.type === AST_NODE_TYPES.ReturnStatement) {
|
|
242
|
+
return statement;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function generateFunction(node, type) {
|
|
248
|
+
const async = node.async ? "async " : "";
|
|
249
|
+
const params = node.params.map((param) => sourceCode.getText(param)).join(", ");
|
|
250
|
+
const generics = node.typeParameters ? sourceCode.getText(node.typeParameters) : "";
|
|
251
|
+
const body = sourceCode.getText(node.body);
|
|
252
|
+
return type === "arrow" ? `const ${node.id.name} = ${async}${generics}(${params}) => ${body}` : `${async}function ${node.parent.id.name}${generics}(${params}) ${body}`;
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
FunctionDeclaration(node) {
|
|
256
|
+
if (!node.id?.name)
|
|
257
|
+
return;
|
|
258
|
+
const statement = getLonelyReturnStatement(node);
|
|
259
|
+
if (!statement || node.generator || getBeforeNode(node)?.type === AST_NODE_TYPES.TSDeclareFunction)
|
|
260
|
+
return;
|
|
261
|
+
context.report({
|
|
262
|
+
node,
|
|
263
|
+
messageId: "arrow",
|
|
264
|
+
fix: (fixer) => {
|
|
265
|
+
const [start, end] = node.range;
|
|
266
|
+
return fixer.replaceTextRange(
|
|
267
|
+
[start, end],
|
|
268
|
+
generateFunction(node, "arrow")
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
},
|
|
273
|
+
ArrowFunctionExpression(node) {
|
|
274
|
+
const { body, parent } = node;
|
|
275
|
+
if (parent?.id?.typeAnnotation)
|
|
276
|
+
return;
|
|
277
|
+
if (body.type === AST_NODE_TYPES.BlockStatement) {
|
|
278
|
+
const { body: blockBody } = body;
|
|
279
|
+
if (blockBody.length > 1 && node.parent?.parent?.type === AST_NODE_TYPES.VariableDeclaration) {
|
|
280
|
+
const parent2 = node.parent.parent;
|
|
281
|
+
context.report({
|
|
282
|
+
node: parent2,
|
|
283
|
+
messageId: "declaration",
|
|
284
|
+
fix: (fixer) => {
|
|
285
|
+
const [start, end] = parent2.range;
|
|
286
|
+
return fixer.replaceTextRange(
|
|
287
|
+
[start, end],
|
|
288
|
+
generateFunction(node, "declaration")
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const statement = getLonelyReturnStatement(node);
|
|
295
|
+
if (statement)
|
|
296
|
+
context.report({
|
|
297
|
+
node,
|
|
298
|
+
messageId: "arrowShorthand",
|
|
299
|
+
fix: (fixer) => {
|
|
300
|
+
const [start, end] = node.body.range;
|
|
301
|
+
return fixer.replaceTextRange(
|
|
302
|
+
[start, end],
|
|
303
|
+
getStatementRaw(statement)
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
235
312
|
const index = {
|
|
236
313
|
rules: {
|
|
237
314
|
"import-dedupe": importDedupe,
|
|
238
315
|
"no-inline-type-import": noInlineTypeImport,
|
|
239
316
|
"no-useless-template-string": noUselessTemplateString,
|
|
240
317
|
"no-beginning-newline": noBeginningNewline,
|
|
241
|
-
"
|
|
318
|
+
"function-style": functionStyle
|
|
242
319
|
}
|
|
243
320
|
};
|
|
244
321
|
|