@lsby/eslint-plugin 0.0.18 → 0.0.19
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.js
CHANGED
|
@@ -4,18 +4,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const no_definite_assignment_assertion_1 = __importDefault(require("./lib/rules/no-definite-assignment-assertion"));
|
|
7
|
+
const no_early_return_on_equality_1 = __importDefault(require("./lib/rules/no-early-return-on-equality"));
|
|
7
8
|
const no_else_on_equality_1 = __importDefault(require("./lib/rules/no-else-on-equality"));
|
|
8
9
|
const no_negation_1 = __importDefault(require("./lib/rules/no-negation"));
|
|
9
10
|
const no_switch_default_1 = __importDefault(require("./lib/rules/no-switch-default"));
|
|
10
11
|
const prefer_let_1 = __importDefault(require("./lib/rules/prefer-let"));
|
|
11
|
-
const prefer_switch_over_multi_if_1 = __importDefault(require("./lib/rules/prefer-switch-over-multi-if"));
|
|
12
12
|
module.exports = {
|
|
13
13
|
rules: {
|
|
14
14
|
'prefer-let': prefer_let_1.default,
|
|
15
15
|
'no-negation': no_negation_1.default,
|
|
16
16
|
'no-definite-assignment-assertion': no_definite_assignment_assertion_1.default,
|
|
17
|
+
'no-early-return-on-equality': no_early_return_on_equality_1.default,
|
|
17
18
|
'no-else-on-equality': no_else_on_equality_1.default,
|
|
18
19
|
'no-switch-default': no_switch_default_1.default,
|
|
19
|
-
'prefer-switch-over-multi-if': prefer_switch_over_multi_if_1.default,
|
|
20
20
|
},
|
|
21
21
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// 禁止等于条件的if提前返回,但允许不等于条件的提前返回
|
|
3
|
+
// 使用等于条件的提前返回容易遗漏状态,应该用正向的不等于条件或结构化流程
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
const rule = {
|
|
6
|
+
meta: {
|
|
7
|
+
type: 'problem',
|
|
8
|
+
docs: {
|
|
9
|
+
description: '禁止在等于条件下使用提前返回(early return)。使用不等于条件的提前返回会更清晰地表达程序的主要流程',
|
|
10
|
+
},
|
|
11
|
+
messages: {
|
|
12
|
+
noEarlyReturnOnEquality: '禁止在等于条件下使用提前返回。建议改用不等于条件的提前返回,使主流程更清晰。例如:将 if (x === y) return; 改为 if (x !== y) { 主要逻辑 }',
|
|
13
|
+
},
|
|
14
|
+
schema: [],
|
|
15
|
+
},
|
|
16
|
+
defaultOptions: [],
|
|
17
|
+
create(context) {
|
|
18
|
+
/**
|
|
19
|
+
* 检查条件中是否是等于操作符(不包括不等于)
|
|
20
|
+
*/
|
|
21
|
+
function isEqualityOperator(node) {
|
|
22
|
+
if (node.type === 'BinaryExpression') {
|
|
23
|
+
return ['===', '=='].includes(node.operator);
|
|
24
|
+
}
|
|
25
|
+
if (node.type === 'LogicalExpression') {
|
|
26
|
+
return isEqualityOperator(node.left) || isEqualityOperator(node.right);
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 检查语句是否是提前返回或抛出(仅包含这些语句)
|
|
32
|
+
*/
|
|
33
|
+
function isEarlyExit(node) {
|
|
34
|
+
if (!node)
|
|
35
|
+
return false;
|
|
36
|
+
// 直接是 return 或 throw
|
|
37
|
+
if (node.type === 'ReturnStatement' || node.type === 'ThrowStatement') {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
// 是 block statement,检查其中的所有语句是否都是 return 或 throw
|
|
41
|
+
if (node.type === 'BlockStatement') {
|
|
42
|
+
return (node.body.length > 0 &&
|
|
43
|
+
node.body.every((stmt) => stmt.type === 'ReturnStatement' || stmt.type === 'ThrowStatement'));
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
IfStatement(node) {
|
|
49
|
+
// 检查:条件是等于 & if 分支是提前返回 & 没有 else 分支
|
|
50
|
+
if (!node.alternate && isEqualityOperator(node.test) && isEarlyExit(node.consequent)) {
|
|
51
|
+
context.report({ node, messageId: 'noEarlyReturnOnEquality' });
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
exports.default = rule;
|
package/package.json
CHANGED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// 建议使用 switch 替代多个 if 判断同一变量
|
|
3
|
-
// 当有多个连续的 if 语句判断同一个表达式时, 应该使用 switch 来提高代码的可读性
|
|
4
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
const rule = {
|
|
6
|
-
meta: {
|
|
7
|
-
type: 'suggestion',
|
|
8
|
-
docs: { description: '检测多个连续 if 判断同一个表达式,建议使用 switch 提高可读性' },
|
|
9
|
-
messages: { preferSwitch: '检测到 {{count}} 个连续的 if 判断同一个表达式,可以考虑使用 switch 提高可读性' },
|
|
10
|
-
schema: [],
|
|
11
|
-
},
|
|
12
|
-
defaultOptions: [],
|
|
13
|
-
create(context) {
|
|
14
|
-
const sourceCode = context.sourceCode;
|
|
15
|
-
const minIfs = 2;
|
|
16
|
-
function getText(node) {
|
|
17
|
-
return sourceCode.getText(node);
|
|
18
|
-
}
|
|
19
|
-
function isValidCaseValue(node) {
|
|
20
|
-
return (node.type === 'Literal' ||
|
|
21
|
-
node.type === 'TemplateLiteral' ||
|
|
22
|
-
node.type === 'Identifier' ||
|
|
23
|
-
node.type === 'MemberExpression');
|
|
24
|
-
}
|
|
25
|
-
function getSwitchInfo(test) {
|
|
26
|
-
if (test.type !== 'BinaryExpression')
|
|
27
|
-
return null;
|
|
28
|
-
// 支持所有的二元比较操作符
|
|
29
|
-
const comparisonOps = ['===', '==', '!==', '!=', '>', '<', '>=', '<='];
|
|
30
|
-
if (!comparisonOps.includes(test.operator))
|
|
31
|
-
return null;
|
|
32
|
-
const left = test.left;
|
|
33
|
-
const right = test.right;
|
|
34
|
-
if ((left.type === 'Identifier' || left.type === 'MemberExpression') && isValidCaseValue(right)) {
|
|
35
|
-
return { variable: getText(left), value: getText(right) };
|
|
36
|
-
}
|
|
37
|
-
if ((right.type === 'Identifier' || right.type === 'MemberExpression') && isValidCaseValue(left)) {
|
|
38
|
-
return { variable: getText(right), value: getText(left) };
|
|
39
|
-
}
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
function collectIfChain(node) {
|
|
43
|
-
const chain = [node];
|
|
44
|
-
let current = node;
|
|
45
|
-
// 收集 else-if 链
|
|
46
|
-
while (current.alternate && current.alternate.type === 'IfStatement') {
|
|
47
|
-
chain.push(current.alternate);
|
|
48
|
-
current = current.alternate;
|
|
49
|
-
}
|
|
50
|
-
// 如果没有 else-if,尝试收集相邻的 if 语句
|
|
51
|
-
if (chain.length === 1 && node.parent) {
|
|
52
|
-
const parent = node.parent;
|
|
53
|
-
let body = null;
|
|
54
|
-
if (parent.type === 'BlockStatement') {
|
|
55
|
-
body = parent.body;
|
|
56
|
-
}
|
|
57
|
-
else if (parent.type === 'Program') {
|
|
58
|
-
body = parent.body;
|
|
59
|
-
}
|
|
60
|
-
if (body) {
|
|
61
|
-
const nodeIndex = body.indexOf(node);
|
|
62
|
-
if (nodeIndex !== -1) {
|
|
63
|
-
const firstInfo = getSwitchInfo(node.test);
|
|
64
|
-
if (firstInfo) {
|
|
65
|
-
let nextIndex = nodeIndex + 1;
|
|
66
|
-
while (nextIndex < body.length && body[nextIndex].type === 'IfStatement') {
|
|
67
|
-
const nextIfStmt = body[nextIndex];
|
|
68
|
-
if (nextIfStmt.alternate)
|
|
69
|
-
break; // 如果有 else/else-if,停止
|
|
70
|
-
const nextInfo = getSwitchInfo(nextIfStmt.test);
|
|
71
|
-
if (!nextInfo || nextInfo.variable !== firstInfo.variable)
|
|
72
|
-
break; // 变量不同,停止
|
|
73
|
-
chain.push(nextIfStmt);
|
|
74
|
-
nextIndex++;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return chain;
|
|
81
|
-
}
|
|
82
|
-
function allSameVariable(chain) {
|
|
83
|
-
if (chain.length < minIfs)
|
|
84
|
-
return null;
|
|
85
|
-
const firstInfo = getSwitchInfo(chain[0].test);
|
|
86
|
-
if (!firstInfo)
|
|
87
|
-
return null;
|
|
88
|
-
for (const stmt of chain.slice(1)) {
|
|
89
|
-
const info = getSwitchInfo(stmt.test);
|
|
90
|
-
if (!info || info.variable !== firstInfo.variable)
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
return { variable: firstInfo.variable, count: chain.length };
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
IfStatement(node) {
|
|
97
|
-
if (node.parent?.type === 'IfStatement' && node.parent.alternate === node)
|
|
98
|
-
return;
|
|
99
|
-
const chain = collectIfChain(node);
|
|
100
|
-
const info = allSameVariable(chain);
|
|
101
|
-
if (!info)
|
|
102
|
-
return;
|
|
103
|
-
context.report({ node, messageId: 'preferSwitch', data: { count: info.count } });
|
|
104
|
-
},
|
|
105
|
-
};
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
exports.default = rule;
|