@so1ve/eslint-plugin 3.1.0 → 3.3.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +16 -14
  2. package/dist/index.js +388 -532
  3. package/package.json +8 -5
package/dist/index.d.ts CHANGED
@@ -1,18 +1,20 @@
1
- import * as _typescript_eslint_utils_ts_eslint from '@typescript-eslint/utils/ts-eslint';
1
+ import * as _typescript_eslint_utils_ts_eslint1 from "@typescript-eslint/utils/ts-eslint";
2
2
 
3
+ //#region src/rules/function-style.d.ts
3
4
  type MessageIds = "arrow" | "declaration";
4
-
5
+ //#endregion
6
+ //#region src/index.d.ts
5
7
  declare const _default: {
6
- rules: {
7
- "function-style": _typescript_eslint_utils_ts_eslint.RuleModule<MessageIds, [], _typescript_eslint_utils_ts_eslint.RuleListener>;
8
- "import-dedupe": _typescript_eslint_utils_ts_eslint.RuleModule<"importDedupe", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
9
- "no-inline-type-import": _typescript_eslint_utils_ts_eslint.RuleModule<"noInlineTypeImport", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
10
- "no-negated-comparison": _typescript_eslint_utils_ts_eslint.RuleModule<"noNegatedComparison", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
11
- "no-useless-template-string": _typescript_eslint_utils_ts_eslint.RuleModule<"noUselessTemplateString", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
12
- "no-import-promises-as": _typescript_eslint_utils_ts_eslint.RuleModule<"noImportPromisesAs", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
13
- "pad-after-last-import": _typescript_eslint_utils_ts_eslint.RuleModule<"padAfterLastImport", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
14
- "require-async-with-await": _typescript_eslint_utils_ts_eslint.RuleModule<"requireAsyncWithAwait", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
15
- };
8
+ rules: {
9
+ "function-style": _typescript_eslint_utils_ts_eslint1.RuleModule<MessageIds, [], unknown, _typescript_eslint_utils_ts_eslint1.RuleListener>;
10
+ "import-dedupe": _typescript_eslint_utils_ts_eslint1.RuleModule<"importDedupe", [], unknown, _typescript_eslint_utils_ts_eslint1.RuleListener>;
11
+ "no-inline-type-import": _typescript_eslint_utils_ts_eslint1.RuleModule<"noInlineTypeImport", [], unknown, _typescript_eslint_utils_ts_eslint1.RuleListener>;
12
+ "no-negated-comparison": _typescript_eslint_utils_ts_eslint1.RuleModule<"noNegatedComparison", [], unknown, _typescript_eslint_utils_ts_eslint1.RuleListener>;
13
+ "no-useless-template-string": _typescript_eslint_utils_ts_eslint1.RuleModule<"noUselessTemplateString", [], unknown, _typescript_eslint_utils_ts_eslint1.RuleListener>;
14
+ "no-import-promises-as": _typescript_eslint_utils_ts_eslint1.RuleModule<"noImportPromisesAs", [], unknown, _typescript_eslint_utils_ts_eslint1.RuleListener>;
15
+ "pad-after-last-import": _typescript_eslint_utils_ts_eslint1.RuleModule<"padAfterLastImport", [], unknown, _typescript_eslint_utils_ts_eslint1.RuleListener>;
16
+ "require-async-with-await": _typescript_eslint_utils_ts_eslint1.RuleModule<"requireAsyncWithAwait", [], unknown, _typescript_eslint_utils_ts_eslint1.RuleListener>;
17
+ };
16
18
  };
17
-
18
- export { _default as default };
19
+ //#endregion
20
+ export { _default as default };
package/dist/index.js CHANGED
@@ -1,562 +1,418 @@
1
- // src/rules/function-style.ts
2
- import { AST_NODE_TYPES } from "@typescript-eslint/types";
3
-
4
- // src/utils/index.ts
1
+ import { AST_NODE_TYPES, TSESTree } from "@typescript-eslint/types";
5
2
  import { ESLintUtils } from "@typescript-eslint/utils";
6
- var createEslintRule = ESLintUtils.RuleCreator((ruleName) => ruleName);
3
+
4
+ //#region src/utils/index.ts
5
+ const createEslintRule = ESLintUtils.RuleCreator((ruleName) => ruleName);
7
6
  function getPreviousNode(node) {
8
- if (!node) {
9
- return;
10
- }
11
- const { parent } = node;
12
- if (parent && "body" in parent) {
13
- const { body } = parent;
14
- if (!Array.isArray(body)) {
15
- return;
16
- }
17
- const index = body.indexOf(node);
18
- if (index > 0) {
19
- return body[index - 1];
20
- }
21
- }
7
+ if (!node) return;
8
+ const { parent } = node;
9
+ if (parent && "body" in parent) {
10
+ const { body } = parent;
11
+ if (!Array.isArray(body)) return;
12
+ const index = body.indexOf(node);
13
+ if (index > 0) return body[index - 1];
14
+ }
22
15
  }
23
16
 
