@so1ve/eslint-plugin 0.77.0 → 0.78.1

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,10 +1,132 @@
1
1
  'use strict';
2
2
 
3
- const utils = require('@typescript-eslint/utils');
4
3
  const types = require('@typescript-eslint/types');
4
+ const utils = require('@typescript-eslint/utils');
5
5
 
6
6
  const createEslintRule = utils.ESLintUtils.RuleCreator((ruleName) => ruleName);
7
7
 
8
+ const RULE_NAME$4 = "function-style";
9
+ const START_RETURN = /^return /;
10
+ const END_SEMICOLON = /;$/;
11
+ const functionStyle = createEslintRule({
12
+ name: RULE_NAME$4,
13
+ meta: {
14
+ type: "problem",
15
+ docs: {
16
+ description: "Enforce function style.",
17
+ recommended: "error"
18
+ },
19
+ fixable: "code",
20
+ schema: [],
21
+ messages: {
22
+ arrow: "Expected an arrow function shorthand.",
23
+ declaration: "Expected a function declaration."
24
+ }
25
+ },
26
+ defaultOptions: [],
27
+ create: (context) => {
28
+ const sourceCode = context.getSourceCode();
29
+ const text = sourceCode.getText();
30
+ const getStatementRaw = (statement) => `(${text.slice(statement.range[0], statement.range[1]).replace(START_RETURN, "").replace(END_SEMICOLON, "")})`;
31
+ function getLoneReturnStatement(node) {
32
+ const { body } = node;
33
+ if (body.type === types.AST_NODE_TYPES.BlockStatement) {
34
+ const { body: blockBody } = body;
35
+ if (blockBody.length === 1) {
36
+ const [statement] = blockBody;
37
+ if (statement?.type === types.AST_NODE_TYPES.ReturnStatement) {
38
+ return statement;
39
+ }
40
+ }
41
+ }
42
+ }
43
+ function generateFunction(type, name, node, rawStatement, asVariable = true) {
44
+ const async = node.async ? "async " : "";
45
+ const generics = node.typeParameters ? sourceCode.getText(node.typeParameters) : "";
46
+ const params = node.params.map((param) => sourceCode.getText(param)).join(", ");
47
+ const returnType = node.returnType ? sourceCode.getText(node.returnType) : "";
48
+ const body = sourceCode.getText(node.body);
49
+ const variableDeclaration = asVariable ? `const ${name} = ` : "";
50
+ return type === "arrow" ? `${variableDeclaration}${async}${generics}(${params})${returnType} => ${rawStatement};` : `${async}function ${name}${generics}(${params})${returnType} ${body}`;
51
+ }
52
+ return {
53
+ FunctionExpression(node) {
54
+ if (node.parent?.id?.typeAnnotation || node.parent?.type !== types.AST_NODE_TYPES.VariableDeclarator) {
55
+ return;
56
+ }
57
+ const name = node.parent.id.name;
58
+ context.report({
59
+ node,
60
+ messageId: "declaration",
61
+ fix: (fixer) => fixer.replaceTextRange(
62
+ node.parent.parent.range,
63
+ generateFunction("declaration", name, node)
64
+ )
65
+ });
66
+ },
67
+ "FunctionDeclaration:not(TSDeclareFunction + FunctionDeclaration)"(node) {
68
+ const statement = getLoneReturnStatement(node);
69
+ if (!statement || !node.id?.name || node.generator) {
70
+ return;
71
+ }
72
+ const asVariable = node.parent?.type !== types.AST_NODE_TYPES.ExportDefaultDeclaration;
73
+ context.report({
74
+ node,
75
+ messageId: "arrow",
76
+ fix: (fixer) => fixer.replaceTextRange(
77
+ node.range,
78
+ generateFunction(
79
+ "arrow",
80
+ node.id.name,
81
+ node,
82
+ getStatementRaw(statement),
83
+ asVariable
84
+ )
85
+ )
86
+ });
87
+ },
88
+ ArrowFunctionExpression(node) {
89
+ const { body, parent } = node;
90
+ const statement = getLoneReturnStatement(node);
91
+ if (statement) {
92
+ context.report({
93
+ node,
94
+ messageId: "arrow",
95
+ fix: (fixer) => fixer.replaceTextRange(
96
+ node.body.range,
97
+ getStatementRaw(statement)
98
+ )
99
+ });
100
+ }
101
+ if (parent?.id?.typeAnnotation) {
102
+ return;
103
+ }
104
+ if (body.type === types.AST_NODE_TYPES.BlockStatement) {
105
+ const { body: blockBody } = body;
106
+ if (blockBody.length > 1 && node.parent?.parent?.type === types.AST_NODE_TYPES.VariableDeclaration) {
107
+ const { parent: parent2 } = node.parent;
108
+ context.report({
109
+ node: parent2,
110
+ messageId: "declaration",
111
+ fix: (fixer) => {
112
+ const [start, end] = parent2.range;
113
+ return fixer.replaceTextRange(
114
+ [start, end],
115
+ generateFunction(
116
+ "declaration",
117
+ node.parent.id.name,
118
+ node
119
+ )
120
+ );
121
+ }
122
+ });
123
+ }
124
+ }
125
+ }
126
+ };
127
+ }
128
+ });
129
+
8
130
  const RULE_NAME$3 = "import-dedupe";
