@so1ve/eslint-plugin 0.76.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,13 +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 = "import-dedupe";
9
- const importDedupe = createEslintRule({
8
+ const RULE_NAME$4 = "function-style";
9
+ const START_RETURN = /^return /;
10
+ const END_SEMICOLON = /;$/;
11
+ const functionStyle = createEslintRule({
10
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
+
127
+ const RULE_NAME$3 = "import-dedupe";
128
+ const importDedupe = createEslintRule({
129
+ name: RULE_NAME$3,
11
130
  meta: {
12
131
  type: "problem",
13
132
  docs: {
@@ -53,9 +172,9 @@ const importDedupe = createEslintRule({
53
172
  })
54
173
  });
55
174
 
56
- const RULE_NAME$3 = "no-inline-type-import";
175
+ const RULE_NAME$2 = "no-inline-type-import";
57
176
  const noInlineTypeImport = createEslintRule({
58
- name: RULE_NAME$3,
177
+ name: RULE_NAME$2,
59
178
  meta: {
60
179
  type: "layout",
61
180
  docs: {
@@ -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$2 = "no-useless-template-string";
123
- const noUselessTemplateString = createEslintRule({
124
- name: RULE_NAME$2,
241
+ const RULE_NAME$1 = "no-negated-equal";
242
+ const noNegatedEqual = createEslintRule({
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,168 +276,48 @@ const noUselessTemplateString = createEslintRule({
156
276
  })
157
277
  });
158
278
 
159
- const RULE_NAME$1 = "no-beginning-newline";
160
- const noBeginningNewline = createEslintRule({
161
- name: RULE_NAME$1,
162
- meta: {
163
- type: "layout",
164
- docs: {
165
- description: "No beginning newline",
166
- recommended: "error"
167
- },
168
- fixable: "whitespace",
169
- schema: [],
170
- messages: {
171
- noBeginningNewline: "No beginning newline"
172
- }
173
- },
174
- defaultOptions: [],
175
- create: (context) => {
176
- const text = context.getSourceCode().text;
177
- return {
178
- Program: (node) => {
179
- const newlines = text.match(/([\n]*)/)[1];
180
- if (newlines.length > 0) {
181
- context.report({
182
- node,
183
- loc: {
184
- start: {
185
- line: 0,
186
- column: 0
187
- },
188
- end: node.loc.start
189
- },
190
- messageId: "noBeginningNewline",
191
- *fix(fixer) {
192
- yield fixer.removeRange([0, node.range[0]]);
193
- }
194
- });
195
- }
196
- }
197
- };
198
- }
199
- });
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({
279
+ const RULE_NAME = "no-useless-template-string";
280
+ const noUselessTemplateString = createEslintRule({
217
281
  name: RULE_NAME,
218
282
  meta: {
219
283
  type: "problem",
220
284
  docs: {
221
- description: "Pad after the last import.",
285
+ description: "No useless template string.",
222
286
  recommended: "error"
223
287
  },
224
288
  fixable: "code",
225
289
  schema: [],
226
290
  messages: {
227
- arrow: "Expected an arrow function.",
228
- arrowShorthand: "Expected an arrow function shorthand.",
229
- declaration: "Expected a function declaration."
291
+ noUselessTemplateString: "No useless template string."
230
292
  }
231
293
  },
232
294
  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;
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) {
263
299
  context.report({
264
300
  node,
265
- messageId: "arrow",
266
- fix: (fixer) => {
267
- const [start, end] = node.range;
301
+ messageId: "noUselessTemplateString",
302
+ fix(fixer) {
268
303
  return fixer.replaceTextRange(
269
- [start, end],
270
- generateFunction(node, "arrow")
304
+ node.range,
305
+ `"${node.quasis[0].value.raw}"`
271
306
  );
272
307
  }
273
308
  });
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
309
  }
310
- };
311
- }
310
+ }
311
+ })
312
312
  });
313
313
 
314
314
  const index = {
315
315
  rules: {
316
+ "function-style": functionStyle,
316
317
  "import-dedupe": importDedupe,
317
318
  "no-inline-type-import": noInlineTypeImport,
318
319
  "no-useless-template-string": noUselessTemplateString,
319
- "no-beginning-newline": noBeginningNewline,
320
- "function-style": functionStyle
320
+ "no-negated-equal": noNegatedEqual
321
321
  }
322
322
  };
323
323
 
package/dist/index.d.ts CHANGED
@@ -1,14 +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
- "no-beginning-newline": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"noBeginningNewline", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
11
- "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>;
12
12
  };
13
13
  };
14
14
 
package/dist/index.mjs CHANGED
@@ -1,11 +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 = "import-dedupe";
7
- const importDedupe = createEslintRule({
6
+ const RULE_NAME$4 = "function-style";
7
+ const START_RETURN = /^return /;
8
+ const END_SEMICOLON = /;$/;
9
+ const functionStyle = createEslintRule({
8
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
+
125
+ const RULE_NAME$3 = "import-dedupe";
126
+ const importDedupe = createEslintRule({
127
+ name: RULE_NAME$3,
9
128
  meta: {
10
129
  type: "problem",
11
130
  docs: {
@@ -51,9 +170,9 @@ const importDedupe = createEslintRule({
51
170
  })
52
171
  });
53
172
 
54
- const RULE_NAME$3 = "no-inline-type-import";
173
+ const RULE_NAME$2 = "no-inline-type-import";
55
174
  const noInlineTypeImport = createEslintRule({
56
- name: RULE_NAME$3,
175
+ name: RULE_NAME$2,
57
176
  meta: {
58
177
  type: "layout",
59
178
  docs: {
@@ -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$2 = "no-useless-template-string";
121
- const noUselessTemplateString = createEslintRule({
122
- name: RULE_NAME$2,
239
+ const RULE_NAME$1 = "no-negated-equal";
240
+ const noNegatedEqual = createEslintRule({
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,168 +274,48 @@ const noUselessTemplateString = createEslintRule({
154
274
  })
155
275
  });
156
276
 
157
- const RULE_NAME$1 = "no-beginning-newline";
158
- const noBeginningNewline = createEslintRule({
159
- name: RULE_NAME$1,
160
- meta: {
161
- type: "layout",
162
- docs: {
163
- description: "No beginning newline",
164
- recommended: "error"
165
- },
166
- fixable: "whitespace",
167
- schema: [],
168
- messages: {
169
- noBeginningNewline: "No beginning newline"
170
- }
171
- },
172
- defaultOptions: [],
173
- create: (context) => {
174
- const text = context.getSourceCode().text;
175
- return {
176
- Program: (node) => {
177
- const newlines = text.match(/([\n]*)/)[1];
178
- if (newlines.length > 0) {
179
- context.report({
180
- node,
181
- loc: {
182
- start: {
183
- line: 0,
184
- column: 0
185
- },
186
- end: node.loc.start
187
- },
188
- messageId: "noBeginningNewline",
189
- *fix(fixer) {
190
- yield fixer.removeRange([0, node.range[0]]);
191
- }
192
- });
193
- }
194
- }
195
- };
196
- }
197
- });
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({
277
+ const RULE_NAME = "no-useless-template-string";
278
+ const noUselessTemplateString = createEslintRule({
215
279
  name: RULE_NAME,
216
280
  meta: {
217
281
  type: "problem",
218
282
  docs: {
219
- description: "Pad after the last import.",
283
+ description: "No useless template string.",
220
284
  recommended: "error"
221
285
  },
222
286
  fixable: "code",
223
287
  schema: [],
224
288
  messages: {
225
- arrow: "Expected an arrow function.",
226
- arrowShorthand: "Expected an arrow function shorthand.",
227
- declaration: "Expected a function declaration."
289
+ noUselessTemplateString: "No useless template string."
228
290
  }
229
291
  },
230
292
  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;
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) {
261
297
  context.report({
262
298
  node,
263
- messageId: "arrow",
264
- fix: (fixer) => {
265
- const [start, end] = node.range;
299
+ messageId: "noUselessTemplateString",
300
+ fix(fixer) {
266
301
  return fixer.replaceTextRange(
267
- [start, end],
268
- generateFunction(node, "arrow")
302
+ node.range,
303
+ `"${node.quasis[0].value.raw}"`
269
304
  );
270
305
  }
271
306
  });
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
307
  }
308
- };
309
- }
308
+ }
309
+ })
310
310
  });
311
311
 
312
312
  const index = {
313
313
  rules: {
314
+ "function-style": functionStyle,
314
315
  "import-dedupe": importDedupe,
315
316
  "no-inline-type-import": noInlineTypeImport,
316
317
  "no-useless-template-string": noUselessTemplateString,
317
- "no-beginning-newline": noBeginningNewline,
318
- "function-style": functionStyle
318
+ "no-negated-equal": noNegatedEqual
319
319
  }
320
320
  };
321
321
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@so1ve/eslint-plugin",
3
- "version": "0.76.0",
3
+ "version": "0.78.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",