24
- // src/rules/function-style.ts
25
- var RULE_NAME = "function-style";
17
+ //#endregion
18
+ //#region src/rules/function-style.ts
19
+ const RULE_NAME$7 = "function-style";
26
20
  var function_style_default = createEslintRule({
27
- name: RULE_NAME,
28
- meta: {
29
- type: "problem",
30
- docs: {
31
- description: "Enforce function style.",
32
- recommended: "stylistic"
33
- },
34
- fixable: "code",
35
- schema: [],
36
- messages: {
37
- arrow: "Expected an arrow function shorthand.",
38
- declaration: "Expected a function declaration."
39
- }
40
- },
41
- defaultOptions: [],
42
- create: (context) => {
43
- const sourceCode = context.sourceCode;
44
- function getLoneReturnStatement(node) {
45
- const { body } = node;
46
- if (body.type !== AST_NODE_TYPES.BlockStatement) {
47
- return;
48
- }
49
- const { body: blockBody } = body;
50
- const allComments = sourceCode.getCommentsInside(node);
51
- if (blockBody.length !== 1) {
52
- return;
53
- }
54
- const [statement] = blockBody;
55
- const statementComments = sourceCode.getCommentsInside(statement);
56
- if (allComments.length !== statementComments.length) {
57
- return;
58
- }
59
- if (statement?.type === AST_NODE_TYPES.ReturnStatement) {
60
- return statement;
61
- }
62
- }
63
- function generateFunction(type, name, node, rawStatement, asVariable = true) {
64
- const async = node.async ? "async " : "";
65
- const generics = node.typeParameters ? sourceCode.getText(node.typeParameters) : "";
66
- const params = node.params.map((param) => sourceCode.getText(param)).join(", ");
67
- const returnType = node.returnType ? sourceCode.getText(node.returnType) : "";
68
- const body = sourceCode.getText(node.body);
69
- const variableDeclaration = asVariable && name ? `const ${name} = ` : "";
70
- return type === "arrow" ? `${variableDeclaration}${async}${generics}(${params})${returnType} => ${rawStatement};` : `${async}function ${name}${generics}(${params})${returnType} ${body}`;
71
- }
72
- const scopeStack = [];
73
- let haveThisAccess = false;
74
- function setupScope(node) {
75
- scopeStack.push(sourceCode.getScope(node));
76
- }
77
- function clearThisAccess() {
78
- scopeStack.pop();
79
- haveThisAccess = false;
80
- }
81
- return {
82
- "FunctionExpression": setupScope,
83
- "FunctionExpression:exit"(node) {
84
- if (node.parent?.id?.typeAnnotation || node.parent?.type !== AST_NODE_TYPES.VariableDeclarator || haveThisAccess) {
85
- clearThisAccess();
86
- return;
87
- }
88
- const name = node.parent.id.name;
89
- context.report({
90
- node,
91
- messageId: "declaration",
92
- fix: (fixer) => fixer.replaceText(
93
- node.parent.parent,
94
- generateFunction("declaration", name, node)
95
- )
96
- });
97
- clearThisAccess();
98
- },
99
- "FunctionDeclaration:not(TSDeclareFunction + FunctionDeclaration)": setupScope,
100
- "FunctionDeclaration:not(TSDeclareFunction + FunctionDeclaration):exit"(node) {
101
- if (haveThisAccess) {
102
- return;
103
- }
104
- const previousNode = getPreviousNode(node.parent);
105
- if (previousNode?.type === AST_NODE_TYPES.ExportNamedDeclaration && previousNode.declaration?.type === AST_NODE_TYPES.TSDeclareFunction) {
106
- return;
107
- }
108
- const statement = getLoneReturnStatement(node);
109
- const isExportDefault = node.parent?.type === AST_NODE_TYPES.ExportDefaultDeclaration;
110
- if (!statement?.argument || !node.id?.name && !isExportDefault || node.generator) {
111
- clearThisAccess();
112
- return;
113
- }
114
- const returnVal = `(${sourceCode.getText(statement.argument)})`;
115
- context.report({
116
- node,
117
- messageId: "arrow",
118
- fix: (fixer) => fixer.replaceText(
119
- node,
120
- generateFunction(
121
- "arrow",
122
- node.id?.name ?? null,
123
- node,
124
- returnVal,
125
- !isExportDefault
126
- )
127
- )
128
- });
129
- clearThisAccess();
130
- },
131
- "ArrowFunctionExpression": setupScope,
132
- "ArrowFunctionExpression:exit"(node) {
133
- if (haveThisAccess) {
134
- return;
135
- }
136
- const { body, parent } = node;
137
- const statement = getLoneReturnStatement(node);
138
- if (statement?.argument) {
139
- const returnVal = `(${sourceCode.getText(statement.argument)})`;
140
- context.report({
141
- node,
142
- messageId: "arrow",
143
- fix: (fixer) => fixer.replaceText(node.body, returnVal)
144
- });
145
- } else if (body.type === AST_NODE_TYPES.BlockStatement && !parent?.id?.typeAnnotation) {
146
- const { body: blockBody } = body;
147
- if (blockBody.length > 0 && node.parent?.parent?.type === AST_NODE_TYPES.VariableDeclaration) {
148
- const { parent: grandParent } = node.parent;
149
- context.report({
150
- node: grandParent,
151
- messageId: "declaration",
152
- fix: (fixer) => fixer.replaceText(
153
- grandParent,
154
- generateFunction(
155
- "declaration",
156
- node.parent.id.name,
157
- node
158
- )
159
- )
160
- });
161
- }
162
- }
163
- clearThisAccess();
164
- },
165
- ThisExpression(node) {
166
- haveThisAccess = scopeStack.includes(sourceCode.getScope(node));
167
- }
168
- };
169
- }
21
+ name: RULE_NAME$7,
22
+ meta: {
23
+ type: "problem",
24
+ docs: { description: "Enforce function style." },
25
+ fixable: "code",
26
+ schema: [],
27
+ messages: {
28
+ arrow: "Expected an arrow function shorthand.",
29
+ declaration: "Expected a function declaration."
30
+ }
31
+ },
32
+ defaultOptions: [],
33
+ create: (context) => {
34
+ const sourceCode = context.sourceCode;
35
+ function getLoneReturnStatement(node) {
36
+ const { body } = node;
37
+ if (body.type !== AST_NODE_TYPES.BlockStatement) return;
38
+ const { body: blockBody } = body;
39
+ const allComments = sourceCode.getCommentsInside(node);
40
+ if (blockBody.length !== 1) return;
41
+ const [statement] = blockBody;
42
+ const statementComments = sourceCode.getCommentsInside(statement);
43
+ if (allComments.length !== statementComments.length) return;
44
+ if (statement?.type === AST_NODE_TYPES.ReturnStatement) return statement;
45
+ }
46
+ function generateFunction(type, name, node, rawStatement, asVariable = true) {
47
+ const async = node.async ? "async " : "";
48
+ const generics = node.typeParameters ? sourceCode.getText(node.typeParameters) : "";
49
+ const params = node.params.map((param) => sourceCode.getText(param)).join(", ");
50
+ const returnType = node.returnType ? sourceCode.getText(node.returnType) : "";
51
+ const body = sourceCode.getText(node.body);
52
+ const variableDeclaration = asVariable && name ? `const ${name} = ` : "";
53
+ return type === "arrow" ? `${variableDeclaration}${async}${generics}(${params})${returnType} => ${rawStatement};` : `${async}function ${name}${generics}(${params})${returnType} ${body}`;
54
+ }
55
+ const scopeStack = [];
56
+ let haveThisAccess = false;
57
+ function setupScope(node) {
58
+ scopeStack.push(sourceCode.getScope(node));
59
+ }
60
+ function clearThisAccess() {
61
+ scopeStack.pop();
62
+ haveThisAccess = false;
63
+ }
64
+ return {
65
+ "FunctionExpression": setupScope,
66
+ "FunctionExpression:exit"(node) {
67
+ if (node.parent?.id?.typeAnnotation || node.parent?.type !== AST_NODE_TYPES.VariableDeclarator || haveThisAccess) {
68
+ clearThisAccess();
69
+ return;
70
+ }
71
+ const name = node.parent.id.name;
72
+ context.report({
73
+ node,
74
+ messageId: "declaration",
75
+ fix: (fixer) => fixer.replaceText(node.parent.parent, generateFunction("declaration", name, node))
76
+ });
77
+ clearThisAccess();
78
+ },
79
+ "FunctionDeclaration:not(TSDeclareFunction + FunctionDeclaration)": setupScope,
80
+ "FunctionDeclaration:not(TSDeclareFunction + FunctionDeclaration):exit"(node) {
81
+ if (haveThisAccess) return;
82
+ const previousNode = getPreviousNode(node.parent);
83
+ if (previousNode?.type === AST_NODE_TYPES.ExportNamedDeclaration && previousNode.declaration?.type === AST_NODE_TYPES.TSDeclareFunction) return;
84
+ const statement = getLoneReturnStatement(node);
85
+ const isExportDefault = node.parent?.type === AST_NODE_TYPES.ExportDefaultDeclaration;
86
+ if (!statement?.argument || !node.id?.name && !isExportDefault || node.generator) {
87
+ clearThisAccess();
88
+ return;
89
+ }
90
+ const returnVal = `(${sourceCode.getText(statement.argument)})`;
91
+ context.report({
92
+ node,
93
+ messageId: "arrow",
94
+ fix: (fixer) => fixer.replaceText(node, generateFunction("arrow", node.id?.name ?? null, node, returnVal, !isExportDefault))
95
+ });
96
+ clearThisAccess();
97
+ },
98
+ "ArrowFunctionExpression": setupScope,
99
+ "ArrowFunctionExpression:exit"(node) {
100
+ if (haveThisAccess) return;
101
+ const { body, parent } = node;
102
+ const statement = getLoneReturnStatement(node);
103
+ if (statement?.argument) {
104
+ const returnVal = `(${sourceCode.getText(statement.argument)})`;
105
+ context.report({
106
+ node,
107
+ messageId: "arrow",
108
+ fix: (fixer) => fixer.replaceText(node.body, returnVal)
109
+ });
110
+ } else if (body.type === AST_NODE_TYPES.BlockStatement && !parent?.id?.typeAnnotation) {
111
+ const { body: blockBody } = body;
112
+ if (blockBody.length > 0 && node.parent?.parent?.type === AST_NODE_TYPES.VariableDeclaration) {
113
+ const { parent: grandParent } = node.parent;
114
+ context.report({
115
+ node: grandParent,
116
+ messageId: "declaration",
117
+ fix: (fixer) => fixer.replaceText(grandParent, generateFunction("declaration", node.parent.id.name, node))
118
+ });
119
+ }
120
+ }
121
+ clearThisAccess();
122
+ },
123
+ ThisExpression(node) {
124
+ haveThisAccess = scopeStack.includes(sourceCode.getScope(node));
125
+ }
126
+ };
127
+ }
170
128
  });
