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