9
131
  const importDedupe = createEslintRule({
10
132
  name: RULE_NAME$3,
@@ -73,7 +195,7 @@ const noInlineTypeImport = createEslintRule({
73
195
  const sourceCode = context.getSourceCode();
74
196
  return {
75
197
  ImportDeclaration: (node) => {
76
- const specifiers = node.specifiers;
198
+ const { specifiers } = node;
77
199
  const typeSpecifiers = specifiers.filter(
78
200
  (s) => s.type === types.AST_NODE_TYPES.ImportSpecifier && s.importKind === "type"
79
201
  );
@@ -93,10 +215,10 @@ const noInlineTypeImport = createEslintRule({
93
215
  const defaultImportSpecifierText = sourceCode.getText(
94
216
  defaultImportSpecifier
95
217
  );
96
- const valueSpecifiersTextWithDefaultImport = defaultImportSpecifier ? `import ${defaultImportSpecifierText}, { ${valueSpecifiersText} } from "${node.source.value}";` : `import { ${valueSpecifiersText} } from "${node.source.value}";`;
218
+ const defaultAndvalueSpecifiersText = defaultImportSpecifier ? `import ${defaultImportSpecifierText}, { ${valueSpecifiersText} } from "${node.source.value}";` : `import { ${valueSpecifiersText} } from "${node.source.value}";`;
97
219
  const texts = [
98
220
  `import type { ${typeSpecifiersText} } from "${node.source.value}";`,
99
- valueSpecifiersTextWithDefaultImport
221
+ defaultAndvalueSpecifiersText
100
222
  ];
101
223
  yield fixer.replaceText(node, texts.join("\n"));
102
224
  }
@@ -119,36 +241,38 @@ const noInlineTypeImport = createEslintRule({
119
241
  }
120
242
  });
121
243
 
122
- const RULE_NAME$1 = "no-useless-template-string";
123
- const noUselessTemplateString = createEslintRule({
244
+ const RULE_NAME$1 = "no-negated-equal";
245
+ const noNegatedEqual = createEslintRule({
124
246
  name: RULE_NAME$1,
125
247
  meta: {
126
248
  type: "problem",
127
249
  docs: {
128
- description: "No useless template string.",
250
+ description: "Disallow negated equal sign.",
129
251
  recommended: "error"
130
252
  },
131
253
  fixable: "code",
132
254
  schema: [],
133
255
  messages: {
134
- noUselessTemplateString: "No useless template string."
256
+ noNegatedEqual: "Expect no negated equal sign."
135
257
  }
136
258
  },
137
259
  defaultOptions: [],
138
260
  create: (context) => ({
139
- TemplateLiteral(node) {
140
- const hasNewline = node.quasis.some((n) => n.value.raw.includes("\n"));
141
- if (node.expressions.length === 0 && !hasNewline) {
261
+ BinaryExpression(node) {
262
+ const { parent, left, right, operator } = node;
263
+ if (!parent) {
264
+ return;
265
+ }
266
+ if (["==", "==="].includes(node.operator) && parent.type === types.AST_NODE_TYPES.UnaryExpression && // Is this necessary?
267
+ parent.operator === "!") {
142
268
  context.report({
143
269
  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
- );
270
+ messageId: "noNegatedEqual",
271
+ *fix(fixer) {
272
+ const operatorRange = [left.range[1], right.range[0]];
273
+ const fixedOperator = operator === "==" ? "!=" : "!==";
274
+ yield fixer.replaceTextRange(operatorRange, fixedOperator);
275
+ yield fixer.removeRange([parent.range[0], parent.range[0] + 1]);
152
276
  }
153
277
  });
154
278
  }
@@ -156,125 +280,48 @@ const noUselessTemplateString = createEslintRule({
156
280
  })
157
281
  });
158
282
 
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({
283
+ const RULE_NAME = "no-useless-template-string";
284
+ const noUselessTemplateString = createEslintRule({
175
285
  name: RULE_NAME,
176
286
  meta: {
177
287
  type: "problem",
178
288
  docs: {
179
- description: "Pad after the last import.",
289
+ description: "No useless template string.",
180
290
  recommended: "error"
181
291
  },
182
292
  fixable: "code",
183
293
  schema: [],
184
294
  messages: {
185
- arrow: "Expected an arrow function.",
186
- arrowShorthand: "Expected an arrow function shorthand.",
187
- declaration: "Expected a function declaration."
295
+ noUselessTemplateString: "No useless template string."
188
296
  }
189
297
  },
190
298
  defaultOptions: [],
191
- create: (context) => {
192
- const sourceCode = context.getSourceCode();
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
- }
214
- return {
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;
299
+ create: (context) => ({
300
+ "TemplateLiteral:not(TaggedTemplateExpression > TemplateLiteral)"(node) {
301
+ const hasNewline = node.quasis.some((n) => n.value.raw.includes("\n"));
302
+ if (node.expressions.length === 0 && !hasNewline) {
221
303
  context.report({
222
304
  node,
223
- messageId: "arrow",
224
- fix: (fixer) => {
225
- const [start, end] = node.range;
305
+ messageId: "noUselessTemplateString",
306
+ fix(fixer) {
226
307
  return fixer.replaceTextRange(
227
- [start, end],
228
- generateFunction(node, "arrow")
308
+ node.range,
309
+ `"${node.quasis[0].value.raw}"`
229
310
  );
230
311
  }
231
312
  });
232
- },
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;
241
- context.report({
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
- }
251
- });
252
- }
253
- }
254
- const statement = getLonelyReturnStatement(node);
255
- if (statement)
256
- context.report({
257
- node,
258
- messageId: "arrowShorthand",
259
- fix: (fixer) => {
260
- const [start, end] = node.body.range;
261
- return fixer.replaceTextRange(
262
- [start, end],
263
- getStatementRaw(statement)
264
- );
265
- }
266
- });
267
313
  }
268
- };
269
- }
314
+ }
315
+ })
270
316
  });
271
317
 
272
318
  const index = {
273
319
  rules: {
320
+ "function-style": functionStyle,
274
321
  "import-dedupe": importDedupe,
275
322
  "no-inline-type-import": noInlineTypeImport,
276
323
  "no-useless-template-string": noUselessTemplateString,
277
- "function-style": functionStyle
324
+ "no-negated-equal": noNegatedEqual
278
325
  }
279
326
  };
280
327
 
package/dist/index.d.ts CHANGED
@@ -1,13 +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";
3
+ type MessageIds = "arrow" | "declaration";
4
4
 
5
5
  declare const _default: {
6
6
  rules: {
7
+ "function-style": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<MessageIds, [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
7
8
  "import-dedupe": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"importDedupe", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
8
9
  "no-inline-type-import": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"noInlineTypeImport", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
9
10
  "no-useless-template-string": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"noUselessTemplateString", [], _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>;
11
+ "no-negated-equal": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"noNegatedEqual", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
11
12
  };
12
13
  };
13
14
 
package/dist/index.mjs CHANGED
@@ -1,8 +1,130 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
1
  import { AST_NODE_TYPES } from '@typescript-eslint/types';
2
+ import { ESLintUtils } from '@typescript-eslint/utils';
3
3
 
4
4
  const createEslintRule = ESLintUtils.RuleCreator((ruleName) => ruleName);
5
5
 
6
+ const RULE_NAME$4 = "function-style";
7
+ const START_RETURN = /^return /;
8
+ const END_SEMICOLON = /;$/;
9
+ const functionStyle = createEslintRule({
10
+ name: RULE_NAME$4,
11
+ meta: {
12
+ type: "problem",
13
+ docs: {
14
+ description: "Enforce function style.",
15
+ recommended: "error"
16
+ },
17
+ fixable: "code",
18
+ schema: [],
19
+ messages: {
20
+ arrow: "Expected an arrow function shorthand.",
21
+ declaration: "Expected a function declaration."
22
+ }
23
+ },
24
+ defaultOptions: [],
25
+ create: (context) => {
26
+ const sourceCode = context.getSourceCode();
27
+ const text = sourceCode.getText();
28
+ const getStatementRaw = (statement) => `(${text.slice(statement.range[0], statement.range[1]).replace(START_RETURN, "").replace(END_SEMICOLON, "")})`;
29
+ function getLoneReturnStatement(node) {
30
+ const { body } = node;
31
+ if (body.type === AST_NODE_TYPES.BlockStatement) {
32
+ const { body: blockBody } = body;
33
+ if (blockBody.length === 1) {
34
+ const [statement] = blockBody;
35
+ if (statement?.type === AST_NODE_TYPES.ReturnStatement) {
36
+ return statement;
37
+ }
38
+ }
39
+ }
40
+ }
41
+ function generateFunction(type, name, node, rawStatement, asVariable = true) {
42
+ const async = node.async ? "async " : "";
43
+ const generics = node.typeParameters ? sourceCode.getText(node.typeParameters) : "";
44
+ const params = node.params.map((param) => sourceCode.getText(param)).join(", ");
45
+ const returnType = node.returnType ? sourceCode.getText(node.returnType) : "";
46
+ const body = sourceCode.getText(node.body);
47
+ const variableDeclaration = asVariable ? `const ${name} = ` : "";
48
+ return type === "arrow" ? `${variableDeclaration}${async}${generics}(${params})${returnType} => ${rawStatement};` : `${async}function ${name}${generics}(${params})${returnType} ${body}`;
49
+ }
50
+ return {
51
+ FunctionExpression(node) {
52
+ if (node.parent?.id?.typeAnnotation || node.parent?.type !== AST_NODE_TYPES.VariableDeclarator) {
53
+ return;
54
+ }
55
+ const name = node.parent.id.name;
56
+ context.report({
57
+ node,
58
+ messageId: "declaration",
59
+ fix: (fixer) => fixer.replaceTextRange(
60
+ node.parent.parent.range,
61
+ generateFunction("declaration", name, node)
62
+ )
63
+ });
64
+ },
65
+ "FunctionDeclaration:not(TSDeclareFunction + FunctionDeclaration)"(node) {
66
+ const statement = getLoneReturnStatement(node);
67
+ if (!statement || !node.id?.name || node.generator) {
68
+ return;
69
+ }
70
+ const asVariable = node.parent?.type !== AST_NODE_TYPES.ExportDefaultDeclaration;
71
+ context.report({
72
+ node,
73
+ messageId: "arrow",
74
+ fix: (fixer) => fixer.replaceTextRange(
75
+ node.range,
76
+ generateFunction(
77
+ "arrow",
78
+ node.id.name,
79
+ node,
80
+ getStatementRaw(statement),
81
+ asVariable
82
+ )
83
+ )
84
+ });
85
+ },
86
+ ArrowFunctionExpression(node) {
87
+ const { body, parent } = node;
88
+ const statement = getLoneReturnStatement(node);
89
+ if (statement) {
90
+ context.report({
91
+ node,
92
+ messageId: "arrow",
93
+ fix: (fixer) => fixer.replaceTextRange(
94
+ node.body.range,
95
+ getStatementRaw(statement)
96
+ )
97
+ });
98
+ }
99
+ if (parent?.id?.typeAnnotation) {
100
+ return;
101
+ }
102
+ if (body.type === AST_NODE_TYPES.BlockStatement) {
103
+ const { body: blockBody } = body;
104
+ if (blockBody.length > 1 && node.parent?.parent?.type === AST_NODE_TYPES.VariableDeclaration) {
105
+ const { parent: parent2 } = node.parent;
106
+ context.report({
107
+ node: parent2,
108
+ messageId: "declaration",
109
+ fix: (fixer) => {
110
+ const [start, end] = parent2.range;
111
+ return fixer.replaceTextRange(
112
+ [start, end],
113
+ generateFunction(
114
+ "declaration",
115
+ node.parent.id.name,
116
+ node
117
+ )
118
+ );
119
+ }
120
+ });
121
+ }
122
+ }
123
+ }
124
+ };
125
+ }
126
+ });
127
+
6
128
  const RULE_NAME$3 = "import-dedupe";
7
129
  const importDedupe = createEslintRule({
8
130
  name: RULE_NAME$3,
@@ -71,7 +193,7 @@ const noInlineTypeImport = createEslintRule({
71
193
  const sourceCode = context.getSourceCode();
72
194
  return {
73
195
  ImportDeclaration: (node) => {
74
- const specifiers = node.specifiers;
196
+ const { specifiers } = node;
75
197
  const typeSpecifiers = specifiers.filter(
76
198
  (s) => s.type === AST_NODE_TYPES.ImportSpecifier && s.importKind === "type"
77
199
  );
@@ -91,10 +213,10 @@ const noInlineTypeImport = createEslintRule({
91
213
  const defaultImportSpecifierText = sourceCode.getText(
92
214
  defaultImportSpecifier
93
215
  );
94
- const valueSpecifiersTextWithDefaultImport = defaultImportSpecifier ? `import ${defaultImportSpecifierText}, { ${valueSpecifiersText} } from "${node.source.value}";` : `import { ${valueSpecifiersText} } from "${node.source.value}";`;
216
+ const defaultAndvalueSpecifiersText = defaultImportSpecifier ? `import ${defaultImportSpecifierText}, { ${valueSpecifiersText} } from "${node.source.value}";` : `import { ${valueSpecifiersText} } from "${node.source.value}";`;
95
217
  const texts = [
96
218
  `import type { ${typeSpecifiersText} } from "${node.source.value}";`,
97
- valueSpecifiersTextWithDefaultImport
219
+ defaultAndvalueSpecifiersText
98
220
  ];
99
221
  yield fixer.replaceText(node, texts.join("\n"));
100
222
  }
@@ -117,36 +239,38 @@ const noInlineTypeImport = createEslintRule({
117
239
  }
118
240
  });
119
241
 
120
- const RULE_NAME$1 = "no-useless-template-string";
121
- const noUselessTemplateString = createEslintRule({
242
+ const RULE_NAME$1 = "no-negated-equal";
243
+ const noNegatedEqual = createEslintRule({
122
244
  name: RULE_NAME$1,
123
245
  meta: {
124
246
  type: "problem",
125
247
  docs: {
126
- description: "No useless template string.",
248
+ description: "Disallow negated equal sign.",
127
249
  recommended: "error"
128
250
  },
129
251
  fixable: "code",
130
252
  schema: [],
131
253
  messages: {
132
- noUselessTemplateString: "No useless template string."
254
+ noNegatedEqual: "Expect no negated equal sign."
133
255
  }
134
256
  },
135
257
  defaultOptions: [],
136
258
  create: (context) => ({
137
- TemplateLiteral(node) {
138
- const hasNewline = node.quasis.some((n) => n.value.raw.includes("\n"));
139
- if (node.expressions.length === 0 && !hasNewline) {
259
+ BinaryExpression(node) {
260
+ const { parent, left, right, operator } = node;
261
+ if (!parent) {
262
+ return;
263
+ }
264
+ if (["==", "==="].includes(node.operator) && parent.type === AST_NODE_TYPES.UnaryExpression && // Is this necessary?
265
+ parent.operator === "!") {
140
266
  context.report({
141
267
  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
- );
268
+ messageId: "noNegatedEqual",
269
+ *fix(fixer) {
270
+ const operatorRange = [left.range[1], right.range[0]];
271
+ const fixedOperator = operator === "==" ? "!=" : "!==";
272
+ yield fixer.replaceTextRange(operatorRange, fixedOperator);
273
+ yield fixer.removeRange([parent.range[0], parent.range[0] + 1]);
150
274
  }
151
275
  });
152
276
  }
@@ -154,125 +278,48 @@ const noUselessTemplateString = createEslintRule({
154
278
  })
155
279
  });
156
280
 
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({
281
+ const RULE_NAME = "no-useless-template-string";
282
+ const noUselessTemplateString = createEslintRule({
173
283
  name: RULE_NAME,
174
284
  meta: {
175
285
  type: "problem",
176
286
  docs: {
177
- description: "Pad after the last import.",
287
+ description: "No useless template string.",
178
288
  recommended: "error"
179
289
  },
180
290
  fixable: "code",
181
291
  schema: [],
182
292
  messages: {
183
- arrow: "Expected an arrow function.",
184
- arrowShorthand: "Expected an arrow function shorthand.",
185
- declaration: "Expected a function declaration."
293
+ noUselessTemplateString: "No useless template string."
186
294
  }
187
295
  },
188
296
  defaultOptions: [],
189
- create: (context) => {
190
- const sourceCode = context.getSourceCode();
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
- }
212
- return {
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;
297
+ create: (context) => ({
298
+ "TemplateLiteral:not(TaggedTemplateExpression > TemplateLiteral)"(node) {
299
+ const hasNewline = node.quasis.some((n) => n.value.raw.includes("\n"));
300
+ if (node.expressions.length === 0 && !hasNewline) {
219
301
  context.report({
220
302
  node,
221
- messageId: "arrow",
222
- fix: (fixer) => {
223
- const [start, end] = node.range;
303
+ messageId: "noUselessTemplateString",
304
+ fix(fixer) {
224
305
  return fixer.replaceTextRange(
225
- [start, end],
226
- generateFunction(node, "arrow")
306
+ node.range,
307
+ `"${node.quasis[0].value.raw}"`
227
308
  );
228
309
  }
229
310
  });
230
- },
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;
239
- context.report({
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
- }
249
- });
250
- }
251
- }
252
- const statement = getLonelyReturnStatement(node);
253
- if (statement)
254
- context.report({
255
- node,
256
- messageId: "arrowShorthand",
257
- fix: (fixer) => {
258
- const [start, end] = node.body.range;
259
- return fixer.replaceTextRange(
260
- [start, end],
261
- getStatementRaw(statement)
262
- );
263
- }
264
- });
265
311
  }
266
- };
267
- }
312
+ }
313
+ })
268
314
  });
269
315
 
270
316
  const index = {
271
317
  rules: {
318
+ "function-style": functionStyle,
272
319
  "import-dedupe": importDedupe,
273
320
  "no-inline-type-import": noInlineTypeImport,
274
321
  "no-useless-template-string": noUselessTemplateString,
275
- "function-style": functionStyle
322
+ "no-negated-equal": noNegatedEqual
276
323
  }
277
324
  };
278
325
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@so1ve/eslint-plugin",
3
- "version": "0.77.0",
3
+ "version": "0.78.1",
4
4
  "author": "Anthony Fu <anthonyfu117@hotmail.com> (https://github.com/antfu/)",
5
5
  "contributors": [
6
6
  {