@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 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$4 = "import-dedupe";
8
+ const RULE_NAME$3 = "import-dedupe";
8
9
  const importDedupe = createEslintRule({
9
- name: RULE_NAME$4,
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
- return {
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;
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
- names.add(id);
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$3 = "no-inline-type-import";
56
+ const RULE_NAME$2 = "no-inline-type-import";
58
57
  const noInlineTypeImport = createEslintRule({
59
- name: RULE_NAME$3,
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 === "ImportSpecifier" && s.importKind === "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 === "ImportSpecifier" && s.importKind === "value"
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
- yield fixer.replaceText(
92
- node,
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$2 = "no-useless-template-string";
122
+ const RULE_NAME$1 = "no-useless-template-string";
117
123
  const noUselessTemplateString = createEslintRule({
118
- name: RULE_NAME$2,
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
- return {
134
- TemplateLiteral(node) {
135
- const hasNewline = node.quasis.some((n) => n.value.raw.includes("\n"));
136
- if (node.expressions.length === 0 && !hasNewline) {
137
- context.report({
138
- node,
139
- messageId: "noUselessTemplateString",
140
- fix(fixer) {
141
- const s = node.range[0];
142
- const e = node.range[1];
143
- return fixer.replaceTextRange(
144
- [s, e],
145
- `"${node.quasis[0].value.raw}"`
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$1 = "pad-after-last-import";
156
- const padAfterLastImport = createEslintRule({
157
- name: RULE_NAME$1,
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
- padAfterLastImport: "Expected a blank line after the last import."
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
- let lastImportNode = null;
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
- ImportDeclaration(node) {
176
- lastImportNode = node;
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
- "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) {
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: lastImportNode,
185
- messageId: "padAfterLastImport",
186
- fix: (fixer) => fixer.insertTextAfter(lastImportNode, "\n")
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
- loc: {
220
- start: {
221
- line: 0,
222
- column: 0
223
- },
224
- end: node.loc.start
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
- "no-beginning-newline": noBeginningNewline,
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
- "no-beginning-newline": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"noBeginningNewline", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
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$4 = "import-dedupe";
6
+ const RULE_NAME$3 = "import-dedupe";
6
7
  const importDedupe = createEslintRule({
7
- name: RULE_NAME$4,
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
- return {
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;
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
- names.add(id);
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$3 = "no-inline-type-import";
54
+ const RULE_NAME$2 = "no-inline-type-import";
56
55
  const noInlineTypeImport = createEslintRule({
57
- name: RULE_NAME$3,
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 === "ImportSpecifier" && s.importKind === "type"
76
+ (s) => s.type === AST_NODE_TYPES.ImportSpecifier && s.importKind === "type"
78
77
  );
79
78
  const valueSpecifiers = specifiers.filter(
80
- (s) => s.type === "ImportSpecifier" && s.importKind === "value"
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
- yield fixer.replaceText(
90
- node,
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$2 = "no-useless-template-string";
120
+ const RULE_NAME$1 = "no-useless-template-string";
115
121
  const noUselessTemplateString = createEslintRule({
116
- name: RULE_NAME$2,
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
- return {
132
- TemplateLiteral(node) {
133
- const hasNewline = node.quasis.some((n) => n.value.raw.includes("\n"));
134
- if (node.expressions.length === 0 && !hasNewline) {
135
- context.report({
136
- node,
137
- messageId: "noUselessTemplateString",
138
- fix(fixer) {
139
- const s = node.range[0];
140
- const e = node.range[1];
141
- return fixer.replaceTextRange(
142
- [s, e],
143
- `"${node.quasis[0].value.raw}"`
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$1 = "pad-after-last-import";
154
- const padAfterLastImport = createEslintRule({
155
- name: RULE_NAME$1,
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
- padAfterLastImport: "Expected a blank line after the last import."
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
- let lastImportNode = null;
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
- ImportDeclaration(node) {
174
- lastImportNode = node;
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
- "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) {
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: lastImportNode,
183
- messageId: "padAfterLastImport",
184
- fix: (fixer) => fixer.insertTextAfter(lastImportNode, "\n")
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
- loc: {
218
- start: {
219
- line: 0,
220
- column: 0
221
- },
222
- end: node.loc.start
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
- "no-beginning-newline": noBeginningNewline,
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.75.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.58.0",
34
+ "@typescript-eslint/utils": "^5.59.2",
35
35
  "@vue/reactivity": "^3.2.47"
36
36
  },
37
37
  "devDependencies": {
38
- "@types/node": "^18.15.11",
39
- "@typescript-eslint/types": "^5.58.0"
38
+ "@types/node": "^18.16.5",
39
+ "@typescript-eslint/types": "^5.59.2"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "unbuild",