mm_eslint 1.1.9 → 1.2.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/index.js +118 -34
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -372,10 +372,7 @@ class Detector {
|
|
|
372
372
|
"snake_case",
|
|
373
373
|
"_snake_case",
|
|
374
374
|
"UPPERCASE",
|
|
375
|
-
"UPPER_SNAKE_CASE"
|
|
376
|
-
"PascalCase",
|
|
377
|
-
"camelCase",
|
|
378
|
-
"_camelCase"
|
|
375
|
+
"UPPER_SNAKE_CASE"
|
|
379
376
|
],
|
|
380
377
|
strong: true, // 强验证模式:根据属性值类型智能判断;false:弱验证模式:只需符合变量名或常量名规则
|
|
381
378
|
},
|
|
@@ -769,10 +766,11 @@ Detector.prototype._splitWords = function (name, rule_type) {
|
|
|
769
766
|
* 属性名检查方法(根据属性值类型应用不同规则)
|
|
770
767
|
* @param {string} name - 属性名
|
|
771
768
|
* @param {Object} val_node - 属性值AST节点
|
|
769
|
+
* @param {Object} parent_node - 父节点AST节点(可选,用于上下文感知检测)
|
|
772
770
|
* @returns {Object} 检查结果
|
|
773
771
|
* @private
|
|
774
772
|
*/
|
|
775
|
-
Detector.prototype._checkPropName = function (name, val_node) {
|
|
773
|
+
Detector.prototype._checkPropName = function (name, val_node, parent_node) {
|
|
776
774
|
if (!name) {
|
|
777
775
|
throw new TypeError("属性名不能为空");
|
|
778
776
|
}
|
|
@@ -789,7 +787,7 @@ Detector.prototype._checkPropName = function (name, val_node) {
|
|
|
789
787
|
this._checkBadWords(name, config, errors);
|
|
790
788
|
|
|
791
789
|
const use_strong_val = config.strong !== false;
|
|
792
|
-
const val_type = this._getPropType(val_node, name);
|
|
790
|
+
const val_type = this._getPropType(val_node, name, parent_node);
|
|
793
791
|
|
|
794
792
|
if (use_strong_val) {
|
|
795
793
|
this._checkPropStrong(name, val_type, config, errors);
|
|
@@ -834,6 +832,9 @@ Detector.prototype._checkPropStrong = function (
|
|
|
834
832
|
case "function":
|
|
835
833
|
this._checkFuncProp(name, config, errors);
|
|
836
834
|
break;
|
|
835
|
+
case "method":
|
|
836
|
+
this._checkMethodProp(name, config, errors);
|
|
837
|
+
break;
|
|
837
838
|
case "class":
|
|
838
839
|
this._checkClassProp(name, config, errors);
|
|
839
840
|
break;
|
|
@@ -856,6 +857,9 @@ Detector.prototype._checkPropWeak = function (name, val_type, config, errors) {
|
|
|
856
857
|
case "function":
|
|
857
858
|
this._checkFuncProp(name, config, errors);
|
|
858
859
|
break;
|
|
860
|
+
case "method":
|
|
861
|
+
this._checkMethodProp(name, config, errors);
|
|
862
|
+
break;
|
|
859
863
|
case "class":
|
|
860
864
|
this._checkClassProp(name, config, errors);
|
|
861
865
|
break;
|
|
@@ -903,6 +907,17 @@ Detector.prototype._checkConstProp = function (name, config, errors) {
|
|
|
903
907
|
}
|
|
904
908
|
};
|
|
905
909
|
|
|
910
|
+
/**
|
|
911
|
+
* 检查方法属性
|
|
912
|
+
* @private
|
|
913
|
+
*/
|
|
914
|
+
Detector.prototype._checkMethodProp = function (name, config, errors) {
|
|
915
|
+
const method_res = this._checkName("method-name", name);
|
|
916
|
+
if (!method_res.valid) {
|
|
917
|
+
errors.push(`${config.name}(方法)${method_res.errors.join(", ")}`);
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
|
|
906
921
|
/**
|
|
907
922
|
* 建议常量命名
|
|
908
923
|
* @private
|
|
@@ -930,21 +945,20 @@ Detector.prototype._suggestConstName = function (name, config, errors) {
|
|
|
930
945
|
* @private
|
|
931
946
|
*/
|
|
932
947
|
Detector.prototype._checkValueProp = function (name, config, errors) {
|
|
933
|
-
|
|
934
|
-
const
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
errors.push(
|
|
938
|
-
`${config.name}(值)禁止使用大写蛇形命名(如PRODUCT_ID或PRODUCTID)`,
|
|
939
|
-
);
|
|
948
|
+
// 检查常量规则
|
|
949
|
+
const const_res = this._checkName("constant-name", name);
|
|
950
|
+
if (const_res.valid) {
|
|
951
|
+
return; // 满足常量规则,通过
|
|
940
952
|
}
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
}
|
|
953
|
+
|
|
954
|
+
// 检查变量规则
|
|
955
|
+
const var_res = this._checkName("variable-name", name);
|
|
956
|
+
if (var_res.valid) {
|
|
957
|
+
return; // 满足变量规则,通过
|
|
947
958
|
}
|
|
959
|
+
|
|
960
|
+
// 都不满足,报告错误
|
|
961
|
+
errors.push(`${config.name}(值)必须符合变量或常量命名规则`);
|
|
948
962
|
};
|
|
949
963
|
|
|
950
964
|
/**
|
|
@@ -1009,14 +1023,22 @@ Detector.prototype._checkPropSingleWord = function (name, config, warnings) {
|
|
|
1009
1023
|
/**
|
|
1010
1024
|
* 获取属性值类型
|
|
1011
1025
|
* @param {Object} val_node - 属性值AST节点
|
|
1012
|
-
* @
|
|
1026
|
+
* @param {string} prop_name - 属性名
|
|
1027
|
+
* @param {Object} parent_node - 父节点AST节点(可选,用于上下文感知检测)
|
|
1028
|
+
* @returns {string} 属性值类型('function', 'method', 'class', 'value')
|
|
1013
1029
|
* @private
|
|
1014
1030
|
*/
|
|
1015
|
-
Detector.prototype._getPropType = function (val_node, prop_name) {
|
|
1031
|
+
Detector.prototype._getPropType = function (val_node, prop_name, parent_node) {
|
|
1016
1032
|
if (!val_node) {
|
|
1017
1033
|
return "value"; // 默认值类型
|
|
1018
1034
|
}
|
|
1019
1035
|
|
|
1036
|
+
// 检查是否为对象方法(在对象字面量中的函数)
|
|
1037
|
+
if (parent_node && parent_node.type === "Property" &&
|
|
1038
|
+
(val_node.type === "FunctionExpression" || val_node.type === "ArrowFunctionExpression")) {
|
|
1039
|
+
return "method"; // 对象方法类型
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1020
1042
|
// 检查是否为函数
|
|
1021
1043
|
if (
|
|
1022
1044
|
val_node.type === "FunctionExpression" ||
|
|
@@ -1032,14 +1054,24 @@ Detector.prototype._getPropType = function (val_node, prop_name) {
|
|
|
1032
1054
|
}
|
|
1033
1055
|
|
|
1034
1056
|
// 检查是否为类
|
|
1035
|
-
if (
|
|
1036
|
-
val_node.type === "ClassExpression" ||
|
|
1037
|
-
(val_node.type === "Identifier" &&
|
|
1038
|
-
val_node.name &&
|
|
1039
|
-
/^[A-Z][a-zA-Z]*$/.test(val_node.name))
|
|
1040
|
-
) {
|
|
1057
|
+
if (val_node.type === "ClassExpression" || val_node.type === "NewExpression") {
|
|
1041
1058
|
return "class";
|
|
1042
1059
|
}
|
|
1060
|
+
|
|
1061
|
+
// 对于标识符类型的值,采用保守策略
|
|
1062
|
+
// 只有当明显是类名时才认为是类类型
|
|
1063
|
+
if (val_node.type === "Identifier" && val_node.name) {
|
|
1064
|
+
// 检查标识符名称是否符合类名模式(PascalCase)
|
|
1065
|
+
const is_pascal_case = /^[A-Z][a-zA-Z0-9]*$/.test(val_node.name);
|
|
1066
|
+
|
|
1067
|
+
// 如果标识符名称符合PascalCase,且不是常见的配置参数名,则认为是类类型
|
|
1068
|
+
const common_config_names = ['config', 'options', 'params', 'settings', 'props'];
|
|
1069
|
+
const is_common_config = common_config_names.includes(val_node.name.toLowerCase());
|
|
1070
|
+
|
|
1071
|
+
if (is_pascal_case && !is_common_config) {
|
|
1072
|
+
return "class";
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1043
1075
|
|
|
1044
1076
|
// 检查是否为常量/配置值(应该使用UPPERCASE风格)
|
|
1045
1077
|
if (this._isConst(val_node, prop_name)) {
|
|
@@ -1079,6 +1111,58 @@ Detector.prototype._isConst = function (val_node, prop_name) {
|
|
|
1079
1111
|
return this._isConstWithoutName(is_prim_const, is_cfg_obj, is_const_id);
|
|
1080
1112
|
};
|
|
1081
1113
|
|
|
1114
|
+
/**
|
|
1115
|
+
* 判断标识符是否为类名(基于上下文分析)
|
|
1116
|
+
* @param {string} name - 标识符名称
|
|
1117
|
+
* @param {Object} context_node - 上下文AST节点
|
|
1118
|
+
* @returns {boolean} 是否为类名
|
|
1119
|
+
* @private
|
|
1120
|
+
*/
|
|
1121
|
+
Detector.prototype._isClassName = function (name, context_node) {
|
|
1122
|
+
if (!name || typeof name !== 'string') {
|
|
1123
|
+
return false;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// 首先检查是否为大驼峰命名(类名的基本要求)
|
|
1127
|
+
if (!/^[A-Z][a-zA-Z]*$/.test(name)) {
|
|
1128
|
+
return false;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// 如果有上下文节点,进行更精确的分析
|
|
1132
|
+
if (context_node) {
|
|
1133
|
+
// 检查是否在类声明中
|
|
1134
|
+
if (context_node.type === 'ClassDeclaration' ||
|
|
1135
|
+
context_node.type === 'ClassExpression') {
|
|
1136
|
+
return true;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
// 检查是否在 extends 或 implements 中
|
|
1140
|
+
if (context_node.type === 'Identifier' &&
|
|
1141
|
+
context_node.parent &&
|
|
1142
|
+
(context_node.parent.type === 'ClassDeclaration' ||
|
|
1143
|
+
context_node.parent.type === 'ClassExpression')) {
|
|
1144
|
+
return true;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// 检查是否在 new 表达式中
|
|
1148
|
+
if (context_node.type === 'NewExpression' &&
|
|
1149
|
+
context_node.callee &&
|
|
1150
|
+
context_node.callee.name === name) {
|
|
1151
|
+
return true;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// 对于没有上下文的情况,采用保守策略
|
|
1156
|
+
// 只对明显是类名的标识符返回 true
|
|
1157
|
+
const class_suffixes = [
|
|
1158
|
+
'Manager', 'Controller', 'Service', 'Factory', 'Builder',
|
|
1159
|
+
'Provider', 'Middleware', 'Component', 'Repository', 'Handler',
|
|
1160
|
+
'Adapter', 'Decorator', 'Validator', 'Generator', 'Processor'
|
|
1161
|
+
];
|
|
1162
|
+
|
|
1163
|
+
return class_suffixes.some(suffix => name.endsWith(suffix));
|
|
1164
|
+
};
|
|
1165
|
+
|
|
1082
1166
|
/**
|
|
1083
1167
|
* 检查是否为基本类型常量
|
|
1084
1168
|
* @private
|
|
@@ -2362,7 +2446,7 @@ const prop_name_rule = {
|
|
|
2362
2446
|
// 如果是真正的属性,使用属性规则检测
|
|
2363
2447
|
const prop_name = node.key.name;
|
|
2364
2448
|
const detector = new Detector({ "property-name": options });
|
|
2365
|
-
const result = detector._checkPropName(prop_name, node.value);
|
|
2449
|
+
const result = detector._checkPropName(prop_name, node.value, node);
|
|
2366
2450
|
|
|
2367
2451
|
if (!result.valid) {
|
|
2368
2452
|
result.errors.forEach((error) => {
|
|
@@ -2605,9 +2689,9 @@ const instance_property_rule = {
|
|
|
2605
2689
|
!node.left.property.name.startsWith("_")
|
|
2606
2690
|
) {
|
|
2607
2691
|
const prop_name = node.left.property.name;
|
|
2608
|
-
//
|
|
2609
|
-
const detector = new Detector({ "
|
|
2610
|
-
const result = detector.
|
|
2692
|
+
// 实例属性应该符合属性命名规范(小写蛇形)
|
|
2693
|
+
const detector = new Detector({ "property-name": options });
|
|
2694
|
+
const result = detector._checkPropName(prop_name, node.right, node);
|
|
2611
2695
|
|
|
2612
2696
|
if (!result.valid) {
|
|
2613
2697
|
result.errors.forEach((error) => {
|
|
@@ -2628,9 +2712,9 @@ const instance_property_rule = {
|
|
|
2628
2712
|
!node.key.name.startsWith("_")
|
|
2629
2713
|
) {
|
|
2630
2714
|
const prop_name = node.key.name;
|
|
2631
|
-
//
|
|
2632
|
-
const detector = new Detector({ "
|
|
2633
|
-
const result = detector.
|
|
2715
|
+
// 实例属性应该符合属性命名规范(小写蛇形)
|
|
2716
|
+
const detector = new Detector({ "property-name": options });
|
|
2717
|
+
const result = detector._checkPropName(prop_name, node.value, node);
|
|
2634
2718
|
|
|
2635
2719
|
if (!result.valid) {
|
|
2636
2720
|
result.errors.forEach((error) => {
|