mm_eslint 1.4.1 → 1.4.3

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 (5) hide show
  1. package/config.js +81 -45
  2. package/detector.js +2374 -376
  3. package/index.js +977 -77
  4. package/package.json +1 -1
  5. package/README_EN.md +0 -410
package/detector.js CHANGED
@@ -9,19 +9,19 @@ class Detector {
9
9
  constructor(config) {
10
10
  // 直接将传入的配置对象赋值,确保原型方法不被丢失
11
11
  this.config = config;
12
-
12
+
13
13
  // 添加命名类型的中文描述
14
14
  this.config.name_type_map = {
15
- 'class-name': '类名',
16
- 'function-name': '函数名',
17
- 'method-name': '方法名',
18
- 'variable-name': '变量名',
19
- 'param-name': '参数名',
20
- 'constant-name': '常量名',
21
- 'property-class-name': '属性类名',
22
- 'property-instance-class-name': '属性实例类名',
23
- 'property-method-name': '属性方法名',
24
- 'property-value-name': '属性值名'
15
+ "class-name": "类名",
16
+ "function-name": "函数名",
17
+ "method-name": "方法名",
18
+ "variable-name": "变量名",
19
+ "param-name": "参数名",
20
+ "constant-name": "常量名",
21
+ "property-class-name": "属性类名",
22
+ "property-instance-class-name": "属性实例类名",
23
+ "property-method-name": "属性方法名",
24
+ "property-value-name": "属性值名",
25
25
  };
26
26
  }
27
27
  }