171
129
 
172
- // src/rules/import-dedupe.ts
173
- var RULE_NAME2 = "import-dedupe";
130
+ //#endregion
131
+ //#region src/rules/import-dedupe.ts
132
+ const RULE_NAME$6 = "import-dedupe";
174
133
  var import_dedupe_default = createEslintRule({
175
- name: RULE_NAME2,
176
- meta: {
177
- type: "problem",
178
- docs: {
179
- description: "Fix duplication in imports.",
180
- recommended: "recommended"
181
- },
182
- fixable: "code",
183
- schema: [],
184
- messages: {
185
- importDedupe: "Expect no duplication in imports."
186
- }
187
- },
188
- defaultOptions: [],
189
- create: (context) => ({
190
- ImportDeclaration(node) {
191
- if (node.specifiers.length <= 1) {
192
- return;
193
- }
194
- const names = /* @__PURE__ */ new Set();
195
- for (const n of node.specifiers) {
196
- const id = n.local.name;
197
- if (names.has(id)) {
198
- context.report({
199
- node,
200
- loc: {
201
- start: n.loc.end,
202
- end: n.loc.start
203
- },
204
- messageId: "importDedupe",
205
- fix(fixer) {
206
- const start = n.range[0];
207
- let end = n.range[1];
208
- const nextToken = context.sourceCode.getTokenAfter(n);
209
- if (nextToken && nextToken.value === ",") {
210
- end = nextToken.range[1];
211
- }
212
- return fixer.removeRange([start, end]);
213
- }
214
- });
215
- }
216
- names.add(id);
217
- }
218
- }
219
- })
134
+ name: RULE_NAME$6,
135
+ meta: {
136
+ type: "problem",
137
+ docs: { description: "Fix duplication in imports." },
138
+ fixable: "code",
139
+ schema: [],
140
+ messages: { importDedupe: "Expect no duplication in imports." }
141
+ },
142
+ defaultOptions: [],
143
+ create: (context) => ({ ImportDeclaration(node) {
144
+ if (node.specifiers.length <= 1) return;
145
+ const names = /* @__PURE__ */ new Set();
146
+ for (const n of node.specifiers) {
147
+ const id = n.local.name;
148
+ if (names.has(id)) context.report({
149
+ node,
150
+ loc: {
151
+ start: n.loc.end,
152
+ end: n.loc.start
153
+ },
154
+ messageId: "importDedupe",
155
+ fix(fixer) {
156
+ const start = n.range[0];
157
+ let end = n.range[1];
158
+ const nextToken = context.sourceCode.getTokenAfter(n);
159
+ if (nextToken && nextToken.value === ",") end = nextToken.range[1];
160
+ return fixer.removeRange([start, end]);
161
+ }
162
+ });
163
+ names.add(id);
164
+ }
165
+ } })
220
166
  });
