mm_eslint 1.1.9 → 1.2.1

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 (2) hide show
  1. package/index.js +133 -35
  2. 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
- const is_upper_snake = /^[A-Z][A-Z0-9_]*(_[A-Z0-9]+)+$/.test(name);
934
- const is_upper_multi = /^[A-Z][A-Z0-9]*[A-Z][A-Z0-9]*$/.test(name);
935
-
936
- if (is_upper_snake || is_upper_multi) {
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
- if (config.styles && config.styles.length > 0) {
943
- const is_valid_style = this._checkStyle(name, config.styles);
944
- if (!is_valid_style && !is_upper_snake && !is_upper_multi) {
945
- this._suggestValueName(name, config, errors);
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
- * @returns {string} 属性值类型('function', 'class', 'value')
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" ||
@@ -1026,20 +1048,44 @@ Detector.prototype._getPropType = function (val_node, prop_name) {
1026
1048
  (val_node.name.endsWith("Function") ||
1027
1049
  val_node.name.endsWith("Func") ||
1028
1050
  val_node.name.startsWith("on") ||
1029
- val_node.name.startsWith("handle")))
1051
+ val_node.name.startsWith("handle") ||
1052
+ // 新增:常见函数命名模式识别
1053
+ val_node.name.endsWith("Manager") ||
1054
+ val_node.name.endsWith("Admin") ||
1055
+ val_node.name.endsWith("Handler") ||
1056
+ val_node.name.endsWith("Service") ||
1057
+ val_node.name.endsWith("Util") ||
1058
+ val_node.name.endsWith("Helper") ||
1059
+ val_node.name.endsWith("Factory") ||
1060
+ val_node.name.endsWith("Provider") ||
1061
+ // 检查是否为小驼峰命名(函数常见命名风格)
1062
+ (/^[a-z][a-zA-Z0-9]*$/.test(val_node.name) &&
1063
+ val_node.name !== val_node.name.toLowerCase() &&
1064
+ !val_node.name.includes("_") &&
1065
+ !val_node.name.includes("-"))))
1030
1066
  ) {
1031
1067
  return "function";
1032
1068
  }
1033
1069
 