@@ -34,64 +34,119 @@ class Detector {
34
34
  */
35
35
  Detector.prototype._checkClassName = function (class_name, node) {
36
36
  try {
37
- var rule = this.config.getRule('class-name');
37
+ var rule = this.config.getRule("class-name");
38
38
  if (!rule) {
39
39
  return null;
40
40
  }
41
41
 
42
42
  // 检查是否为忽略词
43
- if (this._isIgnoredWord(class_name, 'class-name')) {
43
+ if (this._isIgnoredWord(class_name, "class-name")) {
44
44
  return null;
45
45
  }
46
46
 
47
47
  // 检查命名风格
48
- var style_err = this._validate_naming_style(class_name, rule.styles, 'class-name');
48
+ var style_err = this._validate_naming_style(
49
+ class_name,
50
+ rule.styles,
51
+ "class-name",
52
+ );
49
53
  if (style_err) {
54
+ // 如果有推荐建议,在风格错误消息后附加推荐
55
+ var smart_abbreviation = this._getSmartAbbreviation(
56
+ class_name,
57
+ "class-name",
58
+ );
59
+ var error_message = style_err;
60
+ if (smart_abbreviation && smart_abbreviation !== class_name) {
61
+ error_message = style_err + ",建议使用: " + smart_abbreviation;
62
+ }
50
63
  return {
51
64
  node: node,
52
- message: style_err,
65
+ message: error_message,
66
+ rule_type: "class-name",
53
67
  };
54
68
  }
55
69
 
56
70
  // 检查并推荐更合适的词汇
57
- var rec_err = this._checkAndRecommend(class_name, 'class-name');
71
+ var rec_err = this._checkAndRecommend(class_name, "class-name");
58
72
  if (rec_err) {
73
+ // 生成完整的建议名称
74
+ var recommended_full_name = class_name.replace(
75
+ new RegExp(rec_err.original_word, "i"),
76
+ rec_err.recommended_word,
77
+ );
78
+
59
79
  return {
60
80
  node: node,
61
- message: rec_err,
81
+ message: "类名'" + class_name + "',建议使用: " + recommended_full_name,
82
+ rule_type: "class-name",
62
83
  };
63
84
  }
64
85
 
65
86
  // 检查长度
66
- var len_err = this._checkNameLength(class_name, rule.min, rule.max, 'class-name');
87
+ var len_err = this._checkNameLength(
88
+ class_name,
89
+ rule.min,
90
+ rule.max,
91
+ "class-name",
92
+ );
67
93
  if (len_err) {
94
+ // 使用智能缩写生成推荐名称
95
+ var smart_abbreviation = this._getSmartAbbreviation(
96
+ class_name,
97
+ "class-name",
98
+ );
99
+ var error_message = len_err;
100
+ if (smart_abbreviation && smart_abbreviation !== class_name) {
101
+ error_message = len_err + ",建议使用: " + smart_abbreviation;
102
+ }
68
103
  return {
69
104
  node: node,
70
- message: len_err,
105
+ message: error_message,
106
+ rule_type: "class-name",
71
107
  };
72
108
  }
73
109
 
74
110
  // 检查单词长度
75
- var word_err = this._checkWordLength(class_name, rule.single_word_len, 'class-name');
111
+ var word_err = this._checkWordLength(
112
+ class_name,
113
+ rule.single_word_len,
114
+ "class-name",
115
+ );
76
116
  if (word_err) {
117
+ // 检查错误消息是否已经包含建议
118
+ var error_message = word_err;
119
+ if (!word_err.includes("建议使用")) {
120
+ // 如果错误消息中不包含建议,则添加建议
121
+ var smart_abbreviation = this._getSmartAbbreviation(
122
+ class_name,
123
+ "class-name",
124
+ );
125
+ if (smart_abbreviation && smart_abbreviation !== class_name) {
126
+ error_message = word_err + ",建议使用: " + smart_abbreviation;
127
+ }
128
+ }
129
+
77
130
  return {
78
131
  node: node,
79
- message: word_err,
132
+ message: error_message,
133
+ rule_type: "class-name",
80
134
  };
81
135
  }
82
136
 
83
137
  // 检查禁止词汇
84
- var forbid_err = this._checkForbiddenWords(class_name, 'class-name');
138
+ var forbid_err = this._checkForbiddenWords(class_name, "class-name");
85
139
  if (forbid_err) {
86
140
  return {
87
141
  node: node,
88
142
  message: forbid_err,
143
+ rule_type: "class-name",
89
144
  };
90
145
  }
91
146
 
92
147
  return null;
93
148
  } catch (error) {
94
- console.error('检测类名时出错:', error);
149
+ console.error("检测类名时出错:", error);
95
150
  return null;
96
151
  }
97
152
  };
@@ -104,72 +159,138 @@ Detector.prototype._checkClassName = function (class_name, node) {
104
159
  */
105
160
  Detector.prototype._checkMethodName = function (method_name, node) {
106
161
  try {
107
- var rule = this.config.getRule('method-name');
162
+ var rule = this.config.getRule("method-name");
108
163
  if (!rule) {
109
164
  return null;
110
165
  }
111
166
 
112
167
  // 检查是否为忽略词(在所有检测之前)
113
- if (this._isIgnoredWord(method_name, 'method-name')) {
168
+ if (this._isIgnoredWord(method_name, "method-name")) {
114
169
  return null;
115
170
  }
116
171
 
117
172
  // 检查命名风格(支持公开方法和私有方法)
118
173
  var style_err = null;
119
- if (method_name.startsWith('_')) {
174
+ if (method_name.startsWith("_")) {
120
175
  // 私有方法:检查是否符合私有方法命名规范
121
- style_err = this._validate_naming_style(method_name, ['_camelCase'], 'method-name');
176
+ style_err = this._validate_naming_style(
177
+ method_name,
178
+ ["_camelCase"],
179
+ "method-name",
180
+ );
122
181
  } else {
123
182
  // 公开方法:检查是否符合公开方法命名规范
124
- style_err = this._validate_naming_style(method_name, rule.styles, 'method-name');
183
+ style_err = this._validate_naming_style(
184
+ method_name,
185
+ rule.styles,
186
+ "method-name",
187
+ );
125
188
  }
126
189
 
127
190
  if (style_err) {
191
+ // 使用智能缩写生成推荐名称
192
+ var smart_abbreviation = this._getSmartAbbreviation(
193
+ method_name,
194
+ "method-name",
195
+ );
196
+ var error_message = style_err;
197
+ if (smart_abbreviation && smart_abbreviation !== method_name) {
198
+ error_message = style_err + ",建议使用: " + smart_abbreviation;
199
+ }
128
200
  return {
129
201
  node: node,
130
- message: style_err,
202
+ message: error_message,
131
203
  };
132
204
  }
133
205
 
134
206
  // 检查长度
135
- var len_err = this._checkNameLength(method_name, rule.min, rule.max, 'method-name');
207
+ var len_err = this._checkNameLength(
208
+ method_name,
209
+ rule.min,
210
+ rule.max,
211
+ "method-name",
212
+ );
136
213
  if (len_err) {
214
+ // 使用智能缩写生成推荐名称
215
+ var smart_abbreviation = this._getSmartAbbreviation(
216
+ method_name,
217
+ "method-name",
218
+ );
219
+ var error_message = len_err;
220
+ if (smart_abbreviation && smart_abbreviation !== method_name) {
221
+ error_message = len_err + ",建议使用: " + smart_abbreviation;
222
+ }
137
223
  return {
138
224
  node: node,
139
- message: len_err,
225
+ message: error_message,
140
226
  };
141
227
  }
142
228
 
143
229
  // 检查单词长度
144
- var word_err = this._checkWordLength(method_name, rule.single_word_len, 'method-name');
230
+ var word_err = this._checkWordLength(
231
+ method_name,
232
+ rule.single_word_len,
233
+ "method-name",
234
+ );
145
235
  if (word_err) {
236
+ // 检查错误消息是否已经包含建议
237
+ var error_message = word_err;
238
+ if (!word_err.includes("建议使用")) {
239
+ // 如果错误消息中不包含建议,则添加建议
240
+ var smart_abbreviation = this._getSmartAbbreviation(
241
+ method_name,
242
+ "method-name",
243
+ );
244
+ if (smart_abbreviation && smart_abbreviation !== method_name) {
245
+ error_message = word_err + ",建议使用: " + smart_abbreviation;
246
+ }
247
+ }
146
248
  return {
147
249
  node: node,
148
- message: word_err,
250
+ message: error_message,
149
251
  };
150
252
  }
151
253
 
152
254
  // 检查禁止词汇
153
- var forbid_err = this._checkForbiddenWords(method_name, 'method-name');
255
+ var forbid_err = this._checkForbiddenWords(method_name, "method-name");
154
256
  if (forbid_err) {
257
+ // 使用智能缩写生成推荐名称
258
+ var smart_abbreviation = this._getSmartAbbreviation(
259
+ method_name,
260
+ "method-name",
261
+ );
262
+ var error_message = forbid_err;
263
+ if (smart_abbreviation && smart_abbreviation !== method_name) {
264
+ error_message = forbid_err + ",建议使用: " + smart_abbreviation;
265
+ }
155
266
  return {
156
267
  node: node,
157
- message: forbid_err,
268
+ message: error_message,
158
269
  };
159
270
  }
160
271
 
161
- // 检查并推荐更合适的词汇
162
- var recommend_err = this._checkAndRecommend(method_name, 'method-name');
163
- if (recommend_err) {
272
+ // 如果没有错误但有推荐建议,返回优化建议
273
+ var smart_abbreviation = this._getSmartAbbreviation(
274
+ method_name,
275
+ "method-name",
276
+ );
277
+ if (smart_abbreviation && smart_abbreviation !== method_name) {
164
278
  return {
165
279
  node: node,
166
- message: recommend_err,
280
+ message:
281
+ "方法名'" +
282
+ method_name +
283
+ "'不是行业通用名,建议使用: " +
284
+ smart_abbreviation,
285
+ fix: function (fixer) {
286
+ return fixer.replaceText(node, smart_abbreviation);
287
+ },
167
288
  };
168
289
  }
169
290
 
170
291
  return null;
171
292
  } catch (error) {
172
- console.error('检测方法名时出错:', error);
293
+ console.error("检测方法名时出错:", error);
173
294
  return null;
174
295
  }
175
296
  };
@@ -182,67 +303,148 @@ Detector.prototype._checkMethodName = function (method_name, node) {
182
303
  */
183
304
  Detector.prototype._checkFunctionName = function (function_name, node) {
184
305
  try {
185
- var rule = this.config.getRule('function-name');
306
+ var rule = this.config.getRule("function-name");
186
307
  if (!rule) {
187
308
  return null;
188
309
  }
189
310
 
190
311
  // 检查是否为忽略词
191
- if (this._isIgnoredWord(function_name, 'function-name')) {
312
+ if (this._isIgnoredWord(function_name, "function-name")) {
192
313
  return null;
193
314
  }
194
315
 
316
+ // 检查是否为私有函数(不允许私有函数)
317
+ if (function_name.startsWith("_")) {
318
+ // 生成建议:去掉下划线前缀,转换为公有函数
319
+ var public_function_name = function_name.substring(1);
320
+ // 使用智能缩写生成推荐名称
321
+ var smart_abbreviation = this._getSmartAbbreviation(
322
+ public_function_name,
323
+ "function-name",
324
+ );
325
+ var recommended_name =
326
+ smart_abbreviation && smart_abbreviation !== public_function_name
327
+ ? smart_abbreviation
328
+ : public_function_name;
329
+
330
+ return {
331
+ node: node,
332
+ message:
333
+ "函数名'" +
334
+ function_name +
335
+ "'不允许声明私有函数,建议使用: " +
336
+ recommended_name,
337
+ };
338
+ }
339
+
195
340
  // 检查命名风格
196
- var style_err = this._validate_naming_style(function_name, rule.styles, 'function-name');
341
+ var style_err = this._validate_naming_style(
342
+ function_name,
343
+ rule.styles,
344
+ "function-name",
345
+ );
197
346
  if (style_err) {
347
+ // 使用智能缩写生成推荐名称
348
+ var smart_abbreviation = this._getSmartAbbreviation(
349
+ function_name,
350
+ "function-name",
351
+ );
352
+ var error_message = style_err;
353
+ if (smart_abbreviation && smart_abbreviation !== function_name) {
354
+ error_message = style_err + ",建议使用: " + smart_abbreviation;
355
+ }
198
356
  return {
199
357
  node: node,
200
- message: style_err,
358
+ message: error_message,
201
359
  };
202
360
  }
203
361
 
204
362
  // 检查长度
205
- var len_err = this._checkNameLength(function_name, rule.min, rule.max, 'function-name');
363
+ var len_err = this._checkNameLength(
364
+ function_name,
365
+ rule.min,
366
+ rule.max,
367
+ "function-name",
368
+ );
206
369
  if (len_err) {
370
+ // 使用智能缩写生成推荐名称
371
+ var smart_abbreviation = this._getSmartAbbreviation(
372
+ function_name,
373
+ "function-name",
374
+ );
375
+ var error_message = len_err;
376
+ if (smart_abbreviation && smart_abbreviation !== function_name) {
377
+ error_message = len_err + ",建议使用: " + smart_abbreviation;
378
+ }
207
379
  return {
208
380
  node: node,
209
- message: len_err,
381
+ message: error_message,
210
382
  };
211
383
  }
212
384
 
213
385
  // 检查单词长度
214
- var word_err = this._checkWordLength(function_name, rule.single_word_len, 'function-name');
386
+ var word_err = this._checkWordLength(
387
+ function_name,
388
+ rule.single_word_len,
389
+ "function-name",
390
+ );
215
391
  if (word_err) {
392
+ // 检查错误消息是否已经包含建议
393
+ var error_message = word_err;
394
+ if (!word_err.includes("建议使用")) {
395
+ // 如果错误消息中不包含建议,则添加建议
396
+ var smart_abbreviation = this._getSmartAbbreviation(
397
+ function_name,
398
+ "function-name",
399
+ );
400
+ if (smart_abbreviation && smart_abbreviation !== function_name) {
401
+ error_message = word_err + ",建议使用: " + smart_abbreviation;
402
+ }
403
+ }
216
404
  return {
217
405
  node: node,
218
- message: word_err,
406
+ message: error_message,
219
407
  };
220
408
  }
221
409
 
222
410
  // 检查禁止词汇
223
- var forbid_err = this._checkForbiddenWords(
224
- function_name,
225
- 'function-name',
226
- );
411
+ var forbid_err = this._checkForbiddenWords(function_name, "function-name");
227
412
  if (forbid_err) {
413
+ // 使用智能缩写生成推荐名称
414
+ var smart_abbreviation = this._getSmartAbbreviation(
415
+ function_name,
416
+ "function-name",
417
+ );
418
+ var error_message = forbid_err;
419
+ if (smart_abbreviation && smart_abbreviation !== function_name) {
420
+ error_message = forbid_err + ",建议使用: " + smart_abbreviation;
421
+ }
228
422
  return {
229
423
  node: node,
230
- message: forbid_err,
424
+ message: error_message,
231
425
  };
232
426
  }
233
427
 
234
- // 检查并推荐更合适的词汇
235
- var recommend_err = this._checkAndRecommend(function_name, 'function-name');
236
- if (recommend_err) {
428
+ // 检查并推荐更合适的词汇(作为命名风格检查的补充)
429
+ var recommend_info = this._checkAndRecommend(
430
+ function_name,
431
+ "function-name",
432
+ );
433
+ if (recommend_info) {
434
+ // 如果有推荐建议,提示可以使用更简洁的词汇
237
435
  return {
238
436
  node: node,
239
- message: recommend_err,
437
+ message:
438
+ "函数名'" +
439
+ function_name +
440
+ "'建议使用: " +
441
+ recommend_info.recommended_name,
240
442
  };
241
443
  }
242
444
 
243
445
  return null;
244
446
  } catch (error) {
245
- console.error('检测函数名时出错:', error);
447
+ console.error("检测函数名时出错:", error);
246
448
  return null;
247
449
  }
248
450
  };
@@ -255,18 +457,22 @@ Detector.prototype._checkFunctionName = function (function_name, node) {
255
457
  */
256
458
  Detector.prototype._checkVariableName = function (variable_name, node) {
257
459
  try {
258
- var rule = this.config.getRule('variable-name');
460
+ var rule = this.config.getRule("variable-name");
259
461
  if (!rule) {
260
462
  return null;
261
463
  }
262
464
 
263
465
  // 检查是否为忽略词
264
- if (this._isIgnoredWord(variable_name, 'variable-name')) {
466
+ if (this._isIgnoredWord(variable_name, "variable-name")) {
265
467
  return null;
266
468
  }
267
469
 
268
470
  // 检查命名风格
269
- var style_err = this._validate_naming_style(variable_name, rule.styles, 'variable-name');
471
+ var style_err = this._validate_naming_style(
472
+ variable_name,
473
+ rule.styles,
474
+ "variable-name",
475
+ );
270
476
  if (style_err) {
271
477
  return {
272
478
  node: node,
@@ -275,28 +481,59 @@ Detector.prototype._checkVariableName = function (variable_name, node) {
275
481
  }
276
482
 
277
483
  // 检查长度
278
- var len_err = this._checkNameLength(variable_name, rule.min, rule.max, 'variable-name');
484
+ var len_err = this._checkNameLength(
485
+ variable_name,
486
+ rule.min,
487
+ rule.max,
488
+ "variable-name",
489
+ );
279
490
  if (len_err) {
491
+ // 检查错误消息是否已经包含建议
492
+ var error_message = len_err;
493
+ if (!len_err.includes("建议使用")) {
494
+ // 如果错误消息中不包含建议,则添加建议
495
+ var smart_abbreviation = this._getSmartAbbreviation(
496
+ variable_name,
497
+ "variable-name",
498
+ );
499
+ if (smart_abbreviation && smart_abbreviation !== variable_name) {
500
+ error_message = len_err + ",建议使用: " + smart_abbreviation;
501
+ }
502
+ }
503
+
280
504
  return {
281
505
  node: node,
282
- message: len_err,
506
+ message: error_message,
283
507
  };
284
508
  }
285
509
 
286
510
  // 检查单词长度
287
- var word_err = this._checkWordLength(variable_name, rule.single_word_len, 'variable-name');
511
+ var word_err = this._checkWordLength(
512
+ variable_name,
513
+ rule.single_word_len,
514
+ "variable-name",
515
+ );
288
516
  if (word_err) {
517
+ // 检查错误消息是否已经包含建议
518
+ var error_message = word_err;
519
+ if (!word_err.includes("建议使用")) {
520
+ // 如果错误消息中不包含建议,则添加建议
521
+ var smart_abbreviation = this._getSmartAbbreviation(
522
+ variable_name,
523
+ "variable-name",
524
+ );
525
+ if (smart_abbreviation && smart_abbreviation !== variable_name) {
526
+ error_message = word_err + ",建议使用: " + smart_abbreviation;
527
+ }
528
+ }
289
529
  return {
290
530
  node: node,
291
- message: word_err,
531
+ message: error_message,
292
532
  };
293
533
  }
294
534
 
295
535
  // 检查禁止词汇
296
- var forbid_err = this._checkForbiddenWords(
297
- variable_name,
298
- 'variable-name',
299
- );
536
+ var forbid_err = this._checkForbiddenWords(variable_name, "variable-name");
300
537
  if (forbid_err) {
301
538
  return {
302
539
  node: node,
@@ -306,7 +543,7 @@ Detector.prototype._checkVariableName = function (variable_name, node) {
306
543
 
307
544
  return null;
308
545
  } catch (error) {
309
- console.error('检测变量名时出错:', error);
546
+ console.error("检测变量名时出错:", error);
310
547
  return null;
311
548
  }
312
549
  };
@@ -319,55 +556,111 @@ Detector.prototype._checkVariableName = function (variable_name, node) {
319
556
  */
320
557
  Detector.prototype._checkParamName = function (param_name, node) {
321
558
  try {
322
- var rule = this.config.getRule('param-name');
559
+ var rule = this.config.getRule("param-name");
323
560
  if (!rule) {
324
561
  return null;
325
562
  }
326
563
 
327
564
  // 检查是否为忽略词
328
- if (this._isIgnoredWord(param_name, 'param-name')) {
565
+ if (this._isIgnoredWord(param_name, "param-name")) {
329
566
  return null;
330
567
  }
331
568
 
332
569
  // 检查命名风格
333
- var style_err = this._validate_naming_style(param_name, rule.styles, 'param-name');
570
+ var style_err = this._validate_naming_style(
571
+ param_name,
572
+ rule.styles,
573
+ "param-name",
574
+ );
334
575
  if (style_err) {
576
+ // 使用智能缩写生成推荐名称
577
+ var smart_abbreviation = this._getSmartAbbreviation(
578
+ param_name,
579
+ "param-name",
580
+ );
581
+ var error_message = style_err;
582
+ if (smart_abbreviation && smart_abbreviation !== param_name) {
583
+ error_message = style_err + ",建议使用: " + smart_abbreviation;
584
+ }
335
585
  return {
336
586
  node: node,
337
- message: style_err,
587
+ message: error_message,
338
588
  };
339
589
  }
340
590
 
341
591
  // 检查长度
342
- var len_err = this._checkNameLength(param_name, rule.min, rule.max, 'param-name');
592
+ var len_err = this._checkNameLength(
593
+ param_name,
594
+ rule.min,
595
+ rule.max,
596
+ "param-name",
597
+ );
343
598
  if (len_err) {
599
+ // 检查错误消息是否已经包含建议
600
+ var error_message = len_err;
601
+ if (!len_err.includes("建议使用")) {
602
+ // 如果错误消息中不包含建议,则添加建议
603
+ var smart_abbreviation = this._getSmartAbbreviation(
604
+ param_name,
605
+ "param-name",
606
+ );
607
+ if (smart_abbreviation && smart_abbreviation !== param_name) {
608
+ error_message = len_err + ",建议使用: " + smart_abbreviation;
609
+ }
610
+ }
611
+
344
612
  return {
345
613
  node: node,
346
- message: len_err,
614
+ message: error_message,
347
615
  };
348
616
  }
349
617
 
350
618
  // 检查单词长度
351
- var word_err = this._checkWordLength(param_name, rule.single_word_len, 'param-name');
619
+ var word_err = this._checkWordLength(
620
+ param_name,
621
+ rule.single_word_len,
622
+ "param-name",
623
+ );
352
624
  if (word_err) {
625
+ // 检查错误消息是否已经包含建议
626
+ var error_message = word_err;
627
+ if (!word_err.includes("建议使用")) {
628
+ // 如果错误消息中不包含建议,则添加建议
629
+ var smart_abbreviation = this._getSmartAbbreviation(
630
+ param_name,
631
+ "param-name",
632
+ );
633
+ if (smart_abbreviation && smart_abbreviation !== param_name) {
634
+ error_message = word_err + ",建议使用: " + smart_abbreviation;
635
+ }
636
+ }
353
637
  return {
354
638
  node: node,
355
- message: word_err,
639
+ message: error_message,
356
640
  };
357
641
  }
358
642
 
359
643
  // 检查禁止词汇
360
- var forbid_err = this._checkForbiddenWords(param_name, 'param-name');
644
+ var forbid_err = this._checkForbiddenWords(param_name, "param-name");
361
645
  if (forbid_err) {
646
+ // 使用智能缩写生成推荐名称
647
+ var smart_abbreviation = this._getSmartAbbreviation(
648
+ param_name,
649
+ "param-name",
650
+ );
651
+ var error_message = forbid_err;
652
+ if (smart_abbreviation && smart_abbreviation !== param_name) {
653
+ error_message = forbid_err + ",建议使用: " + smart_abbreviation;
654
+ }
362
655
  return {
363
656
  node: node,
364
- message: forbid_err,
657
+ message: error_message,
365
658
  };
366
659
  }
367
660
 
368
661
  return null;
369
662
  } catch (error) {
370
- console.error('检测参数名时出错:', error);
663
+ console.error("检测参数名时出错:", error);
371
664
  return null;
372
665
  }
373
666
  };
@@ -379,11 +672,15 @@ Detector.prototype._checkParamName = function (param_name, node) {
379
672
  * @param {object} val_node 值节点(用于识别基础值)
380
673
  * @returns {object|null} 错误信息或null
381
674
  */
382
- Detector.prototype._checkConstantName = function (constant_name, node, val_node) {
675
+ Detector.prototype._checkConstantName = function (
676
+ constant_name,
677
+ node,
678
+ val_node,
679
+ ) {
383
680
  try {
384
681
  // 检查是否为解构导入(从模块导入的变量)
385
682
  var is_destructured_import = this._isDestructuredImport(node);
386
-
683
+
387
684
  // 如果是解构导入,则不进行命名检测
388
685
  if (is_destructured_import) {
389
686
  return null;
@@ -391,34 +688,38 @@ Detector.prototype._checkConstantName = function (constant_name, node, val_node)
391
688
 
392
689
  // 检查是否应该使用let而不是const
393
690
  var should_use_let = this._shouldUseLetInsteadOfConst(node, val_node);
394
-
691
+
395
692
  // 如果应该使用let,则提示开发者
396
693
  if (should_use_let) {
397
694
  return {
398
695
  node: node,
399
- message: `变量'${constant_name}'应该使用let而不是const声明,因为它不是真正的常量`
696
+ message: `变量'${constant_name}'应该使用let而不是const声明,因为它不是真正的常量`,
400
697
  };
401
698
  }
402
699
 
403
700
  // 根据值类型确定应该应用的命名规则
404
- var rule_type = 'constant-name'; // 默认使用常量命名规则
701
+ var rule_type = "constant-name"; // 默认使用常量命名规则
405
702
  var allowed_styles = [];
406
703
 
407
704
  // 检查是否为函数表达式或箭头函数
408
- if (val_node && (val_node.type === 'FunctionExpression' || val_node.type === 'ArrowFunctionExpression')) {
409
- rule_type = 'function-name';
705
+ if (
706
+ val_node &&
707
+ (val_node.type === "FunctionExpression" ||
708
+ val_node.type === "ArrowFunctionExpression")
709
+ ) {
710
+ rule_type = "function-name";
410
711
  }
411
712
  // 检查是否为类表达式
412
- else if (val_node && val_node.type === 'ClassExpression') {
413
- rule_type = 'class-name';
713
+ else if (val_node && val_node.type === "ClassExpression") {
714
+ rule_type = "class-name";
414
715
  }
415
716
  // 检查是否为类实例(new表达式)
416
- else if (val_node && val_node.type === 'NewExpression') {
417
- rule_type = 'function-name'; // 类实例使用函数命名规则(camelCase)
717
+ else if (val_node && val_node.type === "NewExpression") {
718
+ rule_type = "function-name"; // 类实例使用函数命名规则(camelCase)
418
719
  }
419
720
  // 检查是否为基础值类型
420
721
  else if (val_node && this._isBaseValue(val_node)) {
421
- rule_type = 'constant-name';
722
+ rule_type = "constant-name";
422
723
  }
423
724
  // 检查是否为其他复杂类型(函数调用、变量引用等)
424
725
  else if (val_node && this._isComplexType(val_node)) {
@@ -431,7 +732,28 @@ Detector.prototype._checkConstantName = function (constant_name, node, val_node)
431
732
  }
432
733
 
433
734
  // 获取对应的命名规则
434
- var rule = this.config.getRule(rule_type);
735
+ // 将属性规则类型映射到对应的基础规则类型(用于获取规则配置)
736
+ var rule_config_type = rule_type;
737
+ if (rule_type.startsWith('property-')) {
738
+ // 属性类名 -> 类名
739
+ if (rule_type === 'property-class-name') {
740
+ rule_config_type = 'class-name';
741
+ }
742
+ // 属性实例类名 -> 变量名
743
+ else if (rule_type === 'property-instance-class-name') {
744
+ rule_config_type = 'variable-name';
745
+ }
746
+ // 属性方法名 -> 方法名
747
+ else if (rule_type === 'property-method-name') {
748
+ rule_config_type = 'method-name';
749
+ }
750
+ // 属性值名 -> 变量名
751
+ else if (rule_type === 'property-value-name') {
752
+ rule_config_type = 'variable-name';
753
+ }
754
+ }
755
+
756
+ var rule = this.config.getRule(rule_config_type);
435
757
  if (!rule) {
436
758
  return null;
437
759
  }
@@ -442,53 +764,115 @@ Detector.prototype._checkConstantName = function (constant_name, node, val_node)
442
764
  }
443
765
 
444
766
  // 检查命名风格
445
- var style_err = this._validate_naming_style(constant_name, rule.styles, rule_type);
767
+ var style_err = this._validate_naming_style(
768
+ constant_name,
769
+ rule.styles,
770
+ rule_type,
771
+ );
446
772
  if (style_err) {
773
+ // 使用智能缩写生成推荐名称
774
+ var smart_abbreviation = this._getSmartAbbreviation(
775
+ constant_name,
776
+ rule_type,
777
+ );
778
+ var error_message = style_err;
779
+ if (smart_abbreviation && smart_abbreviation !== constant_name) {
780
+ error_message = style_err + ",建议使用: " + smart_abbreviation;
781
+ }
782
+
447
783
  return {
448
784
  node: node,
449
- message: style_err,
785
+ message: error_message,
786
+ rule_type: rule_type, // 返回正确的规则类型
450
787
  };
451
788
  }
452
789
 
453
790
  // 检查长度
454
- var len_err = this._checkNameLength(constant_name, rule.min, rule.max, 'constant-name');
791
+ var len_err = this._checkNameLength(
792
+ constant_name,
793
+ rule.min,
794
+ rule.max,
795
+ rule_type,
796
+ );
455
797
  if (len_err) {
798
+ // 使用智能缩写生成推荐名称
799
+ var smart_abbreviation = this._getSmartAbbreviation(
800
+ constant_name,
801
+ rule_type,
802
+ );
803
+ var error_message = len_err;
804
+ if (smart_abbreviation && smart_abbreviation !== constant_name) {
805
+ error_message = len_err + ",建议使用: " + smart_abbreviation;
806
+ }
807
+
456
808
  return {
457
809
  node: node,
458
- message: len_err,
810
+ message: error_message,
811
+ rule_type: rule_type, // 返回正确的规则类型
459
812
  };
460
813
  }
461
814
 
462
815
  // 检查单词长度
463
- var word_err = this._checkWordLength(constant_name, rule.single_word_len, 'constant-name');
816
+ var word_err = this._checkWordLength(
817
+ constant_name,
818
+ rule.single_word_len,
819
+ rule_type,
820
+ );
464
821
  if (word_err) {
465
822
  return {
466
823
  node: node,
467
824
  message: word_err,
825
+ rule_type: rule_type, // 返回正确的规则类型
468
826
  };
469
827
  }
470
828
 
471
829
  // 检查禁止词汇
472
- var forbid_err = this._checkForbiddenWords(constant_name, 'constant-name');
830
+ var forbid_err = this._checkForbiddenWords(constant_name, rule_type);
473
831
  if (forbid_err) {
474
832
  return {
475
833
  node: node,
476
834
  message: forbid_err,
835
+ rule_type: rule_type, // 返回正确的规则类型
477
836
  };
478
837
  }
479
838
 
480
- // 检查并推荐更合适的词汇
481
- var rec_err = this._checkAndRecommend(constant_name, 'constant-name');
482
- if (rec_err) {
839
+ // 检查并推荐更合适的词汇(作为命名风格检查的补充)
840
+ var recommend_info = this._checkAndRecommend(constant_name, rule_type);
841
+ if (recommend_info) {
842
+ // 根据规则类型生成正确的错误消息
843
+ var name_type_text = "";
844
+ switch (rule_type) {
845
+ case "function-name":
846
+ name_type_text = "函数名";
847
+ break;
848
+ case "class-name":
849
+ name_type_text = "类名";
850
+ break;
851
+ case "constant-name":
852
+ name_type_text = "常量名";
853
+ break;
854
+ case "variable-name":
855
+ name_type_text = "变量名";
856
+ break;
857
+ default:
858
+ name_type_text = "名称";
859
+ }
860
+
483
861
  return {
484
862
  node: node,
485
- message: rec_err,
863
+ message:
864
+ name_type_text +
865
+ "'" +
866
+ constant_name +
867
+ "'长度过长,最大长度为20字符,建议使用: " +
868
+ recommend_info.recommended_name,
869
+ rule_type: rule_type, // 返回正确的规则类型
486
870
  };
487
871
  }
488
872
 
489
873
  return null;
490
874
  } catch (error) {
491
- console.error('检测常量名时出错:', error);
875
+ console.error("检测常量名时出错:", error);
492
876
  return null;
493
877
  }
494
878
  };
@@ -513,11 +897,11 @@ Detector.prototype._validate_naming_style = function (name, styles, name_type) {
513
897
  }
514
898
  }
515
899
 
516
- var style_names = styles.join('');
900
+ var style_names = styles.join("");
517
901
 
518
- var name_type_desc = this.config.name_type_map[name_type] || '名称';
902
+ var name_type_desc = this.config.name_type_map[name_type] || "名称";
519
903
 
520
- return name_type_desc + '\'' + name + '\'不符合' + style_names + '命名风格';
904
+ return name_type_desc + "'" + name + "'不符合" + style_names + "命名风格";
521
905
  };
522
906
 
523
907
  /**
@@ -529,17 +913,17 @@ Detector.prototype._validate_naming_style = function (name, styles, name_type) {
529
913
  */
530
914
  Detector.prototype._checkNameLength = function (name, min, max, name_type) {
531
915
  if (!name) {
532
- return '名称不能为空';
916
+ return "名称不能为空";
533
917
  }
534
918
 
535
- var name_type_desc = this.config.name_type_map[name_type] || '名称';
919
+ var name_type_desc = this.config.name_type_map[name_type] || "名称";
536
920
  var len = name.length;
537
921
  if (len < min) {
538
- return name_type_desc + '\'' + name + '\'长度过短,最小长度为' + min + '字符';
922
+ return name_type_desc + "'" + name + "'长度过短,最小长度为" + min + "字符";
539
923
  }
540
924
 
541
925
  if (len > max) {
542
- return name_type_desc + '\'' + name + '\'长度过长,最大长度为' + max + '字符';
926
+ return name_type_desc + "'" + name + "'长度过长,最大长度为" + max + "字符";
543
927
  }
544
928
 
545
929
  return null;
@@ -556,13 +940,13 @@ Detector.prototype._checkWordLength = function (name, max_word_len, name_type) {
556
940
  return null;
557
941
  }
558
942
 
559
- var name_type_desc = this.config.name_type_map[name_type] || '名称';
560
-
943
+ var name_type_desc = this.config.name_type_map[name_type] || "名称";
944
+
561
945
  // 处理私有标识符(开头的下划线)
562
946
  var processed_name = name;
563
947
  var has_private_prefix = false;
564
948
 
565
- if (name.startsWith('_')) {
949
+ if (name.startsWith("_")) {
566
950
  has_private_prefix = true;
567
951
  processed_name = name.substring(1); // 去掉开头的下划线
568
952
  }
@@ -570,10 +954,10 @@ Detector.prototype._checkWordLength = function (name, max_word_len, name_type) {
570
954
  // 分割单词(根据命名风格)
571
955
  var words = [];
572
956
 
573
- if (processed_name.includes('_')) {
574
- words = processed_name.split('_');
575
- } else if (processed_name.includes('-')) {
576
- words = processed_name.split('-');
957
+ if (processed_name.includes("_")) {
958
+ words = processed_name.split("_");
959
+ } else if (processed_name.includes("-")) {
960
+ words = processed_name.split("-");
577
961
  } else {
578
962
  // 驼峰命名法分割(保持原词大小写)
579
963
  words = processed_name.split(/(?=[A-Z])/);
@@ -581,11 +965,11 @@ Detector.prototype._checkWordLength = function (name, max_word_len, name_type) {
581
965
 
582
966
  // 如果存在私有标识符,添加空字符串表示私有标识符(不检查长度)
583
967
  if (has_private_prefix) {
584
- words.unshift('_');
968
+ words.unshift("_");
585
969
  }
586
970
 
587
971
  // 过滤空字符串
588
- words = words.filter(function(word) {
972
+ words = words.filter(function (word) {
589
973
  return word && word.length > 0;
590
974
  });
591
975
 
@@ -597,27 +981,27 @@ Detector.prototype._checkWordLength = function (name, max_word_len, name_type) {
597
981
  for (var i = 0; i < words.length; i++) {
598
982
  var word = words[i];
599
983
  // 跳过空字符串和私有标识符(单个下划线)
600
- if (!word || word === '_') {
984
+ if (!word || word === "_") {
601
985
  continue;
602
986
  }
603
987
 
604
988
  if (word.length > max_word_len) {
605
- // 生成推荐命名
606
- var recommended_name = this._generateRecommendedName(name, word, name_type);
607
- var recommendation_text = '';
608
- if (recommended_name) {
609
- recommendation_text = ',推荐名为\'' + recommended_name + '\'';
989
+ // 使用智能缩写生成推荐名称
990
+ var smart_abbreviation = this._getSmartAbbreviation(name, name_type);
991
+ var recommendation_text = "";
992
+ if (smart_abbreviation && smart_abbreviation !== name) {
993
+ recommendation_text = ",建议使用: " + smart_abbreviation;
610
994
  }
611
-
995
+
612
996
  return (
613
997
  name_type_desc +
614
- '\'' +
998
+ "'" +
615
999
  name +
616
- '\'中的单词\'' +
1000
+ "'中的单词'" +
617
1001
  word +
618
- '\'过长,最大长度为' +
1002
+ "'过长,最大长度为" +
619
1003
  max_word_len +
620
- '字符' +
1004
+ "字符" +
621
1005
  recommendation_text
622
1006
  );
623
1007
  }
@@ -642,9 +1026,18 @@ Detector.prototype._checkForbiddenWords = function (name, name_type) {
642
1026
  return null;
643
1027
  }
644
1028
 
645
- var name_type_desc = this.config.name_type_map[name_type] || '名称';
1029
+ var name_type_desc = this.config.name_type_map[name_type] || "名称";
646
1030
  var name_lower = name.toLowerCase();
647
1031
 
1032
+ // 对于私有变量/方法(以_开头),如果是单个单词(移除_后没有其他分隔符),则跳过禁止词汇检查
1033
+ if (name_lower.startsWith("_") && name.length > 2) {
1034
+ // 移除前缀_后检查是否包含分隔符
1035
+ var name_without_prefix = name.substring(1);
1036
+ if (!name_without_prefix.includes("_") && !name_without_prefix.includes("-") && !/[A-Z]/.test(name_without_prefix)) {
1037
+ return null; // 单个单词的私有变量,跳过检查
1038
+ }
1039
+ }
1040
+
648
1041
  // 如果名称本身就是禁止词汇(即单个单词),则允许使用
649
1042
  for (var i = 0; i < forbidden_words.length; i++) {
650
1043
  var forbidden_word = forbidden_words[i].toLowerCase();
@@ -653,25 +1046,55 @@ Detector.prototype._checkForbiddenWords = function (name, name_type) {
653
1046
  }
654
1047
  }
655
1048
 
656
- // 按单词边界分割名称
657
- var words = this._splitNameIntoWords(name_lower);
1049
+ // 按单词边界分割名称(使用原始名称进行拆分,保持大小写信息)
1050
+ var words = this._splitNameIntoWords(name);
658
1051
 
1052
+ // 将拆分后的单词转换为小写进行比较
1053
+ var words_lower = words.map(function(word) {
1054
+ return word.toLowerCase();
1055
+ });
1056
+
659
1057
  // 检查每个单词是否在禁止词汇列表中
660
- for (var i = 0; i < words.length; i++) {
661
- var word = words[i];
1058
+ var found_forbidden_words = [];
1059
+
1060
+ // 对于私有变量(以_开头),跳过第一个单词(即_)
1061
+ var start_index = name_lower.startsWith("_") ? 1 : 0;
1062
+
1063
+ for (var i = start_index; i < words_lower.length; i++) {
1064
+ var word = words_lower[i];
662
1065
  // 跳过空字符串和单个字符
663
1066
  if (!word || word.length <= 1) {
664
1067
  continue;
665
1068
  }
666
-
1069
+
667
1070
  for (var j = 0; j < forbidden_words.length; j++) {
668
1071
  var forbidden_word = forbidden_words[j].toLowerCase();
669
1072
  if (word === forbidden_word) {
670
- return name_type_desc + '\'' + name + '\'包含禁止拼接词\'' + forbidden_word + '\'';
1073
+ // 记录找到的禁用词,但不立即返回
1074
+ if (found_forbidden_words.indexOf(forbidden_word) === -1) {
1075
+ found_forbidden_words.push(forbidden_word);
1076
+ }
671
1077
  }
672
1078
  }
673
1079
  }
674
1080
 
1081
+ // 如果有找到禁用词,返回错误信息
1082
+ if (found_forbidden_words.length > 0) {
1083
+ var error_message = name_type_desc + "'" + name + "'包含禁止拼接词";
1084
+
1085
+ if (found_forbidden_words.length === 1) {
1086
+ error_message += "'" + found_forbidden_words[0] + "'";
1087
+ } else {
1088
+ // 多个禁用词,按优先级排序(长的优先)
1089
+ found_forbidden_words.sort(function(a, b) {
1090
+ return b.length - a.length; // 长的优先
1091
+ });
1092
+ error_message += ":" + found_forbidden_words.join(", ");
1093
+ }
1094
+
1095
+ return error_message;
1096
+ }
1097
+
675
1098
  return null;
676
1099
  };
677
1100
 
@@ -684,22 +1107,27 @@ Detector.prototype._splitNameIntoWords = function (name) {
684
1107
  if (!name) {
685
1108
  return [];
686
1109
  }
687
-
1110
+
688
1111
  var words = [];
689
1112
  var processed_name = name;
690
1113
  var has_private_prefix = false;
691
1114
 
692
1115
  // 处理私有标识符(开头的下划线)
693
- if (name.startsWith('_')) {
1116
+ if (name.startsWith("_")) {
694
1117
  has_private_prefix = true;
695
1118
  processed_name = name.substring(1); // 去掉开头的下划线
696
1119
  }
697
1120
 
1121
+ // 如果移除_后为空,说明只有_,直接返回
1122
+ if (!processed_name) {
1123
+ return ["_"];
1124
+ }
1125
+
698
1126
  // 根据命名风格分割单词
699
- if (processed_name.includes('_')) {
700
- words = processed_name.split('_');
701
- } else if (processed_name.includes('-')) {
702
- words = processed_name.split('-');
1127
+ if (processed_name.includes("_")) {
1128
+ words = processed_name.split("_");
1129
+ } else if (processed_name.includes("-")) {
1130
+ words = processed_name.split("-");
703
1131
  } else {
704
1132
  // 驼峰命名法分割(保持原词大小写)
705
1133
  words = processed_name.split(/(?=[A-Z])/);
@@ -707,11 +1135,11 @@ Detector.prototype._splitNameIntoWords = function (name) {
707
1135
 
708
1136
  // 如果存在私有标识符,添加下划线作为第一个单词
709
1137
  if (has_private_prefix) {
710
- words.unshift('_');
1138
+ words.unshift("_");
711
1139
  }
712
1140
 
713
1141
  // 过滤空字符串
714
- words = words.filter(function(word) {
1142
+ words = words.filter(function (word) {
715
1143
  return word && word.length > 0;
716
1144
  });
717
1145
 
@@ -728,34 +1156,35 @@ Detector.prototype._isThirdPartyConfigProperty = function (node, parent_node) {
728
1156
  try {
729
1157
  // 处理新的父节点信息结构(包含node和parent属性)
730
1158
  var actual_parent_node = parent_node;
731
- if (parent_node && typeof parent_node === 'object' && parent_node.node) {
1159
+ if (parent_node && typeof parent_node === "object" && parent_node.node) {
732
1160
  actual_parent_node = parent_node.node;
733
1161
  }
734
-
1162
+
735
1163
  // 检查当前节点是否为对象字面量的属性
736
- if (!actual_parent_node || actual_parent_node.type !== 'ObjectExpression') {
1164
+ if (!actual_parent_node || actual_parent_node.type !== "ObjectExpression") {
737
1165
  return false;
738
1166
  }
739
1167
 
740
1168
  // 递归查找调用表达式(处理嵌套对象的情况)
741
- var findCallExpression = function(current_node) {
1169
+ var findCallExpression = function (current_node) {
742
1170
  if (!current_node) {
743
1171
  return null;
744
1172
  }
745
-
746
- if (current_node.type === 'CallExpression') {
1173
+
1174
+ if (current_node.type === "CallExpression") {
747
1175
  return current_node;
748
1176
  }
749
-
1177
+
750
1178
  // 继续向上查找
751
1179
  return findCallExpression(current_node.parent);
752
1180
  };
753
1181
 
754
1182
  // 优先使用新的父节点信息结构中的parent属性
755
- var grandparent = parent_node && typeof parent_node === 'object' && parent_node.parent
756
- ? parent_node.parent
757
- : actual_parent_node.parent;
758
-
1183
+ var grandparent =
1184
+ parent_node && typeof parent_node === "object" && parent_node.parent
1185
+ ? parent_node.parent
1186
+ : actual_parent_node.parent;
1187
+
759
1188
  // 查找调用表达式
760
1189
  var call_expression = findCallExpression(grandparent);
761
1190
  if (!call_expression) {
@@ -769,43 +1198,57 @@ Detector.prototype._isThirdPartyConfigProperty = function (node, parent_node) {
769
1198
  }
770
1199
 
771
1200
  // 如果是成员表达式(如 chokidar.watch),则认为是第三方库调用
772
- if (callee.type === 'MemberExpression') {
1201
+ if (callee.type === "MemberExpression") {
773
1202
  // 检查成员表达式的对象是否为模块导入变量
774
1203
  var is_module_import = this._isModuleImportVariable(callee.object);
775
1204
  if (is_module_import) {
776
1205
  return true;
777
1206
  }
778
-
1207
+
779
1208
  // 对于其他成员表达式,也认为是第三方库调用(保守策略)
780
1209
  return true;
781
1210
  }
782
1211
 
783
1212
  // 如果是标识符,检查是否是常见的第三方库函数名
784
- if (callee.type === 'Identifier') {
1213
+ if (callee.type === "Identifier") {
785
1214
  var common_third_party_functions = [
786
- 'watch', 'require', 'import', 'create', 'build', 'compile',
787
- 'parse', 'stringify', 'readFile', 'writeFile', 'mkdir',
788
- 'exec', 'spawn', 'fork', 'connect', 'listen', 'send'
1215
+ "watch",
1216
+ "require",
1217
+ "import",
1218
+ "create",
1219
+ "build",
1220
+ "compile",
1221
+ "parse",
1222
+ "stringify",
1223
+ "readFile",
1224
+ "writeFile",
1225
+ "mkdir",
1226
+ "exec",
1227
+ "spawn",
1228
+ "fork",
1229
+ "connect",
1230
+ "listen",
1231
+ "send",
789
1232
  ];
790
-
1233
+
791
1234
  // 如果是常见的第三方库函数名,则认为是第三方库调用
792
1235
  if (common_third_party_functions.includes(callee.name)) {
793
1236
  return true;
794
1237
  }
795
-
1238
+
796
1239
  // 检查标识符是否为模块导入变量
797
1240
  var is_module_import = this._isModuleImportVariable(callee);
798
1241
  if (is_module_import) {
799
1242
  return true;
800
1243
  }
801
-
1244
+
802
1245
  // 对于其他标识符,暂时不认为是第三方库调用(避免误判)
803
1246
  return false;
804
1247
  }
805
1248
 
806
1249
  return false;
807
1250
  } catch (error) {
808
- console.error('检查第三方库配置参数时出错:', error);
1251
+ console.error("检查第三方库配置参数时出错:", error);
809
1252
  return false;
810
1253
  }
811
1254
  };
@@ -819,59 +1262,125 @@ Detector.prototype._isThirdPartyConfigProperty = function (node, parent_node) {
819
1262
  */
820
1263
  Detector.prototype._getPropType = function (val_node, prop_name, parent_node) {
821
1264
  if (!val_node) {
822
- return 'undefined_value'; // 未赋值类型
1265
+ return "undefined_value"; // 未赋值类型
823
1266
  }
824
1267
 
825
1268
  // 检查是否为null值
826
- if (val_node.type === 'NullLiteral') {
827
- return 'null_value'; // null值类型
1269
+ if (val_node.type === "NullLiteral") {
1270
+ return "null_value"; // null值类型
828
1271
  }
829
1272
 
830
1273
  // 检查是否为对象方法(在对象字面量中的函数)
831
1274
  if (
832
1275
  val_node &&
833
- (val_node.type === 'FunctionExpression' ||
834
- val_node.type === 'ArrowFunctionExpression')
1276
+ (val_node.type === "FunctionExpression" ||
1277
+ val_node.type === "ArrowFunctionExpression")
835
1278
  ) {
836
- return 'method'; // 对象方法类型
1279
+ return "method"; // 对象方法类型
837
1280
  }
838
1281
 
839
1282
  // 检查是否为类引用(属性类)
840
1283
  if (
841
- val_node.type === 'Identifier' &&
1284
+ val_node.type === "Identifier" &&
842
1285
  val_node.name &&
843
1286
  val_node.name[0] === val_node.name[0].toUpperCase()
844
1287
  ) {
845
1288
  // 检查是否是特殊全局变量(如__dirname、__filename、process等)
846
- var special_globals = ['__dirname', '__filename', 'process', 'console', 'module', 'exports', 'require', 'global'];
1289
+ var special_globals = [
1290
+ "__dirname",
1291
+ "__filename",
1292
+ "process",
1293
+ "console",
1294
+ "module",
1295
+ "exports",
1296
+ "require",
1297
+ "global",
1298
+ ];
847
1299
  if (special_globals.includes(val_node.name)) {
848
- return 'value'; // 特殊全局变量应该识别为属性值
1300
+ return "value"; // 特殊全局变量应该识别为属性值
849
1301
  }
850
-
1302
+
851
1303
  // 检查是否是类名引用(通常类名使用PascalCase)
852
- return 'class'; // 属性类类型
1304
+ return "class"; // 属性类类型
853
1305
  }
854
1306
 
855
1307
  // 检查是否为类实例(new表达式)
856
- if (val_node.type === 'NewExpression') {
857
- return 'instance_class'; // 属性实例类类型
1308
+ if (val_node.type === "NewExpression") {
1309
+ return "instance_class"; // 属性实例类类型
858
1310
  }
859
1311
 
860
1312
  // 检查是否为函数调用(可能返回实例)
861
- if (val_node.type === 'CallExpression') {
1313
+ if (val_node.type === "CallExpression") {
862
1314
  // 检查是否调用的是构造函数
863
1315
  if (
864
1316
  val_node.callee &&
865
- val_node.callee.type === 'Identifier' &&
1317
+ val_node.callee.type === "Identifier" &&
866
1318
  val_node.callee.name &&
867
1319
  val_node.callee.name[0] === val_node.callee.name[0].toUpperCase()
868
1320
  ) {
869
- return 'instance_class'; // 属性实例类类型
1321
+ return "instance_class"; // 属性实例类类型
1322
+ }
1323
+
1324
+ // 检查是否是工厂方法(返回实例)
1325
+ var factory_methods = ["create", "make", "build", "get", "fetch"];
1326
+ if (
1327
+ val_node.callee &&
1328
+ val_node.callee.type === "Identifier" &&
1329
+ factory_methods.some(function (method) {
1330
+ return val_node.callee.name.toLowerCase().startsWith(method);
1331
+ })
1332
+ ) {
1333
+ return "instance_class"; // 工厂方法返回的实例
870
1334
  }
871
- return 'value'; // 默认值类型
1335
+
1336
+ return "value"; // 默认值类型
1337
+ }
1338
+
1339
+ // 检查是否为数组(包含对象实例)
1340
+ if (val_node.type === "ArrayExpression") {
1341
+ // 检查数组元素是否包含类实例
1342
+ if (val_node.elements && val_node.elements.length > 0) {
1343
+ var has_instance = val_node.elements.some(function (element) {
1344
+ return element && element.type === "NewExpression";
1345
+ });
1346
+ if (has_instance) {
1347
+ return "instance_class"; // 包含实例的数组
1348
+ }
1349
+ }
1350
+ return "value"; // 普通数组
1351
+ }
1352
+
1353
+ // 检查是否为对象字面量(可能包含类实例)
1354
+ if (val_node.type === "ObjectExpression") {
1355
+ // 检查对象属性是否包含类实例
1356
+ if (val_node.properties && val_node.properties.length > 0) {
1357
+ var has_instance = val_node.properties.some(function (property) {
1358
+ return (
1359
+ property && property.value && property.value.type === "NewExpression"
1360
+ );
1361
+ });
1362
+ if (has_instance) {
1363
+ return "instance_class"; // 包含实例的对象
1364
+ }
1365
+ }
1366
+ return "value"; // 普通对象
1367
+ }
1368
+
1369
+ // 检查是否为模板字面量(包含类实例)
1370
+ if (val_node.type === "TemplateLiteral") {
1371
+ // 检查模板表达式是否包含类实例
1372
+ if (val_node.expressions && val_node.expressions.length > 0) {
1373
+ var has_instance = val_node.expressions.some(function (expression) {
1374
+ return expression && expression.type === "NewExpression";
1375
+ });
1376
+ if (has_instance) {
1377
+ return "instance_class"; // 包含实例的模板
1378
+ }
1379
+ }
1380
+ return "value"; // 普通模板
872
1381
  }
873
1382
 
874
- return 'value';
1383
+ return "value";
875
1384
  };
876
1385
 
877
1386
  /**
@@ -890,131 +1399,199 @@ Detector.prototype._checkPropertyName = function (
890
1399
  ) {
891
1400
  try {
892
1401
  // 检查是否为解构导入中的属性
893
- var is_destructured_import = this._isDestructuredImportProperty(node, parent_node);
894
-
1402
+ var is_destructured_import = this._isDestructuredImportProperty(
1403
+ node,
1404
+ parent_node,
1405
+ );
1406
+
895
1407
  // 如果是解构导入中的属性,则不进行属性名检测
896
1408
  if (is_destructured_import) {
897
1409
  return null;
898
1410
  }
899
1411
 
900
1412
  // 检查是否为第三方库的配置参数(方法调用中的对象字面量属性)
901
- var is_third_party_config = this._isThirdPartyConfigProperty(node, parent_node);
902
-
1413
+ var is_third_party_config = this._isThirdPartyConfigProperty(
1414
+ node,
1415
+ parent_node,
1416
+ );
1417
+
903
1418
  // 如果是第三方库的配置参数,则不进行属性名检测
904
1419
  if (is_third_party_config) {
905
1420
  return null;
906
1421
  }
907
1422
 
1423
+ // 检查是否为 module.exports 中的属性
1424
+ var is_module_exports = this._isModuleExportsProperty(node, parent_node);
1425
+
1426
+ // 如果是 module.exports 中的属性,则不进行属性名检测
1427
+ if (is_module_exports) {
1428
+ return null;
1429
+ }
1430
+
908
1431
  // 获取属性类型
909
1432
  var prop_type = this._getPropType(val_node, prop_name, parent_node);
910
- var rule_type = '';
1433
+ var rule_type = "";
911
1434
 
912
1435
  // 根据属性类型选择对应的规则
913
1436
  // 对于null值和未赋值属性,直接跳过命名规范检测
914
- if (prop_type === 'null_value' || prop_type === 'undefined_value') {
1437
+ if (prop_type === "null_value" || prop_type === "undefined_value") {
915
1438
  return null; // 不进行命名规范检测
916
1439
  }
917
1440
 
918
1441
  switch (prop_type) {
919
- case 'class':
920
- rule_type = 'property-class-name';
1442
+ case "class":
1443
+ rule_type = "property-class-name";
921
1444
  break;
922
- case 'instance_class':
923
- rule_type = 'property-instance-class-name';
1445
+ case "instance_class":
1446
+ rule_type = "property-instance-class-name";
924
1447
  break;
925
- case 'method':
926
- rule_type = 'property-method-name';
1448
+ case "method":
1449
+ rule_type = "property-method-name";
927
1450
  break;
928
- case 'value':
1451
+ case "value":
929
1452
  default:
930
- rule_type = 'property-value-name';
1453
+ rule_type = "property-value-name";
931
1454
  break;
932
1455
  }
933
1456
 
1457
+ // 将属性规则类型映射到对应的基础规则类型
1458
+ var base_rule_type = rule_type;
1459
+ if (rule_type.startsWith('property-')) {
1460
+ // 属性类名 -> 类名
1461
+ if (rule_type === 'property-class-name') {
1462
+ base_rule_type = 'class-name';
1463
+ }
1464
+ // 属性实例类名 -> 变量名
1465
+ else if (rule_type === 'property-instance-class-name') {
1466
+ base_rule_type = 'variable-name';
1467
+ }
1468
+ // 属性方法名 -> 方法名
1469
+ else if (rule_type === 'property-method-name') {
1470
+ base_rule_type = 'method-name';
1471
+ }
1472
+ // 属性值名 -> 变量名
1473
+ else if (rule_type === 'property-value-name') {
1474
+ base_rule_type = 'variable-name';
1475
+ }
1476
+ }
1477
+
934
1478
  // 检查忽略词
935
- var ignored_words = this.config.getIgnoredWords(rule_type);
1479
+ var ignored_words = this.config.getIgnoredWords(base_rule_type);
936
1480
  if (ignored_words && ignored_words.includes(prop_name)) {
937
1481
  return null; // 忽略词不进行命名规范检测
938
1482
  }
939
1483
 
940
- var rule = this.config.getRule(rule_type);
1484
+ var rule = this.config.getRule(base_rule_type);
941
1485
  if (!rule) {
942
1486
  return null;
943
1487
  }
944
1488
 
945
- // 检查命名风格
1489
+ // 首先检查命名风格
946
1490
  var style_err = null;
947
-
948
- if (rule_type === 'property-value-name') {
949
- // 对于属性值名,支持私有变量命名规范(_snake_case)、变量命名规范(snake_case)或常量命名规范(UPPER_SNAKE_CASE)
950
- var private_style_err = this._validate_naming_style(prop_name, ['_snake_case'], rule_type);
951
- var variable_style_err = this._validate_naming_style(prop_name, ['snake_case'], rule_type);
952
- var constant_style_err = this._validate_naming_style(prop_name, ['UPPER_SNAKE_CASE'], rule_type);
953
-
954
- // 只有当所有风格检查都失败时才报错
955
- if (private_style_err && variable_style_err && constant_style_err) {
956
- style_err = '属性值名\'' + prop_name + '\'不符合_snake_case、snake_case或UPPER_SNAKE_CASE命名风格';
957
- }
958
- } else if (rule_type === 'property-method-name') {
959
- // 属性方法:支持公开方法(camelCase)和私有方法(_camelCase)
960
- if (prop_name.startsWith('_')) {
961
- // 私有方法:检查是否符合私有方法命名规范
962
- style_err = this._validate_naming_style(prop_name, ['_camelCase'], rule_type);
963
- } else {
964
- // 公开方法:检查是否符合公开方法命名规范
965
- style_err = this._validate_naming_style(prop_name, rule.styles, rule_type);
966
- }
967
- } else if (rule_type === 'property-instance-class-name') {
968
- // 属性实例类:支持公开实例类(camelCase)和私有实例类(_camelCase)
969
- if (prop_name.startsWith('_')) {
970
- // 私有实例类:检查是否符合私有实例类命名规范
971
- style_err = this._validate_naming_style(prop_name, ['_camelCase'], rule_type);
972
- } else {
973
- // 公开实例类:检查是否符合公开实例类命名规范
974
- style_err = this._validate_naming_style(prop_name, rule.styles, rule_type);
975
- }
1491
+
1492
+ if (rule_type === "property-value-name") {
1493
+ // 对于属性值名,智能识别属性值类型并应用相应的命名规范
1494
+ style_err = this._checkPropertyValueStyle(prop_name, val_node, rule_type);
1495
+ } else if (rule_type === "property-method-name") {
1496
+ // 属性方法:智能识别方法类型并提供准确的命名规范
1497
+ style_err = this._checkPropertyMethodStyle(
1498
+ prop_name,
1499
+ val_node,
1500
+ rule_type,
1501
+ );
1502
+ } else if (rule_type === "property-instance-class-name") {
1503
+ // 属性实例类:智能识别实例类并提供准确的命名规范
1504
+ style_err = this._checkPropertyInstanceClassStyle(
1505
+ prop_name,
1506
+ val_node,
1507
+ rule_type,
1508
+ );
1509
+ } else if (rule_type === "property-class-name") {
1510
+ // 属性类:智能识别类引用并提供准确的命名规范
1511
+ style_err = this._checkPropertyClassStyle(prop_name, val_node, rule_type);
976
1512
  } else {
977
1513
  // 其他属性类型:使用原有逻辑
978
- style_err = this._validate_naming_style(prop_name, rule.styles, rule_type);
1514
+ style_err = this._validate_naming_style(
1515
+ prop_name,
1516
+ rule.styles,
1517
+ rule_type,
1518
+ );
979
1519
  }
980
1520
 
981
1521
  if (style_err) {
982
1522
  return {
983
1523
  node: node,
984
1524
  message: style_err,
1525
+ rule_type: rule_type, // 添加规则类型信息
985
1526
  };
986
1527
  }
987
1528
 
988
1529
  // 检查长度
989
- var len_err = this._checkNameLength(prop_name, rule.min, rule.max, rule_type);
1530
+ var len_err = this._checkNameLength(
1531
+ prop_name,
1532
+ rule.min,
1533
+ rule.max,
1534
+ rule_type,
1535
+ );
990
1536
  if (len_err) {
1537
+ // 使用智能缩写生成推荐名称
1538
+ var smart_abbreviation = this._getSmartAbbreviation(prop_name, rule_type);
1539
+ var error_message = len_err;
1540
+ if (smart_abbreviation && smart_abbreviation !== prop_name) {
1541
+ error_message = len_err + ",建议使用: " + smart_abbreviation;
1542
+ }
1543
+
991
1544
  return {
992
1545
  node: node,
993
- message: len_err,
1546
+ message: error_message,
1547
+ rule_type: rule_type, // 添加规则类型信息
994
1548
  };
995
1549
  }
996
1550
 
997
1551
  // 检查单词长度
998
- var word_err = this._checkWordLength(prop_name, rule.single_word_len, rule_type);
999
- if (word_err) {
1000
- return {
1001
- node: node,
1002
- message: word_err,
1003
- };
1552
+ // 对于私有属性值名(以_开头且长度>2),跳过单词长度检查,视为单个单词
1553
+ var is_private_property = prop_name.startsWith("_");
1554
+ if (!(is_private_property && prop_name.length > 2)) {
1555
+ var word_err = this._checkWordLength(
1556
+ prop_name,
1557
+ rule.single_word_len,
1558
+ rule_type,
1559
+ );
1560
+ if (word_err) {
1561
+ // 检查错误消息是否已经包含建议
1562
+ var error_message = word_err;
1563
+ if (!word_err.includes("建议使用")) {
1564
+ // 如果错误消息中不包含建议,则添加建议
1565
+ var smart_abbreviation = this._getSmartAbbreviation(
1566
+ prop_name,
1567
+ rule_type,
1568
+ );
1569
+ if (smart_abbreviation && smart_abbreviation !== prop_name) {
1570
+ error_message = word_err + ",建议使用: " + smart_abbreviation;
1571
+ }
1572
+ }
1573
+
1574
+ return {
1575
+ node: node,
1576
+ message: error_message,
1577
+ rule_type: rule_type, // 添加规则类型信息
1578
+ };
1579
+ }
1004
1580
  }
1005
1581
 
1006
1582
  // 检查禁止词汇
1007
- var forbid_err = this._checkForbiddenWords(prop_name, rule_type);
1583
+ var forbid_err = this._checkForbiddenWords(prop_name, base_rule_type);
1008
1584
  if (forbid_err) {
1009
1585
  return {
1010
1586
  node: node,
1011
1587
  message: forbid_err,
1588
+ rule_type: rule_type, // 添加规则类型信息
1012
1589
  };
1013
1590
  }
1014
1591
 
1015
1592
  return null;
1016
1593
  } catch (error) {
1017
- console.error('检测属性名时出错:', error);
1594
+ console.error("检测属性名时出错:", error);
1018
1595
  return null;
1019
1596
  }
1020
1597
  };
@@ -1033,8 +1610,10 @@ Detector.prototype._checkAndRecommend = function (name, name_type) {
1033
1610
  }
1034
1611
 
1035
1612
  var name_lower = name.toLowerCase();
1613
+ var is_private = name.startsWith("_");
1614
+ var name_without_prefix = is_private ? name.substring(1) : name;
1615
+ var name_without_prefix_lower = name_without_prefix.toLowerCase();
1036
1616
 
1037
- var name_type_desc = this.config.name_type_map[name_type] || '名称';
1038
1617
  // 检查每个推荐词映射
1039
1618
  for (var rec_word in rec_words) {
1040
1619
  if (rec_words.hasOwnProperty(rec_word)) {
@@ -1043,8 +1622,32 @@ Detector.prototype._checkAndRecommend = function (name, name_type) {
1043
1622
  // 检查名称是否包含任何一个原词
1044
1623
  for (var i = 0; i < original_words.length; i++) {
1045
1624
  var original_word = original_words[i].toLowerCase();
1046
- if (name_lower.includes(original_word)) {
1047
- return name_type_desc + '建议使用\'' + rec_word + '\'替代\'' + original_words[i] + '\'以获得更短的命名';
1625
+
1626
+ // 检查名称(去除私有前缀后)是否包含原词
1627
+ if (name_without_prefix_lower.includes(original_word)) {
1628
+ // 使用智能缩写生成完整的推荐名称
1629
+ var smart_abbreviation = this._getSmartAbbreviation(
1630
+ name,
1631
+ name_type,
1632
+ );
1633
+ var recommended_name =
1634
+ smart_abbreviation && smart_abbreviation !== name
1635
+ ? smart_abbreviation
1636
+ : name;
1637
+
1638
+ return {
1639
+ type: "recommendation",
1640
+ message:
1641
+ "建议使用'" +
1642
+ recommended_name +
1643
+ "'替代'" +
1644
+ name +
1645
+ "'以获得更简洁的命名",
1646
+ recommended_name: recommended_name,
1647
+ original_name: name,
1648
+ original_word: original_words[i],
1649
+ recommended_word: rec_word,
1650
+ };
1048
1651
  }
1049
1652
  }
1050
1653
  }
@@ -1052,7 +1655,7 @@ Detector.prototype._checkAndRecommend = function (name, name_type) {
1052
1655
 
1053
1656
  return null;
1054
1657
  } catch (error) {
1055
- console.error('检查并推荐更合适的词汇时出错:', error);
1658
+ console.error("检查并推荐更合适的词汇时出错:", error);
1056
1659
  return null;
1057
1660
  }
1058
1661
  };
@@ -1072,17 +1675,17 @@ Detector.prototype._isBaseValue = function (val_node) {
1072
1675
  var is_base_value = false;
1073
1676
 
1074
1677
  switch (val_node.type) {
1075
- case 'Literal': // 字面量:数字、字符串、布尔值
1678
+ case "Literal": // 字面量:数字、字符串、布尔值
1076
1679
  is_base_value = true;
1077
1680
  break;
1078
- case 'ArrayExpression': // 数组字面量
1681
+ case "ArrayExpression": // 数组字面量
1079
1682
  is_base_value = true;
1080
1683
  break;
1081
- case 'ObjectExpression': // 对象字面量
1684
+ case "ObjectExpression": // 对象字面量
1082
1685
  is_base_value = true;
1083
1686
  break;
1084
- case 'UnaryExpression': // 一元表达式(如 -1, +100)
1085
- if (val_node.operator === '-' || val_node.operator === '+') {
1687
+ case "UnaryExpression": // 一元表达式(如 -1, +100)
1688
+ if (val_node.operator === "-" || val_node.operator === "+") {
1086
1689
  is_base_value = true;
1087
1690
  }
1088
1691
  break;
@@ -1092,7 +1695,7 @@ Detector.prototype._isBaseValue = function (val_node) {
1092
1695
 
1093
1696
  return is_base_value;
1094
1697
  } catch (error) {
1095
- console.error('检查值是否为基础值类型时出错:', error);
1698
+ console.error("检查值是否为基础值类型时出错:", error);
1096
1699
  return false;
1097
1700
  }
1098
1701
  };
@@ -1117,9 +1720,13 @@ Detector.prototype._shouldUseLetInsteadOfConst = function (node, val_node) {
1117
1720
 
1118
1721
  // 检查是否为解构赋值
1119
1722
  var is_destructuring = false;
1120
- if (node.parent && node.parent.type === 'VariableDeclarator') {
1723
+ if (node.parent && node.parent.type === "VariableDeclarator") {
1121
1724
  var declarator = node.parent;
1122
- if (declarator.id && (declarator.id.type === 'ObjectPattern' || declarator.id.type === 'ArrayPattern')) {
1725
+ if (
1726
+ declarator.id &&
1727
+ (declarator.id.type === "ObjectPattern" ||
1728
+ declarator.id.type === "ArrayPattern")
1729
+ ) {
1123
1730
  is_destructuring = true;
1124
1731
  }
1125
1732
  }
@@ -1128,28 +1735,28 @@ Detector.prototype._shouldUseLetInsteadOfConst = function (node, val_node) {
1128
1735
  // 1. 函数调用(CallExpression)- 返回值可能变化
1129
1736
  // 2. 变量引用(Identifier)- 可能被重新赋值
1130
1737
  // 3. 条件表达式等可能产生不同结果的情况
1131
-
1738
+
1132
1739
  var should_use_let = false;
1133
-
1740
+
1134
1741
  // 检查是否为函数调用
1135
- if (val_node.type === 'CallExpression') {
1742
+ if (val_node.type === "CallExpression") {
1136
1743
  should_use_let = true;
1137
1744
  }
1138
-
1745
+
1139
1746
  // 检查是否为变量引用
1140
- if (val_node.type === 'Identifier') {
1747
+ if (val_node.type === "Identifier") {
1141
1748
  should_use_let = true;
1142
1749
  }
1143
-
1750
+
1144
1751
  // 检查是否为解构赋值且右侧是复杂类型
1145
1752
  var is_complex_type = this._isComplexType(val_node);
1146
1753
  if (is_destructuring && is_complex_type) {
1147
1754
  should_use_let = true;
1148
1755
  }
1149
-
1756
+
1150
1757
  return should_use_let;
1151
1758
  } catch (error) {
1152
- console.error('检查是否应该使用let时出错:', error);
1759
+ console.error("检查是否应该使用let时出错:", error);
1153
1760
  return false;
1154
1761
  }
1155
1762
  };
@@ -1169,15 +1776,15 @@ Detector.prototype._isComplexType = function (val_node) {
1169
1776
  var is_complex_type = false;
1170
1777
 
1171
1778
  switch (val_node.type) {
1172
- case 'FunctionExpression': // 函数表达式
1173
- case 'ArrowFunctionExpression': // 箭头函数
1174
- case 'NewExpression': // new 实例化
1175
- case 'CallExpression': // 函数调用
1176
- case 'MemberExpression': // 成员表达式
1177
- case 'Identifier': // 标识符(可能是变量或函数)
1178
- case 'ClassExpression': // 类表达式
1179
- case 'ThisExpression': // this表达式
1180
- case 'TemplateLiteral': // 模板字符串
1779
+ case "FunctionExpression": // 函数表达式
1780
+ case "ArrowFunctionExpression": // 箭头函数
1781
+ case "NewExpression": // new 实例化
1782
+ case "CallExpression": // 函数调用
1783
+ case "MemberExpression": // 成员表达式
1784
+ case "Identifier": // 标识符(可能是变量或函数)
1785
+ case "ClassExpression": // 类表达式
1786
+ case "ThisExpression": // this表达式
1787
+ case "TemplateLiteral": // 模板字符串
1181
1788
  is_complex_type = true;
1182
1789
  break;
1183
1790
  default:
@@ -1186,7 +1793,7 @@ Detector.prototype._isComplexType = function (val_node) {
1186
1793
 
1187
1794
  return is_complex_type;
1188
1795
  } catch (error) {
1189
- console.error('检查值是否为复杂类型时出错:', error);
1796
+ console.error("检查值是否为复杂类型时出错:", error);
1190
1797
  return false;
1191
1798
  }
1192
1799
  };
@@ -1204,27 +1811,33 @@ Detector.prototype._isModuleImport = function (node, val_node) {
1204
1811
  }
1205
1812
 
1206
1813
  // 情况1:const xxx = require('module') - 直接模块导入
1207
- if (val_node.type === 'CallExpression' && val_node.callee) {
1814
+ if (val_node.type === "CallExpression" && val_node.callee) {
1208
1815
  // 检查是否为require调用
1209
- if (val_node.callee.type === 'Identifier' && val_node.callee.name === 'require') {
1816
+ if (
1817
+ val_node.callee.type === "Identifier" &&
1818
+ val_node.callee.name === "require"
1819
+ ) {
1210
1820
  return true;
1211
1821
  }
1212
-
1822
+
1213
1823
  // 检查是否为import()动态导入
1214
- if (val_node.callee.type === 'Import') {
1824
+ if (val_node.callee.type === "Import") {
1215
1825
  return true;
1216
1826
  }
1217
1827
  }
1218
1828
 
1219
1829
  // 情况2:const {xxx} = require('module') - 解构模块导入
1220
- if (node.parent && node.parent.type === 'VariableDeclarator') {
1830
+ if (node.parent && node.parent.type === "VariableDeclarator") {
1221
1831
  var declarator = node.parent;
1222
-
1832
+
1223
1833
  // 检查是否为解构赋值
1224
- if (declarator.id && declarator.id.type === 'ObjectPattern') {
1834
+ if (declarator.id && declarator.id.type === "ObjectPattern") {
1225
1835
  // 检查右侧是否为require调用
1226
- if (val_node.type === 'CallExpression' && val_node.callee) {
1227
- if (val_node.callee.type === 'Identifier' && val_node.callee.name === 'require') {
1836
+ if (val_node.type === "CallExpression" && val_node.callee) {
1837
+ if (
1838
+ val_node.callee.type === "Identifier" &&
1839
+ val_node.callee.name === "require"
1840
+ ) {
1228
1841
  return true;
1229
1842
  }
1230
1843
  }
@@ -1233,7 +1846,7 @@ Detector.prototype._isModuleImport = function (node, val_node) {
1233
1846
 
1234
1847
  return false;
1235
1848
  } catch (error) {
1236
- console.error('检查是否为模块导入时出错:', error);
1849
+ console.error("检查是否为模块导入时出错:", error);
1237
1850
  return false;
1238
1851
  }
1239
1852
  };
@@ -1245,23 +1858,30 @@ Detector.prototype._isModuleImport = function (node, val_node) {
1245
1858
  */
1246
1859
  Detector.prototype._isModuleImportVariable = function (node) {
1247
1860
  try {
1248
- if (!node || node.type !== 'Identifier') {
1861
+ if (!node || node.type !== "Identifier") {
1249
1862
  return false;
1250
1863
  }
1251
1864
 
1252
1865
  // 检查变量声明是否为模块导入
1253
1866
  if (node.parent && node.parent.parent) {
1254
1867
  var variable_declaration = node.parent.parent;
1255
-
1868
+
1256
1869
  // 检查是否为const声明
1257
- if (variable_declaration.type === 'VariableDeclaration' && variable_declaration.kind === 'const') {
1870
+ if (
1871
+ variable_declaration.type === "VariableDeclaration" &&
1872
+ variable_declaration.kind === "const"
1873
+ ) {
1258
1874
  // 检查声明中是否有require调用
1259
1875
  var declarators = variable_declaration.declarations;
1260
1876
  for (var i = 0; i < declarators.length; i++) {
1261
1877
  var declarator = declarators[i];
1262
- if (declarator.init && declarator.init.type === 'CallExpression') {
1878
+ if (declarator.init && declarator.init.type === "CallExpression") {
1263
1879
  var init_call = declarator.init;
1264
- if (init_call.callee && init_call.callee.type === 'Identifier' && init_call.callee.name === 'require') {
1880
+ if (
1881
+ init_call.callee &&
1882
+ init_call.callee.type === "Identifier" &&
1883
+ init_call.callee.name === "require"
1884
+ ) {
1265
1885
  return true;
1266
1886
  }
1267
1887
  }
@@ -1271,7 +1891,7 @@ Detector.prototype._isModuleImportVariable = function (node) {
1271
1891
 
1272
1892
  return false;
1273
1893
  } catch (error) {
1274
- console.error('检查是否为模块导入变量时出错:', error);
1894
+ console.error("检查是否为模块导入变量时出错:", error);
1275
1895
  return false;
1276
1896
  }
1277
1897
  };
@@ -1291,56 +1911,63 @@ Detector.prototype._isDestructuredImport = function (node) {
1291
1911
  var is_destructured = false;
1292
1912
 
1293
1913
  // 情况1:节点是Property.key(解构赋值中的属性键)
1294
- if (node.parent.type === 'Property' && node.parent.key === node) {
1914
+ if (node.parent.type === "Property" && node.parent.key === node) {
1295
1915
  var property = node.parent;
1296
-
1916
+
1297
1917
  // 检查Property的父节点是否为ObjectPattern
1298
- if (property.parent && property.parent.type === 'ObjectPattern') {
1918
+ if (property.parent && property.parent.type === "ObjectPattern") {
1299
1919
  var object_pattern = property.parent;
1300
-
1920
+
1301
1921
  // 检查ObjectPattern的父节点是否为VariableDeclarator
1302
- if (object_pattern.parent && object_pattern.parent.type === 'VariableDeclarator') {
1922
+ if (
1923
+ object_pattern.parent &&
1924
+ object_pattern.parent.type === "VariableDeclarator"
1925
+ ) {
1303
1926
  var declarator = object_pattern.parent;
1304
-
1927
+
1305
1928
  // 检查右侧是否为require调用或其他模块导入
1306
1929
  if (declarator.init) {
1307
1930
  var init_type = declarator.init.type;
1308
-
1931
+
1309
1932
  // 常见的模块导入方式
1310
- if (init_type === 'CallExpression' &&
1311
- declarator.init.callee &&
1312
- declarator.init.callee.name === 'require') {
1933
+ if (
1934
+ init_type === "CallExpression" &&
1935
+ declarator.init.callee &&
1936
+ declarator.init.callee.name === "require"
1937
+ ) {
1313
1938
  is_destructured = true;
1314
1939
  }
1315
-
1940
+
1316
1941
  // 如果是ImportDeclaration(ES6导入)
1317
- if (init_type === 'ImportExpression') {
1942
+ if (init_type === "ImportExpression") {
1318
1943
  is_destructured = true;
1319
1944
  }
1320
1945
  }
1321
1946
  }
1322
1947
  }
1323
1948
  }
1324
-
1949
+
1325
1950
  // 情况2:节点是VariableDeclarator(简单变量声明)
1326
- else if (node.parent.type === 'VariableDeclarator') {
1951
+ else if (node.parent.type === "VariableDeclarator") {
1327
1952
  var declarator = node.parent;
1328
-
1953
+
1329
1954
  // 检查是否为解构模式(ObjectPattern或ArrayPattern)
1330
- if (declarator.id && declarator.id.type === 'ObjectPattern') {
1955
+ if (declarator.id && declarator.id.type === "ObjectPattern") {
1331
1956
  // 检查右侧是否为require调用或其他模块导入
1332
1957
  if (declarator.init) {
1333
1958
  var init_type = declarator.init.type;
1334
-
1959
+
1335
1960
  // 常见的模块导入方式
1336
- if (init_type === 'CallExpression' &&
1337
- declarator.init.callee &&
1338
- declarator.init.callee.name === 'require') {
1961
+ if (
1962
+ init_type === "CallExpression" &&
1963
+ declarator.init.callee &&
1964
+ declarator.init.callee.name === "require"
1965
+ ) {
1339
1966
  is_destructured = true;
1340
1967
  }
1341
-
1968
+
1342
1969
  // 如果是ImportDeclaration(ES6导入)
1343
- if (init_type === 'ImportExpression') {
1970
+ if (init_type === "ImportExpression") {
1344
1971
  is_destructured = true;
1345
1972
  }
1346
1973
  }
@@ -1349,7 +1976,7 @@ Detector.prototype._isDestructuredImport = function (node) {
1349
1976
 
1350
1977
  return is_destructured;
1351
1978
  } catch (error) {
1352
- console.error('检查是否为解构导入时出错:', error);
1979
+ console.error("检查是否为解构导入时出错:", error);
1353
1980
  return false;
1354
1981
  }
1355
1982
  };
@@ -1360,41 +1987,50 @@ Detector.prototype._isDestructuredImport = function (node) {
1360
1987
  * @param {object} parent_node 父节点
1361
1988
  * @returns {boolean} 是否为解构导入中的属性
1362
1989
  */
1363
- Detector.prototype._isDestructuredImportProperty = function (node, parent_node) {
1990
+ Detector.prototype._isDestructuredImportProperty = function (
1991
+ node,
1992
+ parent_node,
1993
+ ) {
1364
1994
  try {
1365
1995
  // 处理新的父节点信息结构(包含node和parent属性)
1366
1996
  var actual_parent_node = parent_node;
1367
- if (parent_node && typeof parent_node === 'object' && parent_node.node) {
1997
+ if (parent_node && typeof parent_node === "object" && parent_node.node) {
1368
1998
  actual_parent_node = parent_node.node;
1369
1999
  }
1370
-
2000
+
1371
2001
  if (!node || !actual_parent_node) {
1372
2002
  return false;
1373
2003
  }
1374
2004
 
1375
2005
  // 检查父节点是否为ObjectPattern(解构模式)
1376
- if (actual_parent_node.type === 'ObjectPattern') {
2006
+ if (actual_parent_node.type === "ObjectPattern") {
1377
2007
  // 检查父节点的父节点是否为VariableDeclarator
1378
- var actual_parent_parent = parent_node && typeof parent_node === 'object' && parent_node.parent
1379
- ? parent_node.parent
1380
- : actual_parent_node.parent;
1381
-
1382
- if (actual_parent_parent && actual_parent_parent.type === 'VariableDeclarator') {
2008
+ var actual_parent_parent =
2009
+ parent_node && typeof parent_node === "object" && parent_node.parent
2010
+ ? parent_node.parent
2011
+ : actual_parent_node.parent;
2012
+
2013
+ if (
2014
+ actual_parent_parent &&
2015
+ actual_parent_parent.type === "VariableDeclarator"
2016
+ ) {
1383
2017
  var declarator = actual_parent_parent;
1384
-
2018
+
1385
2019
  // 检查右侧是否为require调用或其他模块导入
1386
2020
  if (declarator.init) {
1387
2021
  var init_type = declarator.init.type;
1388
-
2022
+
1389
2023
  // 常见的模块导入方式
1390
- if (init_type === 'CallExpression' &&
1391
- declarator.init.callee &&
1392
- declarator.init.callee.name === 'require') {
2024
+ if (
2025
+ init_type === "CallExpression" &&
2026
+ declarator.init.callee &&
2027
+ declarator.init.callee.name === "require"
2028
+ ) {
1393
2029
  return true;
1394
2030
  }
1395
-
2031
+
1396
2032
  // 如果是ImportDeclaration(ES6导入)
1397
- if (init_type === 'ImportExpression') {
2033
+ if (init_type === "ImportExpression") {
1398
2034
  return true;
1399
2035
  }
1400
2036
  }
@@ -1403,7 +2039,7 @@ Detector.prototype._isDestructuredImportProperty = function (node, parent_node)
1403
2039
 
1404
2040
  return false;
1405
2041
  } catch (error) {
1406
- console.error('检查是否为解构导入中的属性时出错:', error);
2042
+ console.error("检查是否为解构导入中的属性时出错:", error);
1407
2043
  return false;
1408
2044
  }
1409
2045
  };
@@ -1420,29 +2056,32 @@ Detector.prototype._isFunctionAssignment = function (node) {
1420
2056
  }
1421
2057
 
1422
2058
  // 检查节点是否为解构赋值中的属性
1423
- if (node.type === 'Property' && node.key === node) {
2059
+ if (node.type === "Property" && node.key === node) {
1424
2060
  // 检查父节点是否为ObjectPattern
1425
- if (node.parent && node.parent.type === 'ObjectPattern') {
2061
+ if (node.parent && node.parent.type === "ObjectPattern") {
1426
2062
  // 检查父节点的父节点是否为VariableDeclarator
1427
- if (node.parent.parent && node.parent.parent.type === 'VariableDeclarator') {
2063
+ if (
2064
+ node.parent.parent &&
2065
+ node.parent.parent.type === "VariableDeclarator"
2066
+ ) {
1428
2067
  var declarator = node.parent.parent;
1429
-
2068
+
1430
2069
  // 检查右侧是否为函数表达式或箭头函数
1431
2070
  if (declarator.init) {
1432
2071
  var init_type = declarator.init.type;
1433
-
2072
+
1434
2073
  // 函数表达式
1435
- if (init_type === 'FunctionExpression') {
2074
+ if (init_type === "FunctionExpression") {
1436
2075
  return true;
1437
2076
  }
1438
-
2077
+
1439
2078
  // 箭头函数
1440
- if (init_type === 'ArrowFunctionExpression') {
2079
+ if (init_type === "ArrowFunctionExpression") {
1441
2080
  return true;
1442
2081
  }
1443
-
2082
+
1444
2083
  // 函数调用(可能返回函数)
1445
- if (init_type === 'CallExpression') {
2084
+ if (init_type === "CallExpression") {
1446
2085
  return true;
1447
2086
  }
1448
2087
  }
@@ -1451,27 +2090,34 @@ Detector.prototype._isFunctionAssignment = function (node) {
1451
2090
  }
1452
2091
 
1453
2092
  // 检查节点是否为解构赋值中的数组元素
1454
- if (node.type === 'Identifier' && node.parent && node.parent.type === 'ArrayPattern') {
2093
+ if (
2094
+ node.type === "Identifier" &&
2095
+ node.parent &&
2096
+ node.parent.type === "ArrayPattern"
2097
+ ) {
1455
2098
  // 检查父节点的父节点是否为VariableDeclarator
1456
- if (node.parent.parent && node.parent.parent.type === 'VariableDeclarator') {
2099
+ if (
2100
+ node.parent.parent &&
2101
+ node.parent.parent.type === "VariableDeclarator"
2102
+ ) {
1457
2103
  var declarator = node.parent.parent;
1458
-
2104
+
1459
2105
  // 检查右侧是否为函数表达式或箭头函数
1460
2106
  if (declarator.init) {
1461
2107
  var init_type = declarator.init.type;
1462
-
2108
+
1463
2109
  // 函数表达式
1464
- if (init_type === 'FunctionExpression') {
2110
+ if (init_type === "FunctionExpression") {
1465
2111
  return true;
1466
2112
  }
1467
-
2113
+
1468
2114
  // 箭头函数
1469
- if (init_type === 'ArrowFunctionExpression') {
2115
+ if (init_type === "ArrowFunctionExpression") {
1470
2116
  return true;
1471
2117
  }
1472
-
2118
+
1473
2119
  // 函数调用(可能返回函数)
1474
- if (init_type === 'CallExpression') {
2120
+ if (init_type === "CallExpression") {
1475
2121
  return true;
1476
2122
  }
1477
2123
  }
@@ -1480,7 +2126,7 @@ Detector.prototype._isFunctionAssignment = function (node) {
1480
2126
 
1481
2127
  return false;
1482
2128
  } catch (error) {
1483
- console.error('检查是否为函数赋值时出错:', error);
2129
+ console.error("检查是否为函数赋值时出错:", error);
1484
2130
  return false;
1485
2131
  }
1486
2132
  };
@@ -1492,16 +2138,20 @@ Detector.prototype._isFunctionAssignment = function (node) {
1492
2138
  */
1493
2139
  Detector.prototype._isConstantNameValid = function (constant_name) {
1494
2140
  try {
1495
- var rule = this.config.getRule('constant-name');
2141
+ var rule = this.config.getRule("constant-name");
1496
2142
  if (!rule) {
1497
2143
  return false;
1498
2144
  }
1499
2145
 
1500
2146
  // 检查命名风格
1501
- var style_err = this._validate_naming_style(constant_name, rule.styles, 'constant-name');
2147
+ var style_err = this._validate_naming_style(
2148
+ constant_name,
2149
+ rule.styles,
2150
+ "constant-name",
2151
+ );
1502
2152
  return !style_err;
1503
2153
  } catch (error) {
1504
- console.error('检查常量名是否符合规范时出错:', error);
2154
+ console.error("检查常量名是否符合规范时出错:", error);
1505
2155
  return false;
1506
2156
  }
1507
2157
  };
@@ -1527,8 +2177,8 @@ Detector.prototype._isIgnoredWord = function (name, name_type) {
1527
2177
  }
1528
2178
 
1529
2179
  return false;
1530
- } catch (error) {
1531
- console.error('检查是否为忽略词时出错:', error);
2180
+ } catch (error) {
2181
+ console.error("检查是否为忽略词时出错:", error);
1532
2182
  return false;
1533
2183
  }
1534
2184
  };
@@ -1540,7 +2190,11 @@ Detector.prototype._isIgnoredWord = function (name, name_type) {
1540
2190
  * @param {string} name_type 名称类型
1541
2191
  * @returns {string|null} 推荐命名或null
1542
2192
  */
1543
- Detector.prototype._generateRecommendedName = function (original_name, long_word, name_type) {
2193
+ Detector.prototype._generateRecommendedName = function (
2194
+ original_name,
2195
+ long_word,
2196
+ name_type,
2197
+ ) {
1544
2198
  try {
1545
2199
  // 获取推荐词映射
1546
2200
  var recommended_words = this.config.getRecommendedWords(name_type);
@@ -1549,18 +2203,26 @@ Detector.prototype._generateRecommendedName = function (original_name, long_word
1549
2203
  }
1550
2204
 
1551
2205
  var long_word_lower = long_word.toLowerCase();
1552
-
2206
+ var is_private = original_name.startsWith("_");
2207
+ var original_name_without_prefix = is_private
2208
+ ? original_name.substring(1)
2209
+ : original_name;
2210
+
1553
2211
  // 检查推荐词映射中是否有对应的缩写
1554
2212
  for (var short_word in recommended_words) {
1555
2213
  if (recommended_words.hasOwnProperty(short_word)) {
1556
2214
  var original_words = recommended_words[short_word];
1557
-
2215
+
1558
2216
  // 检查过长的单词是否在推荐词的原词列表中
1559
2217
  for (var i = 0; i < original_words.length; i++) {
1560
2218
  var original_word = original_words[i].toLowerCase();
1561
2219
  if (long_word_lower === original_word) {
1562
- // 生成推荐命名:将原始名称中的长单词替换为推荐的缩写
1563
- var recommended_name = original_name.replace(long_word, short_word);
2220
+ // 生成推荐命名:将原始名称中的长单词替换为推荐的缩写,保持私有前缀
2221
+ var recommended_name_without_prefix =
2222
+ original_name_without_prefix.replace(long_word, short_word);
2223
+ var recommended_name = is_private
2224
+ ? "_" + recommended_name_without_prefix
2225
+ : recommended_name_without_prefix;
1564
2226
  return recommended_name;
1565
2227
  }
1566
2228
  }
@@ -1569,50 +2231,679 @@ Detector.prototype._generateRecommendedName = function (original_name, long_word
1569
2231
 
1570
2232
  return null;
1571
2233
  } catch (error) {
1572
- console.error('生成推荐命名时出错:', error);
2234
+ console.error("生成推荐命名时出错:", error);
2235
+ return null;
2236
+ }
2237
+ };
2238
+
2239
+ /**
2240
+ * 转换命名风格
2241
+ * @param {string} name 原始名称
2242
+ * @param {string} target_style 目标命名风格
2243
+ * @param {string} name_type 名称类型
2244
+ * @returns {string} 转换后的名称
2245
+ */
2246
+ Detector.prototype._convertNamingStyle = function (
2247
+ name,
2248
+ target_style,
2249
+ name_type,
2250
+ ) {
2251
+ try {
2252
+ if (!name || !target_style) {
2253
+ return name;
2254
+ }
2255
+
2256
+ // 处理私有标识符
2257
+ var has_private_prefix = name.startsWith("_");
2258
+ var processed_name = has_private_prefix ? name.substring(1) : name;
2259
+
2260
+ // 分割单词
2261
+ var words = this._splitNameIntoWords(processed_name);
2262
+
2263
+ // 过滤空字符串和私有标识符
2264
+ words = words.filter(function (word) {
2265
+ return word && word.length > 0 && word !== "_";
2266
+ });
2267
+
2268
+ if (words.length === 0) {
2269
+ return name;
2270
+ }
2271
+
2272
+ var converted_name = "";
2273
+
2274
+ // 根据目标风格转换
2275
+ switch (target_style) {
2276
+ case "camelCase":
2277
+ // 小驼峰命名法
2278
+ converted_name = words
2279
+ .map(function (word, index) {
2280
+ if (index === 0) {
2281
+ return word.toLowerCase();
2282
+ }
2283
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
2284
+ })
2285
+ .join("");
2286
+ break;
2287
+
2288
+ case "_camelCase":
2289
+ // 私有小驼峰命名法
2290
+ converted_name =
2291
+ "_" +
2292
+ words
2293
+ .map(function (word, index) {
2294
+ if (index === 0) {
2295
+ return word.toLowerCase();
2296
+ }
2297
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
2298
+ })
2299
+ .join("");
2300
+ break;
2301
+
2302
+ case "PascalCase":
2303
+ // 大驼峰命名法
2304
+ converted_name = words
2305
+ .map(function (word) {
2306
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
2307
+ })
2308
+ .join("");
2309
+ break;
2310
+
2311
+ case "snake_case":
2312
+ // 小写蛇形命名法
2313
+ converted_name = words
2314
+ .map(function (word) {
2315
+ return word.toLowerCase();
2316
+ })
2317
+ .join("_");
2318
+ break;
2319
+
2320
+ case "_snake_case":
2321
+ // 私有小写蛇形命名法
2322
+ converted_name =
2323
+ "_" +
2324
+ words
2325
+ .map(function (word) {
2326
+ return word.toLowerCase();
2327
+ })
2328
+ .join("_");
2329
+ break;
2330
+
2331
+ case "UPPER_SNAKE_CASE":
2332
+ // 大写蛇形命名法
2333
+ converted_name = words
2334
+ .map(function (word) {
2335
+ return word.toUpperCase();
2336
+ })
2337
+ .join("_");
2338
+ break;
2339
+
2340
+ default:
2341
+ converted_name = name;
2342
+ }
2343
+
2344
+ // 如果原始名称有私有前缀但目标风格不是私有风格,则添加私有前缀
2345
+ if (
2346
+ has_private_prefix &&
2347
+ !target_style.startsWith("_") &&
2348
+ !converted_name.startsWith("_")
2349
+ ) {
2350
+ converted_name = "_" + converted_name;
2351
+ }
2352
+
2353
+ return converted_name;
2354
+ } catch (error) {
2355
+ console.error("转换命名风格时出错:", error);
2356
+ return name;
2357
+ }
2358
+ };
2359
+
2360
+ /**
2361
+ * 获取命名修复建议
2362
+ * @param {string} name 原始名称
2363
+ * @param {string} name_type 名称类型
2364
+ * @param {string} error_message 错误信息
2365
+ * @returns {object|null} 修复建议对象
2366
+ */
2367
+ Detector.prototype._getFixSuggestion = function (
2368
+ name,
2369
+ name_type,
2370
+ error_message,
2371
+ ) {
2372
+ try {
2373
+ var rule = this.config.getRule(name_type);
2374
+ if (!rule || !rule.styles || rule.styles.length === 0) {
2375
+ return null;
2376
+ }
2377
+
2378
+ // 根据名称类型智能选择目标风格
2379
+ var target_style = this._getSmartTargetStyle(name, name_type, rule.styles);
2380
+
2381
+ // 生成修复后的名称
2382
+ var fixed_name = this._convertNamingStyle(name, target_style, name_type);
2383
+
2384
+ // 优先检查错误消息中是否有建议使用的名称
2385
+ if (error_message && error_message.includes("建议使用:")) {
2386
+ // 从错误消息中提取建议的名称
2387
+ var suggestion_match = error_message.match(/建议使用:\s*([\w_]+)/);
2388
+ if (suggestion_match && suggestion_match[1]) {
2389
+ fixed_name = suggestion_match[1];
2390
+
2391
+ // 对于私有方法(以_开头),根据错误消息确定正确的命名风格
2392
+ if (name_type === "method-name" && fixed_name.startsWith("_")) {
2393
+ // 检查错误消息中是否指定了命名风格
2394
+ if (error_message.includes("_camelCase")) {
2395
+ target_style = "_camelCase";
2396
+ } else if (error_message.includes("_snake_case")) {
2397
+ target_style = "_snake_case";
2398
+ } else {
2399
+ // 默认使用_snake_case风格
2400
+ target_style = "_snake_case";
2401
+ }
2402
+ }
2403
+
2404
+ // 验证建议的名称是否有效
2405
+ var suggestion_validation = this._validate_naming_style(
2406
+ fixed_name,
2407
+ [target_style],
2408
+ name_type,
2409
+ );
2410
+
2411
+ if (suggestion_validation) {
2412
+ // 建议的名称无效,回退到原始转换逻辑
2413
+ fixed_name = this._convertNamingStyle(name, target_style, name_type);
2414
+ }
2415
+ }
2416
+ }
2417
+
2418
+ // 检查是否需要智能缩写(长度过长的问题)
2419
+ if (error_message && error_message.includes("长度过长")) {
2420
+ // 如果错误消息中已经有建议名称,使用建议名称
2421
+ if (error_message.includes("建议使用:")) {
2422
+ // 已经处理过建议名称,直接使用
2423
+ } else {
2424
+ // 如果没有建议名称,使用智能缩写
2425
+ fixed_name = this._getSmartAbbreviation(name, name_type);
2426
+
2427
+ // 如果智能缩写后名称仍然相同,则不提供修复建议
2428
+ if (fixed_name === name) {
2429
+ return null;
2430
+ }
2431
+
2432
+ // 支持多次缩写直到满足长度要求
2433
+ var max_length = rule.max || 20;
2434
+ var current_name = fixed_name;
2435
+ var max_attempts = 5; // 最多尝试5次
2436
+
2437
+ for (var attempt = 0; attempt < max_attempts; attempt++) {
2438
+ if (current_name.length <= max_length) {
2439
+ break; // 长度满足要求,退出循环
2440
+ }
2441
+
2442
+ var next_name = this._getSmartAbbreviation(current_name, name_type);
2443
+ if (next_name === current_name) {
2444
+ break; // 无法进一步缩写,退出循环
2445
+ }
2446
+ current_name = next_name;
2447
+ }
2448
+
2449
+ fixed_name = current_name;
2450
+ }
2451
+ } else if (fixed_name === name) {
2452
+ // 其他情况下,转换后名称相同,不提供修复建议
2453
+ return null;
2454
+ }
2455
+
2456
+ // 检查修复后的名称是否仍然有错误
2457
+ var fixed_style_err = this._validate_naming_style(
2458
+ fixed_name,
2459
+ [target_style],
2460
+ name_type,
2461
+ );
2462
+ if (fixed_style_err) {
2463
+ // 修复后的名称仍然有错误,尝试其他风格
2464
+ for (var i = 1; i < rule.styles.length; i++) {
2465
+ var alternative_style = rule.styles[i];
2466
+ var alternative_name = this._convertNamingStyle(
2467
+ name,
2468
+ alternative_style,
2469
+ name_type,
2470
+ );
2471
+ var alternative_err = this._validate_naming_style(
2472
+ alternative_name,
2473
+ [alternative_style],
2474
+ name_type,
2475
+ );
2476
+
2477
+ if (!alternative_err) {
2478
+ fixed_name = alternative_name;
2479
+ target_style = alternative_style;
2480
+ break;
2481
+ }
2482
+ }
2483
+ }
2484
+
2485
+ // 如果名称长度仍然过长,且错误消息中没有建议名称,进行智能缩写处理
2486
+ if (
2487
+ error_message &&
2488
+ error_message.includes("长度过长") &&
2489
+ !error_message.includes("建议使用:")
2490
+ ) {
2491
+ fixed_name = this._getSmartAbbreviation(name, name_type);
2492
+ }
2493
+
2494
+ return {
2495
+ fixed_name: fixed_name,
2496
+ target_style: target_style,
2497
+ };
2498
+ } catch (error) {
2499
+ console.error("获取命名修复建议时出错:", error);
1573
2500
  return null;
1574
2501
  }
1575
2502
  };
1576
2503
 
2504
+ /**
2505
+ * 智能缩写处理(针对长度过长的名称)
2506
+ * @param {string} name 原始名称
2507
+ * @param {string} name_type 名称类型
2508
+ * @returns {string} 缩写后的名称
2509
+ */
2510
+ Detector.prototype._getSmartAbbreviation = function (name, name_type) {
2511
+ try {
2512
+ // 处理私有标识符
2513
+ var has_private_prefix = name.startsWith("_");
2514
+ var processed_name = has_private_prefix ? name.substring(1) : name;
2515
+
2516
+ // 分割单词
2517
+ var words = this._splitNameIntoWords(processed_name);
2518
+
2519
+ // 过滤空字符串
2520
+ words = words.filter(function (word) {
2521
+ return word && word.length > 0;
2522
+ });
2523
+
2524
+ if (words.length === 0) {
2525
+ return name;
2526
+ }
2527
+
2528
+ // 获取配置中的推荐词映射
2529
+ var rec_words = {};
2530
+ if (
2531
+ this.config.getRecommendedWords &&
2532
+ typeof this.config.getRecommendedWords === "function"
2533
+ ) {
2534
+ rec_words = this.config.getRecommendedWords(name_type);
2535
+ }
2536
+
2537
+ // 获取配置中的禁止词列表(作为禁止拼接词)
2538
+ var forbidden_words = [];
2539
+ if (
2540
+ this.config.getForbiddenWords &&
2541
+ typeof this.config.getForbiddenWords === "function"
2542
+ ) {
2543
+ forbidden_words = this.config.getForbiddenWords(name_type);
2544
+ }
2545
+
2546
+ if (!rec_words || Object.keys(rec_words).length === 0) {
2547
+ return name;
2548
+ }
2549
+
2550
+ // 处理每个单词,使用推荐词替换
2551
+ var processed_words = [];
2552
+ for (var i = 0; i < words.length; i++) {
2553
+ var word = words[i];
2554
+ var word_lower = word.toLowerCase();
2555
+ var replaced = false;
2556
+
2557
+ // 检查是否需要替换为推荐词
2558
+ for (var rec_word in rec_words) {
2559
+ if (rec_words.hasOwnProperty(rec_word)) {
2560
+ var original_words = rec_words[rec_word];
2561
+
2562
+ for (var j = 0; j < original_words.length; j++) {
2563
+ var original_word = original_words[j].toLowerCase();
2564
+
2565
+ // 如果当前单词包含原词(不区分大小写),则替换为推荐词
2566
+ if (word_lower.includes(original_word)) {
2567
+ // 保持首字母大小写
2568
+ if (word[0] === word[0].toUpperCase()) {
2569
+ processed_words.push(
2570
+ rec_word[0].toUpperCase() + rec_word.substring(1),
2571
+ );
2572
+ } else {
2573
+ processed_words.push(rec_word);
2574
+ }
2575
+ replaced = true;
2576
+ break;
2577
+ }
2578
+ }
2579
+
2580
+ if (replaced) break;
2581
+ }
2582
+ }
2583
+
2584
+ // 如果没有找到推荐词,检查是否为禁止拼接词
2585
+ if (!replaced) {
2586
+ var is_forbidden = false;
2587
+ for (var f = 0; f < forbidden_words.length; f++) {
2588
+ var forbidden_word = forbidden_words[f].toLowerCase();
2589
+ if (word_lower === forbidden_word) {
2590
+ is_forbidden = true;
2591
+ break;
2592
+ }
2593
+ }
2594
+
2595
+ // 如果不是禁止拼接词,保留原词
2596
+ if (!is_forbidden) {
2597
+ processed_words.push(word);
2598
+ }
2599
+ }
2600
+ }
2601
+
2602
+ // 根据名称类型确定目标风格
2603
+ var target_style = "camelCase";
2604
+ if (name_type === "constant-name") {
2605
+ target_style = "UPPER_SNAKE_CASE";
2606
+ } else if (
2607
+ name_type === "class-name" ||
2608
+ name_type === "property-class-name"
2609
+ ) {
2610
+ target_style = "PascalCase";
2611
+ } else if (
2612
+ name_type === "variable-name" ||
2613
+ name_type === "property-value-name"
2614
+ ) {
2615
+ target_style = "snake_case";
2616
+ }
2617
+ // 函数名、方法名等保持默认的 camelCase
2618
+
2619
+ var abbreviated_name = "";
2620
+
2621
+ switch (target_style) {
2622
+ case "camelCase":
2623
+ for (var k = 0; k < processed_words.length; k++) {
2624
+ if (k === 0) {
2625
+ abbreviated_name += processed_words[k].toLowerCase();
2626
+ } else {
2627
+ abbreviated_name +=
2628
+ processed_words[k][0].toUpperCase() +
2629
+ processed_words[k].substring(1).toLowerCase();
2630
+ }
2631
+ }
2632
+ break;
2633
+ case "PascalCase":
2634
+ for (var l = 0; l < processed_words.length; l++) {
2635
+ abbreviated_name +=
2636
+ processed_words[l][0].toUpperCase() +
2637
+ processed_words[l].substring(1).toLowerCase();
2638
+ }
2639
+ break;
2640
+ case "snake_case":
2641
+ abbreviated_name = processed_words.join("_").toLowerCase();
2642
+ break;
2643
+ case "UPPER_SNAKE_CASE":
2644
+ abbreviated_name = processed_words.join("_").toUpperCase();
2645
+ break;
2646
+ default:
2647
+ abbreviated_name = processed_words.join("");
2648
+ }
2649
+
2650
+ // 恢复私有标识符
2651
+ if (has_private_prefix) {
2652
+ abbreviated_name = "_" + abbreviated_name;
2653
+ }
2654
+
2655
+ // 检查长度:如果缩写后长度没有变短,尝试其他策略
2656
+ if (abbreviated_name.length >= name.length) {
2657
+ return name;
2658
+ }
2659
+
2660
+ // 如果缩写后仍然超过最大长度,尝试进一步优化
2661
+ var max_length = 20;
2662
+ if (abbreviated_name.length > max_length) {
2663
+ // 策略1: 截断过长的单词
2664
+ var optimized_words = [];
2665
+ for (var k = 0; k < processed_words.length; k++) {
2666
+ var word = processed_words[k];
2667
+ if (word.length > 8) {
2668
+ // 截断过长的单词到8个字符
2669
+ optimized_words.push(word.substring(0, 8));
2670
+ } else {
2671
+ optimized_words.push(word);
2672
+ }
2673
+ }
2674
+
2675
+ // 重新生成名称
2676
+ var optimized_name = "";
2677
+ switch (target_style) {
2678
+ case "camelCase":
2679
+ for (var m = 0; m < optimized_words.length; m++) {
2680
+ if (m === 0) {
2681
+ optimized_name += optimized_words[m].toLowerCase();
2682
+ } else {
2683
+ optimized_name +=
2684
+ optimized_words[m][0].toUpperCase() +
2685
+ optimized_words[m].substring(1).toLowerCase();
2686
+ }
2687
+ }
2688
+ break;
2689
+ case "PascalCase":
2690
+ for (var n = 0; n < optimized_words.length; n++) {
2691
+ optimized_name +=
2692
+ optimized_words[n][0].toUpperCase() +
2693
+ optimized_words[n].substring(1).toLowerCase();
2694
+ }
2695
+ break;
2696
+ case "snake_case":
2697
+ optimized_name = optimized_words.join("_").toLowerCase();
2698
+ break;
2699
+ case "UPPER_SNAKE_CASE":
2700
+ optimized_name = optimized_words.join("_").toUpperCase();
2701
+ break;
2702
+ default:
2703
+ optimized_name = optimized_words.join("");
2704
+ }
2705
+
2706
+ // 恢复私有标识符
2707
+ if (has_private_prefix) {
2708
+ optimized_name = "_" + optimized_name;
2709
+ }
2710
+
2711
+ // 如果优化后名称更短,使用优化后的名称
2712
+ if (optimized_name.length < abbreviated_name.length) {
2713
+ abbreviated_name = optimized_name;
2714
+ }
2715
+
2716
+ // 如果仍然超过长度,尝试移除不重要的单词
2717
+ if (abbreviated_name.length > max_length && processed_words.length > 2) {
2718
+ // 保留前2个和后1个单词
2719
+ var important_words = [
2720
+ processed_words[0],
2721
+ processed_words[1],
2722
+ processed_words[processed_words.length - 1],
2723
+ ];
2724
+
2725
+ // 根据目标风格生成简化名称
2726
+ var simplified_name = "";
2727
+ switch (target_style) {
2728
+ case "camelCase":
2729
+ for (var o = 0; o < important_words.length; o++) {
2730
+ if (o === 0) {
2731
+ simplified_name += important_words[o].toLowerCase();
2732
+ } else {
2733
+ simplified_name +=
2734
+ important_words[o][0].toUpperCase() +
2735
+ important_words[o].substring(1).toLowerCase();
2736
+ }
2737
+ }
2738
+ break;
2739
+ case "PascalCase":
2740
+ for (var p = 0; p < important_words.length; p++) {
2741
+ simplified_name +=
2742
+ important_words[p][0].toUpperCase() +
2743
+ important_words[p].substring(1).toLowerCase();
2744
+ }
2745
+ break;
2746
+ case "snake_case":
2747
+ simplified_name = important_words.join("_").toLowerCase();
2748
+ break;
2749
+ case "UPPER_SNAKE_CASE":
2750
+ simplified_name = important_words.join("_").toUpperCase();
2751
+ break;
2752
+ default:
2753
+ simplified_name = important_words.join("");
2754
+ }
2755
+
2756
+ // 恢复私有标识符
2757
+ if (has_private_prefix) {
2758
+ simplified_name = "_" + simplified_name;
2759
+ }
2760
+
2761
+ // 如果简化后名称更短且不超过最大长度,使用简化后的名称
2762
+ if (
2763
+ simplified_name.length <= max_length &&
2764
+ simplified_name.length < abbreviated_name.length
2765
+ ) {
2766
+ abbreviated_name = simplified_name;
2767
+ }
2768
+ }
2769
+ }
2770
+
2771
+ return abbreviated_name;
2772
+ } catch (error) {
2773
+ console.error("智能缩写处理时出错:", error);
2774
+ return name;
2775
+ }
2776
+ };
2777
+
2778
+ /**
2779
+ * 智能选择目标命名风格
2780
+ * @param {string} name 原始名称
2781
+ * @param {string} name_type 名称类型
2782
+ * @param {array} available_styles 可用的命名风格
2783
+ * @returns {string} 目标命名风格
2784
+ */
2785
+ Detector.prototype._getSmartTargetStyle = function (
2786
+ name,
2787
+ name_type,
2788
+ available_styles,
2789
+ ) {
2790
+ try {
2791
+ // 默认使用第一个风格
2792
+ var target_style = available_styles[0];
2793
+
2794
+ // 根据名称类型和原始名称特征智能选择
2795
+ switch (name_type) {
2796
+ case "property-value-name":
2797
+ // 属性值:根据是否为私有属性和值类型选择风格
2798
+ if (name.startsWith("_")) {
2799
+ // 私有属性值:优先使用私有蛇形命名
2800
+ target_style =
2801
+ available_styles.find(function (style) {
2802
+ return style === "_snake_case";
2803
+ }) || target_style;
2804
+ } else {
2805
+ // 公开属性值:优先使用蛇形命名
2806
+ target_style =
2807
+ available_styles.find(function (style) {
2808
+ return style === "snake_case";
2809
+ }) || target_style;
2810
+ }
2811
+ break;
2812
+
2813
+ case "property-class-name":
2814
+ // 属性类:根据是否为私有类选择风格
2815
+ if (name.startsWith("_")) {
2816
+ // 私有属性类:优先使用私有大驼峰命名
2817
+ target_style =
2818
+ available_styles.find(function (style) {
2819
+ return style === "_PascalCase";
2820
+ }) || target_style;
2821
+ } else {
2822
+ // 公开属性类:优先使用大驼峰命名
2823
+ target_style =
2824
+ available_styles.find(function (style) {
2825
+ return style === "PascalCase";
2826
+ }) || target_style;
2827
+ }
2828
+ break;
2829
+
2830
+ case "property-instance-class-name":
2831
+ case "property-method-name":
2832
+ // 属性实例类和属性方法:根据是否为私有选择风格
2833
+ if (name.startsWith("_")) {
2834
+ // 私有实例类/方法:优先使用私有小驼峰命名
2835
+ target_style =
2836
+ available_styles.find(function (style) {
2837
+ return style === "_camelCase";
2838
+ }) || target_style;
2839
+ } else {
2840
+ // 公开实例类/方法:优先使用小驼峰命名
2841
+ target_style =
2842
+ available_styles.find(function (style) {
2843
+ return style === "camelCase";
2844
+ }) || target_style;
2845
+ }
2846
+ break;
2847
+
2848
+ default:
2849
+ // 其他类型:使用默认风格
2850
+ target_style = available_styles[0];
2851
+ }
2852
+
2853
+ return target_style;
2854
+ } catch (error) {
2855
+ console.error("智能选择目标命名风格时出错:", error);
2856
+ return available_styles[0];
2857
+ }
2858
+ };
2859
+
1577
2860
  /**
1578
2861
  * 检测解构赋值中的常量名
1579
2862
  * @param {string} constant_name 常量名
1580
2863
  * @param {object} node AST节点
1581
2864
  * @returns {object|null} 错误信息或null
1582
2865
  */
1583
- Detector.prototype._checkConstantNameForDestructuring = function (constant_name, node) {
2866
+ Detector.prototype._checkConstantNameForDestructuring = function (
2867
+ constant_name,
2868
+ node,
2869
+ ) {
1584
2870
  try {
1585
- var rule = this.config.getRule('constant-name');
2871
+ // 解构赋值中的变量应该使用变量规则,而不是常量规则
2872
+ var rule = this.config.getRule("variable-name");
1586
2873
  if (!rule) {
1587
2874
  return null;
1588
2875
  }
1589
2876
 
1590
2877
  // 检查是否为忽略词
1591
- if (this._isIgnoredWord(constant_name, 'constant-name')) {
2878
+ if (this._isIgnoredWord(constant_name, "variable-name")) {
1592
2879
  return null;
1593
2880
  }
1594
2881
 
1595
2882
  // 检查是否为解构导入(从模块导入的变量)
1596
2883
  var is_destructured_import = this._isDestructuredImport(node);
1597
-
1598
- // 如果是解构导入,则不进行常量检测
2884
+
2885
+ // 如果是解构导入,则不进行变量检测
1599
2886
  if (is_destructured_import) {
1600
2887
  return null;
1601
2888
  }
1602
2889
 
1603
2890
  // 检查是否为函数赋值(函数表达式或箭头函数)
1604
2891
  var is_function_assignment = this._isFunctionAssignment(node);
1605
-
2892
+
1606
2893
  // 如果是函数赋值,允许camelCase命名风格
1607
2894
  var allowed_styles = [];
1608
2895
  if (is_function_assignment) {
1609
- allowed_styles = ['camelCase', 'UPPER_SNAKE_CASE'];
2896
+ allowed_styles = ["camelCase", "UPPER_SNAKE_CASE"];
1610
2897
  } else {
1611
2898
  allowed_styles = rule.styles;
1612
2899
  }
1613
2900
 
1614
2901
  // 检查命名风格
1615
- var style_err = this._validate_naming_style(constant_name, allowed_styles, 'constant-name');
2902
+ var style_err = this._validate_naming_style(
2903
+ constant_name,
2904
+ allowed_styles,
2905
+ "variable-name",
2906
+ );
1616
2907
  if (style_err) {
1617
2908
  return {
1618
2909
  node: node,
@@ -1620,17 +2911,30 @@ Detector.prototype._checkConstantNameForDestructuring = function (constant_name,
1620
2911
  };
1621
2912
  }
1622
2913
 
1623
- // 检查并推荐更合适的词汇
1624
- var rec_err = this._checkAndRecommend(constant_name, 'constant-name');
1625
- if (rec_err) {
2914
+ // 检查并推荐更合适的词汇(作为命名风格检查的补充)
2915
+ var recommend_info = this._checkAndRecommend(
2916
+ constant_name,
2917
+ "variable-name",
2918
+ );
2919
+ if (recommend_info) {
2920
+ // 如果有推荐建议,在错误消息中提示可以使用更简洁的词汇
1626
2921
  return {
1627
2922
  node: node,
1628
- message: rec_err,
2923
+ message:
2924
+ "变量名'" +
2925
+ constant_name +
2926
+ "'长度过长,最大长度为20字符,建议使用: " +
2927
+ recommend_info.recommended_name,
1629
2928
  };
1630
2929
  }
1631
2930
 
1632
2931
  // 检查长度
1633
- var len_err = this._checkNameLength(constant_name, rule.min, rule.max, 'constant-name');
2932
+ var len_err = this._checkNameLength(
2933
+ constant_name,
2934
+ rule.min,
2935
+ rule.max,
2936
+ "variable-name",
2937
+ );
1634
2938
  if (len_err) {
1635
2939
  return {
1636
2940
  node: node,
@@ -1639,7 +2943,11 @@ Detector.prototype._checkConstantNameForDestructuring = function (constant_name,
1639
2943
  }
1640
2944
 
1641
2945
  // 检查单词长度
1642
- var word_err = this._checkWordLength(constant_name, rule.single_word_len, 'constant-name');
2946
+ var word_err = this._checkWordLength(
2947
+ constant_name,
2948
+ rule.single_word_len,
2949
+ "constant-name",
2950
+ );
1643
2951
  if (word_err) {
1644
2952
  return {
1645
2953
  node: node,
@@ -1648,7 +2956,7 @@ Detector.prototype._checkConstantNameForDestructuring = function (constant_name,
1648
2956
  }
1649
2957
 
1650
2958
  // 检查禁止词汇
1651
- var forbid_err = this._checkForbiddenWords(constant_name, 'constant-name');
2959
+ var forbid_err = this._checkForbiddenWords(constant_name, "constant-name");
1652
2960
  if (forbid_err) {
1653
2961
  return {
1654
2962
  node: node,
@@ -1658,9 +2966,699 @@ Detector.prototype._checkConstantNameForDestructuring = function (constant_name,
1658
2966
 
1659
2967
  return null;
1660
2968
  } catch (error) {
1661
- console.error('检测解构赋值常量名时出错:', error);
2969
+ console.error("检测解构赋值常量名时出错:", error);
1662
2970
  return null;
1663
2971
  }
1664
2972
  };
1665
2973
 
2974
+ /**
2975
+ * 检查属性值命名风格
2976
+ * @param {string} prop_name 属性名
2977
+ * @param {object} val_node 属性值节点
2978
+ * @param {string} rule_type 规则类型
2979
+ * @returns {string|null} 错误信息或null
2980
+ */
2981
+ Detector.prototype._checkPropertyValueStyle = function (
2982
+ prop_name,
2983
+ val_node,
2984
+ rule_type,
2985
+ ) {
2986
+ try {
2987
+ // 首先检查禁止拼接词
2988
+ var forbid_err = this._checkForbiddenWords(prop_name, rule_type);
2989
+ if (forbid_err) {
2990
+ return forbid_err;
2991
+ }
2992
+
2993
+ // 检查属性值类型,智能选择命名规范
2994
+ var is_constant_value = this._isConstantValue(val_node);
2995
+ var is_private_property = prop_name.startsWith("_");
2996
+
2997
+ // 属性值应该允许满足常量或变量命名规则之一即可
2998
+ // 构建允许的命名风格列表
2999
+ var allowed_styles = [];
3000
+
3001
+ // 常量值:允许常量命名规范
3002
+ if (is_constant_value) {
3003
+ allowed_styles.push("UPPER_SNAKE_CASE");
3004
+ }
3005
+
3006
+ // 私有属性:允许私有变量命名规范
3007
+ if (is_private_property) {
3008
+ allowed_styles.push("_snake_case");
3009
+ }
3010
+
3011
+ // 普通属性值:允许变量命名规范
3012
+ allowed_styles.push("snake_case");
3013
+
3014
+ // 检查命名风格 - 只要满足其中一种风格即可
3015
+ for (var i = 0; i < allowed_styles.length; i++) {
3016
+ var style_check = this._validate_naming_style(
3017
+ prop_name,
3018
+ [allowed_styles[i]],
3019
+ rule_type,
3020
+ );
3021
+ if (!style_check) {
3022
+ // 当前风格符合要求,无需报错
3023
+ return null;
3024
+ }
3025
+ }
3026
+
3027
+ // 所有风格都不符合,生成错误信息
3028
+ var style_names = allowed_styles.join("、");
3029
+
3030
+ return (
3031
+ "属性值名'" + prop_name + "'不符合" + style_names + "命名风格中的任何一种"
3032
+ );
3033
+ } catch (error) {
3034
+ console.error("检查属性值命名风格时出错:", error);
3035
+ return null;
3036
+ }
3037
+ };
3038
+
3039
+ /**
3040
+ * 检查属性方法命名风格
3041
+ * @param {string} prop_name 属性名
3042
+ * @param {object} val_node 属性值节点
3043
+ * @param {string} rule_type 规则类型
3044
+ * @returns {string|null} 错误信息或null
3045
+ */
3046
+ Detector.prototype._checkPropertyMethodStyle = function (
3047
+ prop_name,
3048
+ val_node,
3049
+ rule_type,
3050
+ ) {
3051
+ try {
3052
+ // 首先检查禁止拼接词 - 使用 method-name 规则类型
3053
+ var forbid_err = this._checkForbiddenWords(prop_name, "method-name");
3054
+ if (forbid_err) {
3055
+ return forbid_err;
3056
+ }
3057
+
3058
+ // 检查是否为私有属性方法
3059
+ var is_private_method = prop_name.startsWith("_");
3060
+
3061
+ // 属性方法应该允许满足公开方法或私有方法命名规则之一即可
3062
+ // 构建允许的命名风格列表
3063
+ var allowed_styles = [];
3064
+
3065
+ // 私有属性方法:允许私有方法命名规范
3066
+ if (is_private_method) {
3067
+ allowed_styles.push("_camelCase");
3068
+ }
3069
+
3070
+ // 公开属性方法:允许公开方法命名规范
3071
+ allowed_styles.push("camelCase");
3072
+
3073
+ // 检查命名风格 - 只要满足其中一种风格即可
3074
+ for (var i = 0; i < allowed_styles.length; i++) {
3075
+ var style_check = this._validate_naming_style(
3076
+ prop_name,
3077
+ [allowed_styles[i]],
3078
+ rule_type,
3079
+ );
3080
+ if (!style_check) {
3081
+ // 当前风格符合要求,无需报错
3082
+ return null;
3083
+ }
3084
+ }
3085
+
3086
+ // 所有风格都不符合,生成错误信息
3087
+ var style_names = allowed_styles.join("、");
3088
+
3089
+ return (
3090
+ "属性方法名'" + prop_name + "'不符合" + style_names + "命名风格中的任何一种"
3091
+ );
3092
+ } catch (error) {
3093
+ console.error("检查属性方法命名风格时出错:", error);
3094
+ return null;
3095
+ }
3096
+ };
3097
+
3098
+ /**
3099
+ * 检查属性实例类命名风格
3100
+ * @param {string} prop_name 属性名
3101
+ * @param {object} val_node 属性值节点
3102
+ * @param {string} rule_type 规则类型
3103
+ * @returns {string|null} 错误信息或null
3104
+ */
3105
+ Detector.prototype._checkPropertyInstanceClassStyle = function (
3106
+ prop_name,
3107
+ val_node,
3108
+ rule_type,
3109
+ ) {
3110
+ try {
3111
+ // 首先检查禁止拼接词
3112
+ var forbid_err = this._checkForbiddenWords(prop_name, "method-name");
3113
+ if (forbid_err) {
3114
+ return forbid_err;
3115
+ }
3116
+
3117
+ // 检查是否为私有属性实例类
3118
+ var is_private_instance = prop_name.startsWith("_");
3119
+
3120
+ // 属性类实例应该允许满足公开或私有命名规则之一即可
3121
+ // 构建允许的命名风格列表
3122
+ var allowed_styles = [];
3123
+
3124
+ // 私有属性实例类:允许私有实例类命名规范
3125
+ if (is_private_instance) {
3126
+ allowed_styles.push("_camelCase");
3127
+ }
3128
+
3129
+ // 公开属性实例类:允许公开实例类命名规范
3130
+ allowed_styles.push("camelCase");
3131
+
3132
+ // 检查命名风格 - 只要满足其中一种风格即可
3133
+ for (var i = 0; i < allowed_styles.length; i++) {
3134
+ var style_check = this._validate_naming_style(
3135
+ prop_name,
3136
+ [allowed_styles[i]],
3137
+ rule_type,
3138
+ );
3139
+ if (!style_check) {
3140
+ // 当前风格符合要求,无需报错
3141
+ return null;
3142
+ }
3143
+ }
3144
+
3145
+ // 所有风格都不符合,生成错误信息
3146
+ var style_names = allowed_styles.join("、");
3147
+
3148
+ return (
3149
+ "属性实例类名'" +
3150
+ prop_name +
3151
+ "'不符合" +
3152
+ style_names +
3153
+ "命名风格中的任何一种"
3154
+ );
3155
+ } catch (error) {
3156
+ console.error("检查属性实例类命名风格时出错:", error);
3157
+ return null;
3158
+ }
3159
+ };
3160
+
3161
+ /**
3162
+ * 检查属性类命名风格
3163
+ * @param {string} prop_name 属性名
3164
+ * @param {object} val_node 属性值节点
3165
+ * @param {string} rule_type 规则类型
3166
+ * @returns {string|null} 错误信息或null
3167
+ */
3168
+ Detector.prototype._checkPropertyClassStyle = function (
3169
+ prop_name,
3170
+ val_node,
3171
+ rule_type,
3172
+ ) {
3173
+ try {
3174
+ // 首先检查禁止拼接词
3175
+ var forbid_err = this._checkForbiddenWords(prop_name, "class-name");
3176
+ if (forbid_err) {
3177
+ return forbid_err;
3178
+ }
3179
+
3180
+ // 检查是否为私有属性类
3181
+ var is_private_class = prop_name.startsWith("_");
3182
+
3183
+ // 根据属性类类型选择合适的命名规范
3184
+ var allowed_styles = [];
3185
+
3186
+ if (is_private_class) {
3187
+ // 私有属性类:使用私有类命名规范
3188
+ allowed_styles = ["_PascalCase"];
3189
+ } else {
3190
+ // 公开属性类:使用类命名规范
3191
+ allowed_styles = ["PascalCase"];
3192
+ }
3193
+
3194
+ // 检查命名风格
3195
+ var style_err = null;
3196
+ for (var i = 0; i < allowed_styles.length; i++) {
3197
+ var style_check = this._validate_naming_style(
3198
+ prop_name,
3199
+ [allowed_styles[i]],
3200
+ rule_type,
3201
+ );
3202
+ if (!style_check) {
3203
+ // 当前风格符合要求,无需报错
3204
+ return null;
3205
+ }
3206
+ }
3207
+
3208
+ // 所有风格都不符合,生成错误信息
3209
+ var style_names = allowed_styles.join("、");
3210
+
3211
+ return (
3212
+ "属性类名'" + prop_name + "'不符合" + style_names + "命名风格中的任何一种"
3213
+ );
3214
+ } catch (error) {
3215
+ console.error("检查属性类命名风格时出错:", error);
3216
+ return null;
3217
+ }
3218
+ };
3219
+
3220
+ /**
3221
+ * 检查是否为常量值
3222
+ * @param {object} val_node 属性值节点
3223
+ * @returns {boolean} 是否为常量值
3224
+ */
3225
+ Detector.prototype._isConstantValue = function (val_node) {
3226
+ try {
3227
+ if (!val_node) {
3228
+ return false;
3229
+ }
3230
+
3231
+ // 常量值类型:字面量、基础值、不可变值
3232
+ var is_constant = false;
3233
+
3234
+ switch (val_node.type) {
3235
+ case "Literal": // 字面量:数字、字符串、布尔值
3236
+ is_constant = true;
3237
+ break;
3238
+ case "UnaryExpression": // 一元表达式(如 -1, +100)
3239
+ if (val_node.operator === "-" || val_node.operator === "+") {
3240
+ is_constant = true;
3241
+ }
3242
+ break;
3243
+ case "ArrayExpression": // 数组字面量(空数组或包含常量值的数组)
3244
+ if (!val_node.elements || val_node.elements.length === 0) {
3245
+ is_constant = true;
3246
+ } else {
3247
+ // 检查数组元素是否都是常量值
3248
+ is_constant = val_node.elements.every(function (element) {
3249
+ return this._isConstantValue(element);
3250
+ }, this);
3251
+ }
3252
+ break;
3253
+ case "ObjectExpression": // 对象字面量(空对象或包含常量值的对象)
3254
+ if (!val_node.properties || val_node.properties.length === 0) {
3255
+ is_constant = true;
3256
+ } else {
3257
+ // 检查对象属性值是否都是常量值
3258
+ is_constant = val_node.properties.every(function (property) {
3259
+ return (
3260
+ property &&
3261
+ property.value &&
3262
+ this._isConstantValue(property.value)
3263
+ );
3264
+ }, this);
3265
+ }
3266
+ break;
3267
+ case "TemplateLiteral": // 模板字面量(包含常量值的模板)
3268
+ if (!val_node.expressions || val_node.expressions.length === 0) {
3269
+ is_constant = true;
3270
+ } else {
3271
+ // 检查模板表达式是否都是常量值
3272
+ is_constant = val_node.expressions.every(function (expression) {
3273
+ return this._isConstantValue(expression);
3274
+ }, this);
3275
+ }
3276
+ break;
3277
+ default:
3278
+ is_constant = false;
3279
+ }
3280
+
3281
+ return is_constant;
3282
+ } catch (error) {
3283
+ console.error("检查是否为常量值时出错:", error);
3284
+ return false;
3285
+ }
3286
+ };
3287
+
3288
+ /**
3289
+ * 检测参数声明与函数内部引用是否一致
3290
+ * @param {object} context ESLint上下文
3291
+ * @param {object} node 函数节点(FunctionDeclaration、FunctionExpression、ArrowFunctionExpression)
3292
+ */
3293
+ Detector.prototype._checkParamReferences = function (context, node) {
3294
+ try {
3295
+ // 获取函数参数列表
3296
+ var params = node.params || [];
3297
+ if (params.length === 0) {
3298
+ return; // 没有参数,无需检查
3299
+ }
3300
+
3301
+ // 提取参数名
3302
+ var param_names = [];
3303
+ for (var i = 0; i < params.length; i++) {
3304
+ var param = params[i];
3305
+ if (param.type === 'Identifier') {
3306
+ param_names.push(param.name);
3307
+ }
3308
+ // 处理解构参数
3309
+ else if (param.type === 'ObjectPattern' && param.properties) {
3310
+ for (var p = 0; p < param.properties.length; p++) {
3311
+ var property = param.properties[p];
3312
+ if (property.key && property.key.type === 'Identifier') {
3313
+ param_names.push(property.key.name);
3314
+ }
3315
+ }
3316
+ }
3317
+ }
3318
+
3319
+ if (param_names.length === 0) {
3320
+ return; // 没有有效的参数名
3321
+ }
3322
+
3323
+ // 分析函数体内的标识符引用
3324
+ var body_identifiers = this._extractIdentifiers(node.body);
3325
+
3326
+ // 检查每个参数是否被正确引用
3327
+ for (var j = 0; j < param_names.length; j++) {
3328
+ var param_name = param_names[j];
3329
+ var is_referenced = false;
3330
+ var reference_errors = [];
3331
+
3332
+ // 检查参数是否被引用
3333
+ for (var k = 0; k < body_identifiers.length; k++) {
3334
+ var identifier = body_identifiers[k];
3335
+
3336
+ // 检查标识符名称与参数名的相似性
3337
+ if (this._isSimilarIdentifier(identifier.name, param_name)) {
3338
+ if (identifier.name === param_name) {
3339
+ // 完全匹配,正确引用
3340
+ is_referenced = true;
3341
+ break;
3342
+ } else {
3343
+ // 相似但不完全匹配,可能是拼写错误
3344
+ reference_errors.push({
3345
+ node: identifier.node,
3346
+ actual_name: identifier.name,
3347
+ expected_name: param_name
3348
+ });
3349
+ }
3350
+ }
3351
+ }
3352
+
3353
+ // 如果没有正确引用但有相似引用,报告错误
3354
+ if (!is_referenced && reference_errors.length > 0) {
3355
+ for (var m = 0; m < reference_errors.length; m++) {
3356
+ var error = reference_errors[m];
3357
+
3358
+ // 检查参数名是否符合命名规范,如果不符合,使用符合规范的名称
3359
+ var param_name_err = this._checkParamName(param_name, null);
3360
+ var recommended_name = param_name;
3361
+
3362
+ if (param_name_err) {
3363
+ var fix_suggestion = this._getFixSuggestion(param_name, 'param-name', param_name_err.message);
3364
+ if (fix_suggestion && fix_suggestion.fixed_name !== param_name) {
3365
+ recommended_name = fix_suggestion.fixed_name;
3366
+ }
3367
+ }
3368
+
3369
+ context.report({
3370
+ node: error.node,
3371
+ message: "参数引用不一致:声明为 '" + param_name + "',但引用为 '" + error.actual_name + "',建议使用: " + recommended_name,
3372
+ fix: function(fixer) {
3373
+ return fixer.replaceText(error.node, recommended_name);
3374
+ }
3375
+ });
3376
+ }
3377
+ }
3378
+ }
3379
+ } catch (error) {
3380
+ console.error("检查参数引用一致性时出错:", error);
3381
+ }
3382
+ };
3383
+
3384
+ /**
3385
+ * 提取函数体内的所有标识符
3386
+ * @param {object} node AST节点
3387
+ * @returns {array} 标识符数组
3388
+ */
3389
+ Detector.prototype._extractIdentifiers = function (node) {
3390
+ var identifiers = [];
3391
+
3392
+ if (!node) {
3393
+ return identifiers;
3394
+ }
3395
+
3396
+ var visited_nodes = new Set(); // 防止循环引用
3397
+ var max_depth = 100; // 最大递归深度
3398
+
3399
+ // 递归遍历AST节点,提取标识符
3400
+ function traverse(current_node, depth) {
3401
+ if (!current_node || depth > max_depth) return;
3402
+
3403
+ // 防止循环引用
3404
+ if (visited_nodes.has(current_node)) return;
3405
+ visited_nodes.add(current_node);
3406
+
3407
+ // 如果是标识符节点,添加到结果中
3408
+ if (current_node.type === 'Identifier') {
3409
+ identifiers.push({
3410
+ name: current_node.name,
3411
+ node: current_node
3412
+ });
3413
+ return;
3414
+ }
3415
+
3416
+ // 遍历子节点
3417
+ var child_nodes = [];
3418
+
3419
+ switch (current_node.type) {
3420
+ case 'FunctionExpression':
3421
+ case 'FunctionDeclaration':
3422
+ case 'ArrowFunctionExpression':
3423
+ // 跳过函数定义,避免递归到参数
3424
+ if (current_node.body) {
3425
+ traverse(current_node.body, depth + 1);
3426
+ }
3427
+ break;
3428
+
3429
+ case 'BlockStatement':
3430
+ child_nodes = current_node.body || [];
3431
+ break;
3432
+
3433
+ case 'VariableDeclaration':
3434
+ child_nodes = current_node.declarations || [];
3435
+ break;
3436
+
3437
+ case 'VariableDeclarator':
3438
+ if (current_node.id) traverse(current_node.id, depth + 1);
3439
+ if (current_node.init) traverse(current_node.init, depth + 1);
3440
+ break;
3441
+
3442
+ case 'ExpressionStatement':
3443
+ if (current_node.expression) traverse(current_node.expression, depth + 1);
3444
+ break;
3445
+
3446
+ case 'CallExpression':
3447
+ if (current_node.callee) traverse(current_node.callee, depth + 1);
3448
+ child_nodes = current_node.arguments || [];
3449
+ break;
3450
+
3451
+ case 'MemberExpression':
3452
+ if (current_node.object) traverse(current_node.object, depth + 1);
3453
+ if (current_node.property) traverse(current_node.property, depth + 1);
3454
+ break;
3455
+
3456
+ case 'ReturnStatement':
3457
+ if (current_node.argument) traverse(current_node.argument, depth + 1);
3458
+ break;
3459
+
3460
+ case 'BinaryExpression':
3461
+ case 'LogicalExpression':
3462
+ if (current_node.left) traverse(current_node.left, depth + 1);
3463
+ if (current_node.right) traverse(current_node.right, depth + 1);
3464
+ break;
3465
+
3466
+ case 'UnaryExpression':
3467
+ if (current_node.argument) traverse(current_node.argument, depth + 1);
3468
+ break;
3469
+
3470
+ case 'ConditionalExpression':
3471
+ if (current_node.test) traverse(current_node.test, depth + 1);
3472
+ if (current_node.consequent) traverse(current_node.consequent, depth + 1);
3473
+ if (current_node.alternate) traverse(current_node.alternate, depth + 1);
3474
+ break;
3475
+
3476
+ case 'ArrayExpression':
3477
+ child_nodes = current_node.elements || [];
3478
+ break;
3479
+
3480
+ case 'ObjectExpression':
3481
+ child_nodes = current_node.properties || [];
3482
+ break;
3483
+
3484
+ case 'Property':
3485
+ if (current_node.key) traverse(current_node.key, depth + 1);
3486
+ if (current_node.value) traverse(current_node.value, depth + 1);
3487
+ break;
3488
+
3489
+ case 'Literal':
3490
+ // 字面量,跳过
3491
+ break;
3492
+
3493
+ default:
3494
+ // 对于其他节点类型,只遍历已知的AST属性,避免无限递归
3495
+ var ast_props = ['body', 'declarations', 'expression', 'callee', 'arguments',
3496
+ 'object', 'property', 'argument', 'left', 'right', 'test',
3497
+ 'consequent', 'alternate', 'elements', 'properties', 'key', 'value'];
3498
+
3499
+ for (var i = 0; i < ast_props.length; i++) {
3500
+ var prop = ast_props[i];
3501
+ var value = current_node[prop];
3502
+
3503
+ if (Array.isArray(value)) {
3504
+ for (var j = 0; j < value.length; j++) {
3505
+ if (value[j] && typeof value[j] === 'object' && value[j].type) {
3506
+ traverse(value[j], depth + 1);
3507
+ }
3508
+ }
3509
+ } else if (value && typeof value === 'object' && value.type) {
3510
+ traverse(value, depth + 1);
3511
+ }
3512
+ }
3513
+ break;
3514
+ }
3515
+
3516
+ // 遍历子节点数组
3517
+ for (var k = 0; k < child_nodes.length; k++) {
3518
+ if (child_nodes[k] && typeof child_nodes[k] === 'object' && child_nodes[k].type) {
3519
+ traverse(child_nodes[k], depth + 1);
3520
+ }
3521
+ }
3522
+ }
3523
+
3524
+ traverse(node, 0);
3525
+ return identifiers;
3526
+ };
3527
+
3528
+ /**
3529
+ * 检查两个标识符是否相似(用于检测拼写错误)
3530
+ * @param {string} actual_name 实际使用的名称
3531
+ * @param {string} expected_name 期望的名称
3532
+ * @returns {boolean} 是否相似
3533
+ */
3534
+ Detector.prototype._isSimilarIdentifier = function (actual_name, expected_name) {
3535
+ if (actual_name === expected_name) {
3536
+ return true;
3537
+ }
3538
+
3539
+ // 检查大小写不一致的情况
3540
+ if (actual_name.toLowerCase() === expected_name.toLowerCase()) {
3541
+ return true;
3542
+ }
3543
+
3544
+ // 检查常见的拼写错误模式
3545
+ var common_patterns = [
3546
+ // 下划线相关错误
3547
+ { pattern: /_/g, replacement: '' }, // 忘记下划线
3548
+ { pattern: /([a-z])([A-Z])/g, replacement: '$1_$2' }, // 驼峰转蛇形
3549
+ { pattern: /_([a-z])/g, replacement: function(match, p1) { return p1.toUpperCase(); } } // 蛇形转驼峰
3550
+ ];
3551
+
3552
+ for (var i = 0; i < common_patterns.length; i++) {
3553
+ var pattern = common_patterns[i];
3554
+ var transformed_actual = actual_name.replace(pattern.pattern, pattern.replacement);
3555
+ var transformed_expected = expected_name.replace(pattern.pattern, pattern.replacement);
3556
+
3557
+ if (transformed_actual === transformed_expected ||
3558
+ transformed_actual.toLowerCase() === transformed_expected.toLowerCase()) {
3559
+ return true;
3560
+ }
3561
+ }
3562
+
3563
+ // 检查编辑距离(简单的相似度检查)
3564
+ var distance = this._levenshteinDistance(actual_name.toLowerCase(), expected_name.toLowerCase());
3565
+ var max_length = Math.max(actual_name.length, expected_name.length);
3566
+ var similarity = 1 - (distance / max_length);
3567
+
3568
+ return similarity > 0.7; // 相似度超过70%认为相似
3569
+ };
3570
+
3571
+ /**
3572
+ * 计算两个字符串的编辑距离(Levenshtein距离)
3573
+ * @param {string} a 字符串A
3574
+ * @param {string} b 字符串B
3575
+ * @returns {number} 编辑距离
3576
+ */
3577
+ Detector.prototype._levenshteinDistance = function (a, b) {
3578
+ if (a.length === 0) return b.length;
3579
+ if (b.length === 0) return a.length;
3580
+
3581
+ var matrix = [];
3582
+
3583
+ // 初始化矩阵
3584
+ for (var i = 0; i <= b.length; i++) {
3585
+ matrix[i] = [i];
3586
+ }
3587
+
3588
+ for (var j = 0; j <= a.length; j++) {
3589
+ matrix[0][j] = j;
3590
+ }
3591
+
3592
+ // 计算编辑距离
3593
+ for (i = 1; i <= b.length; i++) {
3594
+ for (j = 1; j <= a.length; j++) {
3595
+ if (b.charAt(i - 1) === a.charAt(j - 1)) {
3596
+ matrix[i][j] = matrix[i - 1][j - 1];
3597
+ } else {
3598
+ matrix[i][j] = Math.min(
3599
+ matrix[i - 1][j - 1] + 1, // 替换
3600
+ matrix[i][j - 1] + 1, // 插入
3601
+ matrix[i - 1][j] + 1 // 删除
3602
+ );
3603
+ }
3604
+ }
3605
+ }
3606
+
3607
+ return matrix[b.length][a.length];
3608
+ };
3609
+
3610
+ /**
3611
+ * 检查是否为 module.exports 中的属性
3612
+ * @param {object} node 属性节点
3613
+ * @param {object} parent_node 父节点信息
3614
+ * @returns {boolean} 是否为 module.exports 中的属性
3615
+ */
3616
+ Detector.prototype._isModuleExportsProperty = function (node, parent_node) {
3617
+ try {
3618
+ // 处理新的父节点信息结构(包含node和parent属性)
3619
+ var actual_parent_node = parent_node;
3620
+ if (parent_node && typeof parent_node === "object" && parent_node.node) {
3621
+ actual_parent_node = parent_node.node;
3622
+ }
3623
+
3624
+ if (!node || !actual_parent_node) {
3625
+ return false;
3626
+ }
3627
+
3628
+ // 检查父节点是否为 ObjectExpression(对象字面量)
3629
+ if (actual_parent_node.type === "ObjectExpression") {
3630
+ // 检查父节点的父节点是否为 AssignmentExpression
3631
+ var actual_parent_parent =
3632
+ parent_node && typeof parent_node === "object" && parent_node.parent
3633
+ ? parent_node.parent
3634
+ : null;
3635
+
3636
+ if (
3637
+ actual_parent_parent &&
3638
+ actual_parent_parent.type === "AssignmentExpression"
3639
+ ) {
3640
+ // 检查赋值表达式的左侧是否为 module.exports
3641
+ var left = actual_parent_parent.left;
3642
+ if (
3643
+ left &&
3644
+ left.type === "MemberExpression" &&
3645
+ left.object &&
3646
+ left.object.type === "Identifier" &&
3647
+ left.object.name === "module" &&
3648
+ left.property &&
3649
+ left.property.type === "Identifier" &&
3650
+ left.property.name === "exports"
3651
+ ) {
3652
+ return true;
3653
+ }
3654
+ }
3655
+ }
3656
+
3657
+ return false;
3658
+ } catch (error) {
3659
+ console.error("检查是否为 module.exports 中的属性时出错:", error);
3660
+ return false;
3661
+ }
3662
+ };
3663
+
1666
3664
  module.exports = { Detector };