221
167
 
222
- // src/rules/no-import-promises-as.ts
223
- var RULE_NAME3 = "no-import-promises-as";
224
- var _POSSIBLE_IMPORT_SOURCES = ["dns", "fs", "readline", "stream"];
225
- var POSSIBLE_IMPORT_SOURCES = [
226
- ..._POSSIBLE_IMPORT_SOURCES,
227
- ..._POSSIBLE_IMPORT_SOURCES.map((s) => `node:${s}`)
168
+ //#endregion
169
+ //#region src/rules/no-import-promises-as.ts
170
+ const RULE_NAME$5 = "no-import-promises-as";
171
+ const _POSSIBLE_IMPORT_SOURCES = [
172
+ "dns",
173
+ "fs",
174
+ "readline",
175
+ "stream"
228
176
  ];
177
+ const POSSIBLE_IMPORT_SOURCES = [..._POSSIBLE_IMPORT_SOURCES, ..._POSSIBLE_IMPORT_SOURCES.map((s) => `node:${s}`)];
229
178
  var no_import_promises_as_default = createEslintRule({
230
- name: RULE_NAME3,
231
- meta: {
232
- type: "problem",
233
- docs: {
234
- description: "Disallow import promises as.",
235
- recommended: "stylistic"
236
- },
237
- fixable: "code",
238
- schema: [],
239
- messages: {
240
- noImportPromisesAs: "Expect no import promises as."
241
- }
242
- },
243
- defaultOptions: [],
244
- create: (context) => {
245
- const sourceCode = context.sourceCode;
246
- const { text } = sourceCode;
247
- return {
248
- ImportDeclaration(node) {
249
- if (!POSSIBLE_IMPORT_SOURCES.includes(node.source.value)) {
250
- return;
251
- }
252
- const promisesSpecifier = node.specifiers.find(
253
- (s) => s.type === "ImportSpecifier" && s.imported.name === "promises" && s.local.name !== "promises"
254
- );
255
- const as = promisesSpecifier?.local.name;
256
- if (!promisesSpecifier || !as) {
257
- return;
258
- }
259
- context.report({
260
- node,
261
- messageId: "noImportPromisesAs",
262
- *fix(fixer) {
263
- const s = promisesSpecifier.range[0];
264
- let e = promisesSpecifier.range[1];
265
- if (text[e] === ",") {
266
- e += 1;
267
- }
268
- yield fixer.removeRange([s, e]);
269
- yield fixer.insertTextAfter(
270
- node,
271
- `
272
- import ${as} from "${node.source.value}/promises";`
273
- );
274
- }
275
- });
276
- }
277
- };
278
- }
179
+ name: RULE_NAME$5,
180
+ meta: {
181
+ type: "problem",
182
+ docs: { description: "Disallow import promises as." },
183
+ fixable: "code",
184
+ schema: [],
185
+ messages: { noImportPromisesAs: "Expect no import promises as." }
186
+ },
187
+ defaultOptions: [],
188
+ create: (context) => {
189
+ const sourceCode = context.sourceCode;
190
+ const { text } = sourceCode;
191
+ return { ImportDeclaration(node) {
192
+ if (!POSSIBLE_IMPORT_SOURCES.includes(node.source.value)) return;
193
+ const promisesSpecifier = node.specifiers.find((s) => s.type === "ImportSpecifier" && s.imported.type === "Identifier" && s.imported.name === "promises" && s.local.name !== "promises");
194
+ const as = promisesSpecifier?.local.name;
195
+ if (!promisesSpecifier || !as) return;
196
+ context.report({
197
+ node,
198
+ messageId: "noImportPromisesAs",
199
+ *fix(fixer) {
200
+ const s = promisesSpecifier.range[0];
201
+ let e = promisesSpecifier.range[1];
202
+ if (text[e] === ",") e += 1;
203
+ yield fixer.removeRange([s, e]);
204
+ yield fixer.insertTextAfter(node, `\nimport ${as} from "${node.source.value}/promises";`);
205
+ }
206
+ });
207
+ } };
208
+ }
279
209
  });
280
210
 
281
- // src/rules/no-inline-type-import.ts
282
- import { AST_NODE_TYPES as AST_NODE_TYPES2 } from "@typescript-eslint/types";
283
- var RULE_NAME4 = "no-inline-type-import";
211
+ //#endregion
212
+ //#region src/rules/no-inline-type-import.ts
213
+ const RULE_NAME$4 = "no-inline-type-import";
284
214
  var no_inline_type_import_default = createEslintRule({
285
- name: RULE_NAME4,
286
- meta: {
287
- type: "layout",
288
- docs: {
289
- description: "Disallow inline type import.",
290
- recommended: "stylistic"
291
- },
292
- fixable: "code",
293
- schema: [],
294
- messages: {
295
- noInlineTypeImport: "Expected no inline type import."
296
- }
297
- },
298
- defaultOptions: [],
299
- create: (context) => {
300
- const sourceCode = context.sourceCode;
301
- return {
302
- ImportDeclaration: (node) => {
303
- const { specifiers } = node;
304
- const typeSpecifiers = specifiers.filter(
305
- (s) => s.type === AST_NODE_TYPES2.ImportSpecifier && s.importKind === "type"
306
- );
307
- const valueSpecifiers = specifiers.filter(
308
- (s) => s.type === AST_NODE_TYPES2.ImportSpecifier && s.importKind === "value"
309
- );
310
- const defaultImportSpecifier = specifiers.find(
311
- (s) => s.type === AST_NODE_TYPES2.ImportDefaultSpecifier
312
- );
313
- if (typeSpecifiers.length > 0 && valueSpecifiers.length > 0) {
314
- context.report({
315
- node,
316
- messageId: "noInlineTypeImport",
317
- fix(fixer) {
318
- const typeSpecifiersText = typeSpecifiers.map((s) => sourceCode.getText(s).replace("type ", "")).join(", ");
319
- const valueSpecifiersText = valueSpecifiers.map((s) => sourceCode.getText(s)).join(", ");
320
- const defaultImportSpecifierText = sourceCode.getText(
321
- defaultImportSpecifier
322
- );
323
- const defaultAndValueSpecifiersText = defaultImportSpecifier ? `import ${defaultImportSpecifierText}, { ${valueSpecifiersText} } from "${node.source.value}";` : `import { ${valueSpecifiersText} } from "${node.source.value}";`;
324
- const texts = [
325
- `import type { ${typeSpecifiersText} } from "${node.source.value}";`,
326
- defaultAndValueSpecifiersText
327
- ];
328
- return fixer.replaceText(node, texts.join("\n"));
329
- }
330
- });
331
- } else if (typeSpecifiers.length > 0) {
332
- context.report({
333
- node,
334
- messageId: "noInlineTypeImport",
335
- fix(fixer) {
336
- const typeSpecifiersText = typeSpecifiers.map((s) => sourceCode.getText(s).replace("type ", "")).join(", ");
337
- return fixer.replaceText(
338
- node,
339
- `import type { ${typeSpecifiersText} } from "${node.source.value}";`
340
- );
341
- }
342
- });
343
- }
344
- }
345
- };
346
- }
215
+ name: RULE_NAME$4,
216
+ meta: {
217
+ type: "layout",
218
+ docs: { description: "Disallow inline type import." },
219
+ fixable: "code",
220
+ schema: [],
221
+ messages: { noInlineTypeImport: "Expected no inline type import." }
222
+ },
223
+ defaultOptions: [],
224
+ create: (context) => {
225
+ const sourceCode = context.sourceCode;
226
+ return { ImportDeclaration: (node) => {
227
+ const { specifiers } = node;
228
+ const typeSpecifiers = specifiers.filter((s) => s.type === AST_NODE_TYPES.ImportSpecifier && s.importKind === "type");
229
+ const valueSpecifiers = specifiers.filter((s) => s.type === AST_NODE_TYPES.ImportSpecifier && s.importKind === "value");
230
+ const defaultImportSpecifier = specifiers.find((s) => s.type === AST_NODE_TYPES.ImportDefaultSpecifier);
231
+ if (typeSpecifiers.length > 0 && valueSpecifiers.length > 0) context.report({
232
+ node,
233
+ messageId: "noInlineTypeImport",
234
+ fix(fixer) {
235
+ const typeSpecifiersText = typeSpecifiers.map((s) => sourceCode.getText(s).replace("type ", "")).join(", ");
236
+ const valueSpecifiersText = valueSpecifiers.map((s) => sourceCode.getText(s)).join(", ");
237
+ const defaultImportSpecifierText = sourceCode.getText(defaultImportSpecifier);
238
+ const defaultAndValueSpecifiersText = defaultImportSpecifier ? `import ${defaultImportSpecifierText}, { ${valueSpecifiersText} } from "${node.source.value}";` : `import { ${valueSpecifiersText} } from "${node.source.value}";`;
239
+ const texts = [`import type { ${typeSpecifiersText} } from "${node.source.value}";`, defaultAndValueSpecifiersText];
240
+ return fixer.replaceText(node, texts.join("\n"));
241
+ }
242
+ });
243
+ else if (typeSpecifiers.length > 0) context.report({
244
+ node,
245
+ messageId: "noInlineTypeImport",
246
+ fix(fixer) {
247
+ const typeSpecifiersText = typeSpecifiers.map((s) => sourceCode.getText(s).replace("type ", "")).join(", ");
248
+ return fixer.replaceText(node, `import type { ${typeSpecifiersText} } from "${node.source.value}";`);
249
+ }
250
+ });
251
+ } };
252
+ }
347
253
  });
348
254
 
349
- // src/rules/no-negated-comparison.ts
350
- import { AST_NODE_TYPES as AST_NODE_TYPES3 } from "@typescript-eslint/types";
351
- var RULE_NAME5 = "no-negated-comparison";
352
- var negatedToPositive = {
353
- "==": "!=",
354
- "===": "!==",
355
- "!=": "==",
356
- "!==": "===",
357
- "<": ">=",
358
- "<=": ">",
359
- ">": "<=",
360
- ">=": "<"
255
+ //#endregion
256
+ //#region src/rules/no-negated-comparison.ts
257
+ const RULE_NAME$3 = "no-negated-comparison";
258
+ const negatedToPositive = {
259
+ "==": "!=",
260
+ "===": "!==",
261
+ "!=": "==",
262
+ "!==": "===",
263
+ "<": ">=",
264
+ "<=": ">",
265
+ ">": "<=",
266
+ ">=": "<"
361
267
  };
362
- var negatives = Object.keys(negatedToPositive);
268
+ const negatives = Object.keys(negatedToPositive);
363
269
  var no_negated_comparison_default = createEslintRule({
364
- name: RULE_NAME5,
365
- meta: {
366
- type: "problem",
367
- docs: {
368
- description: "Disallow negated comparison.",
369
- recommended: "stylistic"
370
- },
371
- fixable: "code",
372
- schema: [],
373
- messages: {
374
- noNegatedComparison: "Expect no negated comparison."
375
- }
376
- },
377
- defaultOptions: [],
378
- create: (context) => ({
379
- BinaryExpression(node) {
380
- const { parent, left, right, operator } = node;
381
- if (!parent) {
382
- return;
383
- }
384
- if (negatives.includes(operator) && parent.type === AST_NODE_TYPES3.UnaryExpression && // Is this necessary?
385
- parent.operator === "!") {
386
- context.report({
387
- node,
388
- messageId: "noNegatedComparison",
389
- *fix(fixer) {
390
- const operatorRange = [left.range[1], right.range[0]];
391
- const fixedOperator = negatedToPositive[operator];
392
- yield fixer.replaceTextRange(operatorRange, fixedOperator);
393
- yield fixer.removeRange([parent.range[0], parent.range[0] + 1]);
394
- }
395
- });
396
- }
397
- }
398
- })
270
+ name: RULE_NAME$3,
271
+ meta: {
272
+ type: "problem",
273
+ docs: { description: "Disallow negated comparison." },
274
+ fixable: "code",
275
+ schema: [],
276
+ messages: { noNegatedComparison: "Expect no negated comparison." }
277
+ },
278
+ defaultOptions: [],
279
+ create: (context) => ({ BinaryExpression(node) {
280
+ const { parent, left, right, operator } = node;
281
+ if (!parent) return;
282
+ if (negatives.includes(operator) && parent.type === AST_NODE_TYPES.UnaryExpression && parent.operator === "!") context.report({
283
+ node,
284
+ messageId: "noNegatedComparison",
285
+ *fix(fixer) {
286
+ const operatorRange = [left.range[1], right.range[0]];
287
+ const fixedOperator = negatedToPositive[operator];
288
+ yield fixer.replaceTextRange(operatorRange, fixedOperator);
289
+ yield fixer.removeRange([parent.range[0], parent.range[0] + 1]);
290
+ }
291
+ });
292
+ } })
399
293
  });
400
294
 
401
- // src/rules/no-useless-template-string.ts
402
- var RULE_NAME6 = "no-useless-template-string";
295
+ //#endregion
296
+ //#region src/rules/no-useless-template-string.ts
297
+ const RULE_NAME$2 = "no-useless-template-string";
403
298
  var no_useless_template_string_default = createEslintRule({
404
- name: RULE_NAME6,
405
- meta: {
406
- type: "problem",
407
- docs: {
408
- description: "No useless template string.",
409
- recommended: "stylistic"
410
- },
411
- fixable: "code",
412
- schema: [],
413
- messages: {
414
- noUselessTemplateString: "No useless template string."
415
- }
416
- },
417
- defaultOptions: [],
418
- create: (context) => ({
419
- "TemplateLiteral:not(TaggedTemplateExpression > TemplateLiteral)"(node) {
420
- const { quasis } = node;
421
- const isSafe = !quasis.some(
422
- ({ value: { raw } }) => raw.includes('"') || raw.includes("'") || raw.includes("\n")
423
- );
424
- if (node.expressions.length === 0 && isSafe) {
425
- context.report({
426
- node,
427
- messageId: "noUselessTemplateString",
428
- fix(fixer) {
429
- return fixer.replaceTextRange(
430
- node.range,
431
- `"${node.quasis[0].value.raw}"`
432
- );
433
- }
434
- });
435
- }
436
- }
437
- })
299
+ name: RULE_NAME$2,
300
+ meta: {
301
+ type: "problem",
302
+ docs: { description: "No useless template string." },
303
+ fixable: "code",
304
+ schema: [],
305
+ messages: { noUselessTemplateString: "No useless template string." }
306
+ },
307
+ defaultOptions: [],
308
+ create: (context) => ({ "TemplateLiteral:not(TaggedTemplateExpression > TemplateLiteral)"(node) {
309
+ const { quasis } = node;
310
+ const isSafe = !quasis.some(({ value: { raw } }) => raw.includes("\"") || raw.includes("'") || raw.includes("\n"));
311
+ if (node.expressions.length === 0 && isSafe) context.report({
312
+ node,
313
+ messageId: "noUselessTemplateString",
314
+ fix(fixer) {
315
+ return fixer.replaceTextRange(node.range, `"${node.quasis[0].value.raw}"`);
316
+ }
317
+ });
318
+ } })
438
319
  });
439
320
 
440
- // src/rules/pad-after-last-import.ts
441
- var RULE_NAME7 = "pad-after-last-import";
321
+ //#endregion
322
+ //#region src/rules/pad-after-last-import.ts
323
+ const RULE_NAME$1 = "pad-after-last-import";
442
324
  var pad_after_last_import_default = createEslintRule({
443
- name: RULE_NAME7,
444
- meta: {
445
- type: "problem",
446
- docs: {
447
- description: "Pad after the last import.",
448
- recommended: "stylistic"
449
- },
450
- fixable: "code",
451
- schema: [],
452
- messages: {
453
- padAfterLastImport: "Expected a blank line after the last import."
454
- }
455
- },
456
- defaultOptions: [],
457
- create: (context) => {
458
- const sourceCode = context.sourceCode;
459
- let lastImportNode = null;
460
- return {
461
- ImportDeclaration(node) {
462
- lastImportNode = node;
463
- },
464
- "Program:exit"() {
465
- if (lastImportNode) {
466
- const nextToken = sourceCode.getTokenAfter(lastImportNode);
467
- const firstCommentAfterTokenStartLine = sourceCode.getCommentsAfter(lastImportNode)[0]?.loc.start.line;
468
- const expectedLine = lastImportNode.loc.end.line + 1;
469
- const nextTokenStartLine = nextToken?.loc.start.line;
470
- if (nextToken && // Workaround: Vue
471
- nextToken.value !== "</script>" && (expectedLine === nextTokenStartLine || expectedLine === firstCommentAfterTokenStartLine)) {
472
- context.report({
473
- node: lastImportNode,
474
- messageId: "padAfterLastImport",
475
- fix: (fixer) => fixer.insertTextAfter(lastImportNode, "\n")
476
- });
477
- }
478
- }
479
- }
480
- };
481
- }
325
+ name: RULE_NAME$1,
326
+ meta: {
327
+ type: "problem",
328
+ docs: { description: "Pad after the last import." },
329
+ fixable: "code",
330
+ schema: [],
331
+ messages: { padAfterLastImport: "Expected a blank line after the last import." }
332
+ },
333
+ defaultOptions: [],
334
+ create: (context) => {
335
+ const sourceCode = context.sourceCode;
336
+ let lastImportNode = null;
337
+ return {
338
+ ImportDeclaration(node) {
339
+ lastImportNode = node;
340
+ },
341
+ "Program:exit"() {
342
+ if (lastImportNode) {
343
+ const nextToken = sourceCode.getTokenAfter(lastImportNode);
344
+ const firstCommentAfterTokenStartLine = sourceCode.getCommentsAfter(lastImportNode)[0]?.loc.start.line;
345
+ const expectedLine = lastImportNode.loc.end.line + 1;
346
+ const nextTokenStartLine = nextToken?.loc.start.line;
347
+ if (nextToken && nextToken.value !== "</script>" && (expectedLine === nextTokenStartLine || expectedLine === firstCommentAfterTokenStartLine)) context.report({
348
+ node: lastImportNode,
349
+ messageId: "padAfterLastImport",
350
+ fix: (fixer) => fixer.insertTextAfter(lastImportNode, "\n")
351
+ });
352
+ }
353
+ }
354
+ };
355
+ }
482
356
  });
483
357
 
484
- // src/rules/require-async-with-await.ts
485
- import { TSESTree } from "@typescript-eslint/types";
486
- var RULE_NAME8 = "require-async-with-await";
358
+ //#endregion
359
+ //#region src/rules/require-async-with-await.ts
360
+ const RULE_NAME = "require-async-with-await";
487
361
  var require_async_with_await_default = createEslintRule({
488
- name: RULE_NAME8,
489
- meta: {
490
- type: "problem",
491
- docs: {
492
- description: "Require using async keyword with await.",
493
- recommended: "recommended"
494
- },
495
- fixable: "code",
496
- schema: [],
497
- messages: {
498
- requireAsyncWithAwait: "Expect using async keyword with await."
499
- }
500
- },
501
- defaultOptions: [],
502
- create: (context) => {
503
- const functionNodeStack = [];
504
- function setupNode(node) {
505
- functionNodeStack.push(node);
506
- }
507
- function clearNode() {
508
- functionNodeStack.pop();
509
- }
510
- return {
511
- "FunctionExpression": setupNode,
512
- "FunctionExpression:exit": clearNode,
513
- "FunctionDeclaration": setupNode,
514
- "FunctionDeclaration:exit": clearNode,
515
- "ArrowFunctionExpression": setupNode,
516
- "ArrowFunctionExpression:exit": clearNode,
517
- AwaitExpression() {
518
- const node = functionNodeStack[functionNodeStack.length - 1];
519
- if (!node || node.async) {
520
- return;
521
- }
522
- let fixRange;
523
- if (node.type === TSESTree.AST_NODE_TYPES.ArrowFunctionExpression) {
524
- fixRange = node.range;
525
- }
526
- if (node.type === TSESTree.AST_NODE_TYPES.FunctionDeclaration || node.type === TSESTree.AST_NODE_TYPES.FunctionExpression) {
527
- if (node.parent.type === TSESTree.AST_NODE_TYPES.Property || node.parent.type === TSESTree.AST_NODE_TYPES.MethodDefinition) {
528
- if (node.parent.kind === "method" || node.parent.kind === "init") {
529
- fixRange = node.parent.key.range;
530
- }
531
- } else {
532
- fixRange = node.range;
533
- }
534
- }
535
- if (fixRange) {
536
- context.report({
537
- node,
538
- messageId: "requireAsyncWithAwait",
539
- fix: (fixer) => fixer.insertTextBeforeRange(fixRange, "async ")
540
- });
541
- }
542
- }
543
- };
544
- }
362
+ name: RULE_NAME,
363
+ meta: {
364
+ type: "problem",
365
+ docs: { description: "Require using async keyword with await." },
366
+ fixable: "code",
367
+ schema: [],
368
+ messages: { requireAsyncWithAwait: "Expect using async keyword with await." }
369
+ },
370
+ defaultOptions: [],
371
+ create: (context) => {
372
+ const functionNodeStack = [];
373
+ function setupNode(node) {
374
+ functionNodeStack.push(node);
375
+ }
376
+ function clearNode() {
377
+ functionNodeStack.pop();
378
+ }
379
+ return {
380
+ "FunctionExpression": setupNode,
381
+ "FunctionExpression:exit": clearNode,
382
+ "FunctionDeclaration": setupNode,
383
+ "FunctionDeclaration:exit": clearNode,
384
+ "ArrowFunctionExpression": setupNode,
385
+ "ArrowFunctionExpression:exit": clearNode,
386
+ AwaitExpression() {
387
+ const node = functionNodeStack[functionNodeStack.length - 1];
388
+ if (!node || node.async) return;
389
+ let fixRange;
390
+ if (node.type === TSESTree.AST_NODE_TYPES.ArrowFunctionExpression) fixRange = node.range;
391
+ if (node.type === TSESTree.AST_NODE_TYPES.FunctionDeclaration || node.type === TSESTree.AST_NODE_TYPES.FunctionExpression) if (node.parent.type === TSESTree.AST_NODE_TYPES.Property || node.parent.type === TSESTree.AST_NODE_TYPES.MethodDefinition) {
392
+ if (node.parent.kind === "method" || node.parent.kind === "init") fixRange = node.parent.key.range;
393
+ } else fixRange = node.range;
394
+ if (fixRange) context.report({
395
+ node,
396
+ messageId: "requireAsyncWithAwait",
397
+ fix: (fixer) => fixer.insertTextBeforeRange(fixRange, "async ")
398
+ });
399
+ }
400
+ };
401
+ }
545
402
  });
546
403
 
547
- // src/index.ts
548
- var src_default = {
549
- rules: {
550
- "function-style": function_style_default,
551
- "import-dedupe": import_dedupe_default,
552
- "no-inline-type-import": no_inline_type_import_default,
553
- "no-negated-comparison": no_negated_comparison_default,
554
- "no-useless-template-string": no_useless_template_string_default,
555
- "no-import-promises-as": no_import_promises_as_default,
556
- "pad-after-last-import": pad_after_last_import_default,
557
- "require-async-with-await": require_async_with_await_default
558
- }
559
- };
560
- export {
561
- src_default as default
562
- };
404
+ //#endregion
405
+ //#region src/index.ts
406
+ var src_default = { rules: {
407
+ "function-style": function_style_default,
408
+ "import-dedupe": import_dedupe_default,
409
+ "no-inline-type-import": no_inline_type_import_default,
410
+ "no-negated-comparison": no_negated_comparison_default,
411
+ "no-useless-template-string": no_useless_template_string_default,
412
+ "no-import-promises-as": no_import_promises_as_default,
413
+ "pad-after-last-import": pad_after_last_import_default,
414
+ "require-async-with-await": require_async_with_await_default
415
+ } };
416
+
417
+ //#endregion
418
+ export { src_default as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@so1ve/eslint-plugin",
3
- "version": "3.1.0",
3
+ "version": "3.3.0",
4
4
  "author": "Ray <i@mk1.io> (https://github.com/so1ve/)",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -33,12 +33,15 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@typescript-eslint/types": "^7.12.0",
37
- "@typescript-eslint/utils": "^7.12.0"
36
+ "@typescript-eslint/types": "^8.34.0",
37
+ "@typescript-eslint/utils": "^8.34.0"
38
+ },
39
+ "devDependencies": {
40
+ "vue-eslint-parser": "^10.1.3"
38
41
  },
39
42
  "scripts": {
40
- "build": "tsup",
43
+ "build": "tsdown",
41
44
  "test": "vitest",
42
- "watch": "tsup --watch"
45
+ "watch": "tsdown --watch"
43
46
  }
44
47
  }