1034
1070
  // 检查是否为类
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
- ) {
1071
+ if (val_node.type === "ClassExpression" || val_node.type === "NewExpression") {
1041
1072
  return "class";
1042
1073
  }
1074
+
1075
+ // 对于标识符类型的值,采用保守策略
1076
+ // 只有当明显是类名时才认为是类类型
1077
+ if (val_node.type === "Identifier" && val_node.name) {
1078
+ // 检查标识符名称是否符合类名模式(PascalCase)
1079
+ const is_pascal_case = /^[A-Z][a-zA-Z0-9]*$/.test(val_node.name);
1080
+
1081
+ // 如果标识符名称符合PascalCase,且不是常见的配置参数名,则认为是类类型
1082
+ const common_config_names = ['config', 'options', 'params', 'settings', 'props'];
1083
+ const is_common_config = common_config_names.includes(val_node.name.toLowerCase());
1084
+
1085
+ if (is_pascal_case && !is_common_config) {
1086
+ return "class";
1087
+ }
1088
+ }
1043
1089
 
1044
1090
  // 检查是否为常量/配置值(应该使用UPPERCASE风格)
1045
1091
  if (this._isConst(val_node, prop_name)) {
@@ -1079,6 +1125,58 @@ Detector.prototype._isConst = function (val_node, prop_name) {
1079
1125
  return this._isConstWithoutName(is_prim_const, is_cfg_obj, is_const_id);
1080
1126
  };
1081
1127
 
1128
+ /**
1129
+ * 判断标识符是否为类名(基于上下文分析)
1130
+ * @param {string} name - 标识符名称
1131
+ * @param {Object} context_node - 上下文AST节点
1132
+ * @returns {boolean} 是否为类名
1133
+ * @private
1134
+ */
1135
+ Detector.prototype._isClassName = function (name, context_node) {
1136
+ if (!name || typeof name !== 'string') {
1137
+ return false;
1138
+ }
1139
+
1140
+ // 首先检查是否为大驼峰命名(类名的基本要求)
1141
+ if (!/^[A-Z][a-zA-Z]*$/.test(name)) {
1142
+ return false;
1143
+ }
1144
+
1145
+ // 如果有上下文节点,进行更精确的分析
1146
+ if (context_node) {
1147
+ // 检查是否在类声明中
1148
+ if (context_node.type === 'ClassDeclaration' ||
1149
+ context_node.type === 'ClassExpression') {
1150
+ return true;
1151
+ }
1152
+
1153
+ // 检查是否在 extends 或 implements 中
1154
+ if (context_node.type === 'Identifier' &&
1155
+ context_node.parent &&
1156
+ (context_node.parent.type === 'ClassDeclaration' ||
1157
+ context_node.parent.type === 'ClassExpression')) {
1158
+ return true;
1159
+ }
1160
+
1161
+ // 检查是否在 new 表达式中
1162
+ if (context_node.type === 'NewExpression' &&
1163
+ context_node.callee &&
1164
+ context_node.callee.name === name) {
1165
+ return true;
1166
+ }
1167
+ }
1168
+
1169
+ // 对于没有上下文的情况,采用保守策略
1170
+ // 只对明显是类名的标识符返回 true
1171
+ const class_suffixes = [
1172
+ 'Manager', 'Controller', 'Service', 'Factory', 'Builder',
1173
+ 'Provider', 'Middleware', 'Component', 'Repository', 'Handler',
1174
+ 'Adapter', 'Decorator', 'Validator', 'Generator', 'Processor'
1175
+ ];
1176
+
1177
+ return class_suffixes.some(suffix => name.endsWith(suffix));
1178
+ };
1179
+
1082
1180
  /**
1083
1181
  * 检查是否为基本类型常量
1084
1182
  * @private
@@ -2362,7 +2460,7 @@ const prop_name_rule = {
2362
2460
  // 如果是真正的属性,使用属性规则检测
2363
2461
  const prop_name = node.key.name;
2364
2462
  const detector = new Detector({ "property-name": options });
2365
- const result = detector._checkPropName(prop_name, node.value);
2463
+ const result = detector._checkPropName(prop_name, node.value, node);
2366
2464
 
2367
2465
  if (!result.valid) {
2368
2466
  result.errors.forEach((error) => {
@@ -2605,9 +2703,9 @@ const instance_property_rule = {
2605
2703
  !node.left.property.name.startsWith("_")
2606
2704
  ) {
2607
2705
  const prop_name = node.left.property.name;
2608
- // 实例属性应该符合变量命名规范(小写蛇形)
2609
- const detector = new Detector({ "variable-name": options });
2610
- const result = detector.checkName(prop_name, "variable-name");
2706
+ // 实例属性应该符合属性命名规范(小写蛇形)
2707
+ const detector = new Detector({ "property-name": options });
2708
+ const result = detector._checkPropName(prop_name, node.right, node);
2611
2709
 
2612
2710
  if (!result.valid) {
2613
2711
  result.errors.forEach((error) => {
@@ -2628,9 +2726,9 @@ const instance_property_rule = {
2628
2726
  !node.key.name.startsWith("_")
2629
2727
  ) {
2630
2728
  const prop_name = node.key.name;
2631
- // 实例属性应该符合方法命名规范(小驼峰)
2632
- const detector = new Detector({ "method-name": options });
2633
- const result = detector.checkName(prop_name, "method-name");
2729
+ // 实例属性应该符合属性命名规范(小写蛇形)
2730
+ const detector = new Detector({ "property-name": options });
2731
+ const result = detector._checkPropName(prop_name, node.value, node);
2634
2732
 
2635
2733
  if (!result.valid) {
2636
2734
  result.errors.forEach((error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mm_eslint",
3
- "version": "1.1.9",
3
+ "version": "1.2.1",
4
4
  "description": "ESLint plugin for naming conventions - PascalCase, camelCase, snake_case, and UPPER_SNAKE_CASE naming rules",
5
5
  "main": "index.js",
6
6
  "keywords": [