@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.
- package/dist/index.d.ts +16 -14
- package/dist/index.js +388 -532
- package/package.json +8 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import * as
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3
|
+
|
|
4
|
+
//#region src/utils/index.ts
|
|
5
|
+
const createEslintRule = ESLintUtils.RuleCreator((ruleName) => ruleName);
|
|
7
6
|
function getPreviousNode(node) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
25
|
-
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/rules/function-style.ts
|
|
19
|
+
const RULE_NAME$7 = "function-style";
|
|
26
20
|
var function_style_default = createEslintRule({
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
173
|
-
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region src/rules/import-dedupe.ts
|
|
132
|
+
const RULE_NAME$6 = "import-dedupe";
|
|
174
133
|
var import_dedupe_default = createEslintRule({
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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
|
-
|
|
268
|
+
const negatives = Object.keys(negatedToPositive);
|
|
363
269
|
var no_negated_comparison_default = createEslintRule({
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
-
|
|
402
|
-
|
|
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
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
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
|
-
|
|
441
|
-
|
|
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
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
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
|
-
|
|
485
|
-
|
|
486
|
-
|
|
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
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
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.
|
|
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": "^
|
|
37
|
-
"@typescript-eslint/utils": "^
|
|
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": "
|
|
43
|
+
"build": "tsdown",
|
|
41
44
|
"test": "vitest",
|
|
42
|
-
"watch": "
|
|
45
|
+
"watch": "tsdown --watch"
|
|
43
46
|
}
|
|
44
47
|
}
|