mm_eslint 1.4.3 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/detector.js CHANGED
@@ -1,3664 +1,1239 @@
1
- /**
2
- * 命名规范检测器类
3
- */
4
- class Detector {
5
- /**
6
- * 构造函数
7
- * @param {object} config 配置对象
8
- */
9
- constructor(config) {
10
- // 直接将传入的配置对象赋值,确保原型方法不被丢失
11
- this.config = config;
12
-
13
- // 添加命名类型的中文描述
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": "属性值名",
25
- };
26
- }
27
- }
28
-
29
- /**
30
- * 检测类名
31
- * @param {string} class_name 类名
32
- * @param {object} node AST节点
33
- * @returns {object|null} 错误信息或null
34
- */
35
- Detector.prototype._checkClassName = function (class_name, node) {
36
- try {
37
- var rule = this.config.getRule("class-name");
38
- if (!rule) {
39
- return null;
40
- }
41
-
42
- // 检查是否为忽略词
43
- if (this._isIgnoredWord(class_name, "class-name")) {
44
- return null;
45
- }
46
-
47
- // 检查命名风格
48
- var style_err = this._validate_naming_style(
49
- class_name,
50
- rule.styles,
51
- "class-name",
52
- );
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
- }
63
- return {
64
- node: node,
65
- message: error_message,
66
- rule_type: "class-name",
67
- };
68
- }
69
-
70
- // 检查并推荐更合适的词汇
71
- var rec_err = this._checkAndRecommend(class_name, "class-name");
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
-
79
- return {
80
- node: node,
81
- message: "类名'" + class_name + "',建议使用: " + recommended_full_name,
82
- rule_type: "class-name",
83
- };
84
- }
85
-
86
- // 检查长度
87
- var len_err = this._checkNameLength(
88
- class_name,
89
- rule.min,
90
- rule.max,
91
- "class-name",
92
- );
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
- }
103
- return {
104
- node: node,
105
- message: error_message,
106
- rule_type: "class-name",
107
- };
108
- }
109
-
110
- // 检查单词长度
111
- var word_err = this._checkWordLength(
112
- class_name,
113
- rule.single_word_len,
114
- "class-name",
115
- );
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
-
130
- return {
131
- node: node,
132
- message: error_message,
133
- rule_type: "class-name",
134
- };
135
- }
136
-
137
- // 检查禁止词汇
138
- var forbid_err = this._checkForbiddenWords(class_name, "class-name");
139
- if (forbid_err) {
140
- return {
141
- node: node,
142
- message: forbid_err,
143
- rule_type: "class-name",
144
- };
145
- }
146
-
147
- return null;
148
- } catch (error) {
149
- console.error("检测类名时出错:", error);
150
- return null;
151
- }
152
- };
153
-
154
- /**
155
- * 检测方法名
156
- * @param {string} method_name 方法名
157
- * @param {object} node AST节点
158
- * @returns {object|null} 错误信息或null
159
- */
160
- Detector.prototype._checkMethodName = function (method_name, node) {
161
- try {
162
- var rule = this.config.getRule("method-name");
163
- if (!rule) {
164
- return null;
165
- }
166
-
167
- // 检查是否为忽略词(在所有检测之前)
168
- if (this._isIgnoredWord(method_name, "method-name")) {
169
- return null;
170
- }
171
-
172
- // 检查命名风格(支持公开方法和私有方法)
173
- var style_err = null;
174
- if (method_name.startsWith("_")) {
175
- // 私有方法:检查是否符合私有方法命名规范
176
- style_err = this._validate_naming_style(
177
- method_name,
178
- ["_camelCase"],
179
- "method-name",
180
- );
181
- } else {
182
- // 公开方法:检查是否符合公开方法命名规范
183
- style_err = this._validate_naming_style(
184
- method_name,
185
- rule.styles,
186
- "method-name",
187
- );
188
- }
189
-
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
- }
200
- return {
201
- node: node,
202
- message: error_message,
203
- };
204
- }
205
-
206
- // 检查长度
207
- var len_err = this._checkNameLength(
208
- method_name,
209
- rule.min,
210
- rule.max,
211
- "method-name",
212
- );
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
- }
223
- return {
224
- node: node,
225
- message: error_message,
226
- };
227
- }
228
-
229
- // 检查单词长度
230
- var word_err = this._checkWordLength(
231
- method_name,
232
- rule.single_word_len,
233
- "method-name",
234
- );
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
- }
248
- return {
249
- node: node,
250
- message: error_message,
251
- };
252
- }
253
-
254
- // 检查禁止词汇
255
- var forbid_err = this._checkForbiddenWords(method_name, "method-name");
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
- }
266
- return {
267
- node: node,
268
- message: error_message,
269
- };
270
- }
271
-
272
- // 如果没有错误但有推荐建议,返回优化建议
273
- var smart_abbreviation = this._getSmartAbbreviation(
274
- method_name,
275
- "method-name",
276
- );
277
- if (smart_abbreviation && smart_abbreviation !== method_name) {
278
- return {
279
- node: node,
280
- message:
281
- "方法名'" +
282
- method_name +
283
- "'不是行业通用名,建议使用: " +
284
- smart_abbreviation,
285
- fix: function (fixer) {
286
- return fixer.replaceText(node, smart_abbreviation);
287
- },
288
- };
289
- }
290
-
291
- return null;
292
- } catch (error) {
293
- console.error("检测方法名时出错:", error);
294
- return null;
295
- }
296
- };
297
-
298
- /**
299
- * 检测函数名
300
- * @param {string} function_name 函数名
301
- * @param {object} node AST节点
302
- * @returns {object|null} 错误信息或null
303
- */
304
- Detector.prototype._checkFunctionName = function (function_name, node) {
305
- try {
306
- var rule = this.config.getRule("function-name");
307
- if (!rule) {
308
- return null;
309
- }
310
-
311
- // 检查是否为忽略词
312
- if (this._isIgnoredWord(function_name, "function-name")) {
313
- return null;
314
- }
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
-
340
- // 检查命名风格
341
- var style_err = this._validate_naming_style(
342
- function_name,
343
- rule.styles,
344
- "function-name",
345
- );
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
- }
356
- return {
357
- node: node,
358
- message: error_message,
359
- };
360
- }
361
-
362
- // 检查长度
363
- var len_err = this._checkNameLength(
364
- function_name,
365
- rule.min,
366
- rule.max,
367
- "function-name",
368
- );
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
- }
379
- return {
380
- node: node,
381
- message: error_message,
382
- };
383
- }
384
-
385
- // 检查单词长度
386
- var word_err = this._checkWordLength(
387
- function_name,
388
- rule.single_word_len,
389
- "function-name",
390
- );
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
- }
404
- return {
405
- node: node,
406
- message: error_message,
407
- };
408
- }
409
-
410
- // 检查禁止词汇
411
- var forbid_err = this._checkForbiddenWords(function_name, "function-name");
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
- }
422
- return {
423
- node: node,
424
- message: error_message,
425
- };
426
- }
427
-
428
- // 检查并推荐更合适的词汇(作为命名风格检查的补充)
429
- var recommend_info = this._checkAndRecommend(
430
- function_name,
431
- "function-name",
432
- );
433
- if (recommend_info) {
434
- // 如果有推荐建议,提示可以使用更简洁的词汇
435
- return {
436
- node: node,
437
- message:
438
- "函数名'" +
439
- function_name +
440
- "'建议使用: " +
441
- recommend_info.recommended_name,
442
- };
443
- }
444
-
445
- return null;
446
- } catch (error) {
447
- console.error("检测函数名时出错:", error);
448
- return null;
449
- }
450
- };
451
-
452
- /**
453
- * 检测变量名
454
- * @param {string} variable_name 变量名
455
- * @param {object} node AST节点
456
- * @returns {object|null} 错误信息或null
457
- */
458
- Detector.prototype._checkVariableName = function (variable_name, node) {
459
- try {
460
- var rule = this.config.getRule("variable-name");
461
- if (!rule) {
462
- return null;
463
- }
464
-
465
- // 检查是否为忽略词
466
- if (this._isIgnoredWord(variable_name, "variable-name")) {
467
- return null;
468
- }
469
-
470
- // 检查命名风格
471
- var style_err = this._validate_naming_style(
472
- variable_name,
473
- rule.styles,
474
- "variable-name",
475
- );
476
- if (style_err) {
477
- return {
478
- node: node,
479
- message: style_err,
480
- };
481
- }
482
-
483
- // 检查长度
484
- var len_err = this._checkNameLength(
485
- variable_name,
486
- rule.min,
487
- rule.max,
488
- "variable-name",
489
- );
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
-
504
- return {
505
- node: node,
506
- message: error_message,
507
- };
508
- }
509
-
510
- // 检查单词长度
511
- var word_err = this._checkWordLength(
512
- variable_name,
513
- rule.single_word_len,
514
- "variable-name",
515
- );
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
- }
529
- return {
530
- node: node,
531
- message: error_message,
532
- };
533
- }
534
-
535
- // 检查禁止词汇
536
- var forbid_err = this._checkForbiddenWords(variable_name, "variable-name");
537
- if (forbid_err) {
538
- return {
539
- node: node,
540
- message: forbid_err,
541
- };
542
- }
543
-
544
- return null;
545
- } catch (error) {
546
- console.error("检测变量名时出错:", error);
547
- return null;
548
- }
549
- };
550
-
551
- /**
552
- * 检测参数名
553
- * @param {string} param_name 参数名
554
- * @param {object} node AST节点
555
- * @returns {object|null} 错误信息或null
556
- */
557
- Detector.prototype._checkParamName = function (param_name, node) {
558
- try {
559
- var rule = this.config.getRule("param-name");
560
- if (!rule) {
561
- return null;
562
- }
563
-
564
- // 检查是否为忽略词
565
- if (this._isIgnoredWord(param_name, "param-name")) {
566
- return null;
567
- }
568
-
569
- // 检查命名风格
570
- var style_err = this._validate_naming_style(
571
- param_name,
572
- rule.styles,
573
- "param-name",
574
- );
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
- }
585
- return {
586
- node: node,
587
- message: error_message,
588
- };
589
- }
590
-
591
- // 检查长度
592
- var len_err = this._checkNameLength(
593
- param_name,
594
- rule.min,
595
- rule.max,
596
- "param-name",
597
- );
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
-
612
- return {
613
- node: node,
614
- message: error_message,
615
- };
616
- }
617
-
618
- // 检查单词长度
619
- var word_err = this._checkWordLength(
620
- param_name,
621
- rule.single_word_len,
622
- "param-name",
623
- );
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
- }
637
- return {
638
- node: node,
639
- message: error_message,
640
- };
641
- }
642
-
643
- // 检查禁止词汇
644
- var forbid_err = this._checkForbiddenWords(param_name, "param-name");
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
- }
655
- return {
656
- node: node,
657
- message: error_message,
658
- };
659
- }
660
-
661
- return null;
662
- } catch (error) {
663
- console.error("检测参数名时出错:", error);
664
- return null;
665
- }
666
- };
667
-
668
- /**
669
- * 检测常量名
670
- * @param {string} constant_name 常量名
671
- * @param {object} node AST节点
672
- * @param {object} val_node 值节点(用于识别基础值)
673
- * @returns {object|null} 错误信息或null
674
- */
675
- Detector.prototype._checkConstantName = function (
676
- constant_name,
677
- node,
678
- val_node,
679
- ) {
680
- try {
681
- // 检查是否为解构导入(从模块导入的变量)
682
- var is_destructured_import = this._isDestructuredImport(node);
683
-
684
- // 如果是解构导入,则不进行命名检测
685
- if (is_destructured_import) {
686
- return null;
687
- }
688
-
689
- // 检查是否应该使用let而不是const
690
- var should_use_let = this._shouldUseLetInsteadOfConst(node, val_node);
691
-
692
- // 如果应该使用let,则提示开发者
693
- if (should_use_let) {
694
- return {
695
- node: node,
696
- message: `变量'${constant_name}'应该使用let而不是const声明,因为它不是真正的常量`,
697
- };
698
- }
699
-
700
- // 根据值类型确定应该应用的命名规则
701
- var rule_type = "constant-name"; // 默认使用常量命名规则
702
- var allowed_styles = [];
703
-
704
- // 检查是否为函数表达式或箭头函数
705
- if (
706
- val_node &&
707
- (val_node.type === "FunctionExpression" ||
708
- val_node.type === "ArrowFunctionExpression")
709
- ) {
710
- rule_type = "function-name";
711
- }
712
- // 检查是否为类表达式
713
- else if (val_node && val_node.type === "ClassExpression") {
714
- rule_type = "class-name";
715
- }
716
- // 检查是否为类实例(new表达式)
717
- else if (val_node && val_node.type === "NewExpression") {
718
- rule_type = "function-name"; // 类实例使用函数命名规则(camelCase)
719
- }
720
- // 检查是否为基础值类型
721
- else if (val_node && this._isBaseValue(val_node)) {
722
- rule_type = "constant-name";
723
- }
724
- // 检查是否为其他复杂类型(函数调用、变量引用等)
725
- else if (val_node && this._isComplexType(val_node)) {
726
- // 其他复杂类型不进行命名检测
727
- return null;
728
- }
729
- // 其他情况不进行命名检测
730
- else {
731
- return null;
732
- }
733
-
734
- // 获取对应的命名规则
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);
757
- if (!rule) {
758
- return null;
759
- }
760
-
761
- // 检查是否为忽略词
762
- if (this._isIgnoredWord(constant_name, rule_type)) {
763
- return null;
764
- }
765
-
766
- // 检查命名风格
767
- var style_err = this._validate_naming_style(
768
- constant_name,
769
- rule.styles,
770
- rule_type,
771
- );
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
-
783
- return {
784
- node: node,
785
- message: error_message,
786
- rule_type: rule_type, // 返回正确的规则类型
787
- };
788
- }
789
-
790
- // 检查长度
791
- var len_err = this._checkNameLength(
792
- constant_name,
793
- rule.min,
794
- rule.max,
795
- rule_type,
796
- );
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
-
808
- return {
809
- node: node,
810
- message: error_message,
811
- rule_type: rule_type, // 返回正确的规则类型
812
- };
813
- }
814
-
815
- // 检查单词长度
816
- var word_err = this._checkWordLength(
817
- constant_name,
818
- rule.single_word_len,
819
- rule_type,
820
- );
821
- if (word_err) {
822
- return {
823
- node: node,
824
- message: word_err,
825
- rule_type: rule_type, // 返回正确的规则类型
826
- };
827
- }
828
-
829
- // 检查禁止词汇
830
- var forbid_err = this._checkForbiddenWords(constant_name, rule_type);
831
- if (forbid_err) {
832
- return {
833
- node: node,
834
- message: forbid_err,
835
- rule_type: rule_type, // 返回正确的规则类型
836
- };
837
- }
838
-
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
-
861
- return {
862
- node: node,
863
- message:
864
- name_type_text +
865
- "'" +
866
- constant_name +
867
- "'长度过长,最大长度为20字符,建议使用: " +
868
- recommend_info.recommended_name,
869
- rule_type: rule_type, // 返回正确的规则类型
870
- };
871
- }
872
-
873
- return null;
874
- } catch (error) {
875
- console.error("检测常量名时出错:", error);
876
- return null;
877
- }
878
- };
879
-
880
- /**
881
- * 验证命名风格
882
- * @param {string} name 名称
883
- * @param {Array} styles 允许的风格列表
884
- * @param {string} name_type 名称类型
885
- * @returns {string|null} 错误信息或null
886
- */
887
- Detector.prototype._validate_naming_style = function (name, styles, name_type) {
888
- if (!name || !styles || !Array.isArray(styles)) {
889
- return null;
890
- }
891
-
892
- for (var i = 0; i < styles.length; i++) {
893
- var style = styles[i];
894
- var regex = this.config.getRegex(style);
895
- if (regex && regex.test(name)) {
896
- return null;
897
- }
898
- }
899
-
900
- var style_names = styles.join("或");
901
-
902
- var name_type_desc = this.config.name_type_map[name_type] || "名称";
903
-
904
- return name_type_desc + "'" + name + "'不符合" + style_names + "命名风格";
905
- };
906
-
907
- /**
908
- * 检查名称长度
909
- * @param {string} name 名称
910
- * @param {number} min 最小长度
911
- * @param {number} max 最大长度
912
- * @returns {string|null} 错误信息或null
913
- */
914
- Detector.prototype._checkNameLength = function (name, min, max, name_type) {
915
- if (!name) {
916
- return "名称不能为空";
917
- }
918
-
919
- var name_type_desc = this.config.name_type_map[name_type] || "名称";
920
- var len = name.length;
921
- if (len < min) {
922
- return name_type_desc + "'" + name + "'长度过短,最小长度为" + min + "字符";
923
- }
924
-
925
- if (len > max) {
926
- return name_type_desc + "'" + name + "'长度过长,最大长度为" + max + "字符";
927
- }
928
-
929
- return null;
930
- };
931
-
932
- /**
933
- * 检查单词长度
934
- * @param {string} name 名称
935
- * @param {number} max_word_len 最大单词长度
936
- * @returns {string|null} 错误信息或null
937
- */
938
- Detector.prototype._checkWordLength = function (name, max_word_len, name_type) {
939
- if (!name || !max_word_len) {
940
- return null;
941
- }
942
-
943
- var name_type_desc = this.config.name_type_map[name_type] || "名称";
944
-
945
- // 处理私有标识符(开头的下划线)
946
- var processed_name = name;
947
- var has_private_prefix = false;
948
-
949
- if (name.startsWith("_")) {
950
- has_private_prefix = true;
951
- processed_name = name.substring(1); // 去掉开头的下划线
952
- }
953
-
954
- // 分割单词(根据命名风格)
955
- var words = [];
956
-
957
- if (processed_name.includes("_")) {
958
- words = processed_name.split("_");
959
- } else if (processed_name.includes("-")) {
960
- words = processed_name.split("-");
961
- } else {
962
- // 驼峰命名法分割(保持原词大小写)
963
- words = processed_name.split(/(?=[A-Z])/);
964
- }
965
-
966
- // 如果存在私有标识符,添加空字符串表示私有标识符(不检查长度)
967
- if (has_private_prefix) {
968
- words.unshift("_");
969
- }
970
-
971
- // 过滤空字符串
972
- words = words.filter(function (word) {
973
- return word && word.length > 0;
974
- });
975
-
976
- // 如果是单个单词,则不检测单词长度
977
- if (words.length <= 1) {
978
- return null;
979
- }
980
-
981
- for (var i = 0; i < words.length; i++) {
982
- var word = words[i];
983
- // 跳过空字符串和私有标识符(单个下划线)
984
- if (!word || word === "_") {
985
- continue;
986
- }
987
-
988
- if (word.length > max_word_len) {
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;
994
- }
995
-
996
- return (
997
- name_type_desc +
998
- "'" +
999
- name +
1000
- "'中的单词'" +
1001
- word +
1002
- "'过长,最大长度为" +
1003
- max_word_len +
1004
- "字符" +
1005
- recommendation_text
1006
- );
1007
- }
1008
- }
1009
-
1010
- return null;
1011
- };
1012
-
1013
- /**
1014
- * 检查禁止词汇
1015
- * @param {string} name 名称
1016
- * @param {string} name_type 名称类型
1017
- * @returns {string|null} 错误信息或null
1018
- */
1019
- Detector.prototype._checkForbiddenWords = function (name, name_type) {
1020
- if (!name || !name_type) {
1021
- return null;
1022
- }
1023
-
1024
- var forbidden_words = this.config.getForbiddenWords(name_type);
1025
- if (!forbidden_words || !Array.isArray(forbidden_words)) {
1026
- return null;
1027
- }
1028
-
1029
- var name_type_desc = this.config.name_type_map[name_type] || "名称";
1030
- var name_lower = name.toLowerCase();
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
-
1041
- // 如果名称本身就是禁止词汇(即单个单词),则允许使用
1042
- for (var i = 0; i < forbidden_words.length; i++) {
1043
- var forbidden_word = forbidden_words[i].toLowerCase();
1044
- if (name_lower === forbidden_word) {
1045
- return null; // 单个单词允许使用
1046
- }
1047
- }
1048
-
1049
- // 按单词边界分割名称(使用原始名称进行拆分,保持大小写信息)
1050
- var words = this._splitNameIntoWords(name);
1051
-
1052
- // 将拆分后的单词转换为小写进行比较
1053
- var words_lower = words.map(function(word) {
1054
- return word.toLowerCase();
1055
- });
1056
-
1057
- // 检查每个单词是否在禁止词汇列表中
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];
1065
- // 跳过空字符串和单个字符
1066
- if (!word || word.length <= 1) {
1067
- continue;
1068
- }
1069
-
1070
- for (var j = 0; j < forbidden_words.length; j++) {
1071
- var forbidden_word = forbidden_words[j].toLowerCase();
1072
- if (word === forbidden_word) {
1073
- // 记录找到的禁用词,但不立即返回
1074
- if (found_forbidden_words.indexOf(forbidden_word) === -1) {
1075
- found_forbidden_words.push(forbidden_word);
1076
- }
1077
- }
1078
- }
1079
- }
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
-
1098
- return null;
1099
- };
1100
-
1101
- /**
1102
- * 按单词边界分割名称
1103
- * @param {string} name 名称
1104
- * @returns {Array} 单词数组
1105
- */
1106
- Detector.prototype._splitNameIntoWords = function (name) {
1107
- if (!name) {
1108
- return [];
1109
- }
1110
-
1111
- var words = [];
1112
- var processed_name = name;
1113
- var has_private_prefix = false;
1114
-
1115
- // 处理私有标识符(开头的下划线)
1116
- if (name.startsWith("_")) {
1117
- has_private_prefix = true;
1118
- processed_name = name.substring(1); // 去掉开头的下划线
1119
- }
1120
-
1121
- // 如果移除_后为空,说明只有_,直接返回
1122
- if (!processed_name) {
1123
- return ["_"];
1124
- }
1125
-
1126
- // 根据命名风格分割单词
1127
- if (processed_name.includes("_")) {
1128
- words = processed_name.split("_");
1129
- } else if (processed_name.includes("-")) {
1130
- words = processed_name.split("-");
1131
- } else {
1132
- // 驼峰命名法分割(保持原词大小写)
1133
- words = processed_name.split(/(?=[A-Z])/);
1134
- }
1135
-
1136
- // 如果存在私有标识符,添加下划线作为第一个单词
1137
- if (has_private_prefix) {
1138
- words.unshift("_");
1139
- }
1140
-
1141
- // 过滤空字符串
1142
- words = words.filter(function (word) {
1143
- return word && word.length > 0;
1144
- });
1145
-
1146
- return words;
1147
- };
1148
-
1149
- /**
1150
- * 检查是否为第三方库的配置参数
1151
- * @param {object} node AST节点
1152
- * @param {object} parent_node 父节点
1153
- * @returns {boolean} 是否为第三方库配置参数
1154
- */
1155
- Detector.prototype._isThirdPartyConfigProperty = function (node, parent_node) {
1156
- try {
1157
- // 处理新的父节点信息结构(包含node和parent属性)
1158
- var actual_parent_node = parent_node;
1159
- if (parent_node && typeof parent_node === "object" && parent_node.node) {
1160
- actual_parent_node = parent_node.node;
1161
- }
1162
-
1163
- // 检查当前节点是否为对象字面量的属性
1164
- if (!actual_parent_node || actual_parent_node.type !== "ObjectExpression") {
1165
- return false;
1166
- }
1167
-
1168
- // 递归查找调用表达式(处理嵌套对象的情况)
1169
- var findCallExpression = function (current_node) {
1170
- if (!current_node) {
1171
- return null;
1172
- }
1173
-
1174
- if (current_node.type === "CallExpression") {
1175
- return current_node;
1176
- }
1177
-
1178
- // 继续向上查找
1179
- return findCallExpression(current_node.parent);
1180
- };
1181
-
1182
- // 优先使用新的父节点信息结构中的parent属性
1183
- var grandparent =
1184
- parent_node && typeof parent_node === "object" && parent_node.parent
1185
- ? parent_node.parent
1186
- : actual_parent_node.parent;
1187
-
1188
- // 查找调用表达式
1189
- var call_expression = findCallExpression(grandparent);
1190
- if (!call_expression) {
1191
- return false;
1192
- }
1193
-
1194
- // 检查方法调用是否来自外部模块(非当前文件定义的函数)
1195
- var callee = call_expression.callee;
1196
- if (!callee) {
1197
- return false;
1198
- }
1199
-
1200
- // 如果是成员表达式(如 chokidar.watch),则认为是第三方库调用
1201
- if (callee.type === "MemberExpression") {
1202
- // 检查成员表达式的对象是否为模块导入变量
1203
- var is_module_import = this._isModuleImportVariable(callee.object);
1204
- if (is_module_import) {
1205
- return true;
1206
- }
1207
-
1208
- // 对于其他成员表达式,也认为是第三方库调用(保守策略)
1209
- return true;
1210
- }
1211
-
1212
- // 如果是标识符,检查是否是常见的第三方库函数名
1213
- if (callee.type === "Identifier") {
1214
- var common_third_party_functions = [
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",
1232
- ];
1233
-
1234
- // 如果是常见的第三方库函数名,则认为是第三方库调用
1235
- if (common_third_party_functions.includes(callee.name)) {
1236
- return true;
1237
- }
1238
-
1239
- // 检查标识符是否为模块导入变量
1240
- var is_module_import = this._isModuleImportVariable(callee);
1241
- if (is_module_import) {
1242
- return true;
1243
- }
1244
-
1245
- // 对于其他标识符,暂时不认为是第三方库调用(避免误判)
1246
- return false;
1247
- }
1248
-
1249
- return false;
1250
- } catch (error) {
1251
- console.error("检查第三方库配置参数时出错:", error);
1252
- return false;
1253
- }
1254
- };
1255
-
1256
- /**
1257
- * 获取属性类型
1258
- * @param {object} val_node 属性值节点
1259
- * @param {string} prop_name 属性名
1260
- * @param {object} parent_node 父节点
1261
- * @returns {string} 属性类型
1262
- */
1263
- Detector.prototype._getPropType = function (val_node, prop_name, parent_node) {
1264
- if (!val_node) {
1265
- return "undefined_value"; // 未赋值类型
1266
- }
1267
-
1268
- // 检查是否为null值
1269
- if (val_node.type === "NullLiteral") {
1270
- return "null_value"; // null值类型
1271
- }
1272
-
1273
- // 检查是否为对象方法(在对象字面量中的函数)
1274
- if (
1275
- val_node &&
1276
- (val_node.type === "FunctionExpression" ||
1277
- val_node.type === "ArrowFunctionExpression")
1278
- ) {
1279
- return "method"; // 对象方法类型
1280
- }
1281
-
1282
- // 检查是否为类引用(属性类)
1283
- if (
1284
- val_node.type === "Identifier" &&
1285
- val_node.name &&
1286
- val_node.name[0] === val_node.name[0].toUpperCase()
1287
- ) {
1288
- // 检查是否是特殊全局变量(如__dirname、__filename、process等)
1289
- var special_globals = [
1290
- "__dirname",
1291
- "__filename",
1292
- "process",
1293
- "console",
1294
- "module",
1295
- "exports",
1296
- "require",
1297
- "global",
1298
- ];
1299
- if (special_globals.includes(val_node.name)) {
1300
- return "value"; // 特殊全局变量应该识别为属性值
1301
- }
1302
-
1303
- // 检查是否是类名引用(通常类名使用PascalCase)
1304
- return "class"; // 属性类类型
1305
- }
1306
-
1307
- // 检查是否为类实例(new表达式)
1308
- if (val_node.type === "NewExpression") {
1309
- return "instance_class"; // 属性实例类类型
1310
- }
1311
-
1312
- // 检查是否为函数调用(可能返回实例)
1313
- if (val_node.type === "CallExpression") {
1314
- // 检查是否调用的是构造函数
1315
- if (
1316
- val_node.callee &&
1317
- val_node.callee.type === "Identifier" &&
1318
- val_node.callee.name &&
1319
- val_node.callee.name[0] === val_node.callee.name[0].toUpperCase()
1320
- ) {
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"; // 工厂方法返回的实例
1334
- }
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"; // 普通模板
1381
- }
1382
-
1383
- return "value";
1384
- };
1385
-
1386
- /**
1387
- * 检测属性名
1388
- * @param {string} prop_name 属性名
1389
- * @param {object} node AST节点
1390
- * @param {object} val_node 属性值节点
1391
- * @param {object} parent_node 父节点
1392
- * @returns {object|null} 错误信息或null
1393
- */
1394
- Detector.prototype._checkPropertyName = function (
1395
- prop_name,
1396
- node,
1397
- val_node,
1398
- parent_node,
1399
- ) {
1400
- try {
1401
- // 检查是否为解构导入中的属性
1402
- var is_destructured_import = this._isDestructuredImportProperty(
1403
- node,
1404
- parent_node,
1405
- );
1406
-
1407
- // 如果是解构导入中的属性,则不进行属性名检测
1408
- if (is_destructured_import) {
1409
- return null;
1410
- }
1411
-
1412
- // 检查是否为第三方库的配置参数(方法调用中的对象字面量属性)
1413
- var is_third_party_config = this._isThirdPartyConfigProperty(
1414
- node,
1415
- parent_node,
1416
- );
1417
-
1418
- // 如果是第三方库的配置参数,则不进行属性名检测
1419
- if (is_third_party_config) {
1420
- return null;
1421
- }
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
-
1431
- // 获取属性类型
1432
- var prop_type = this._getPropType(val_node, prop_name, parent_node);
1433
- var rule_type = "";
1434
-
1435
- // 根据属性类型选择对应的规则
1436
- // 对于null值和未赋值属性,直接跳过命名规范检测
1437
- if (prop_type === "null_value" || prop_type === "undefined_value") {
1438
- return null; // 不进行命名规范检测
1439
- }
1440
-
1441
- switch (prop_type) {
1442
- case "class":
1443
- rule_type = "property-class-name";
1444
- break;
1445
- case "instance_class":
1446
- rule_type = "property-instance-class-name";
1447
- break;
1448
- case "method":
1449
- rule_type = "property-method-name";
1450
- break;
1451
- case "value":
1452
- default:
1453
- rule_type = "property-value-name";
1454
- break;
1455
- }
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
-
1478
- // 检查忽略词
1479
- var ignored_words = this.config.getIgnoredWords(base_rule_type);
1480
- if (ignored_words && ignored_words.includes(prop_name)) {
1481
- return null; // 忽略词不进行命名规范检测
1482
- }
1483
-
1484
- var rule = this.config.getRule(base_rule_type);
1485
- if (!rule) {
1486
- return null;
1487
- }
1488
-
1489
- // 首先检查命名风格
1490
- var style_err = null;
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);
1512
- } else {
1513
- // 其他属性类型:使用原有逻辑
1514
- style_err = this._validate_naming_style(
1515
- prop_name,
1516
- rule.styles,
1517
- rule_type,
1518
- );
1519
- }
1520
-
1521
- if (style_err) {
1522
- return {
1523
- node: node,
1524
- message: style_err,
1525
- rule_type: rule_type, // 添加规则类型信息
1526
- };
1527
- }
1528
-
1529
- // 检查长度
1530
- var len_err = this._checkNameLength(
1531
- prop_name,
1532
- rule.min,
1533
- rule.max,
1534
- rule_type,
1535
- );
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
-
1544
- return {
1545
- node: node,
1546
- message: error_message,
1547
- rule_type: rule_type, // 添加规则类型信息
1548
- };
1549
- }
1550
-
1551
- // 检查单词长度
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
- }
1580
- }
1581
-
1582
- // 检查禁止词汇
1583
- var forbid_err = this._checkForbiddenWords(prop_name, base_rule_type);
1584
- if (forbid_err) {
1585
- return {
1586
- node: node,
1587
- message: forbid_err,
1588
- rule_type: rule_type, // 添加规则类型信息
1589
- };
1590
- }
1591
-
1592
- return null;
1593
- } catch (error) {
1594
- console.error("检测属性名时出错:", error);
1595
- return null;
1596
- }
1597
- };
1598
-
1599
- /**
1600
- * 检查并推荐更合适的词汇
1601
- * @param {string} name 名称
1602
- * @param {string} name_type 名称类型
1603
- * @returns {string|null} 推荐信息或null
1604
- */
1605
- Detector.prototype._checkAndRecommend = function (name, name_type) {
1606
- try {
1607
- var rec_words = this.config.getRecommendedWords(name_type);
1608
- if (!rec_words || Object.keys(rec_words).length === 0) {
1609
- return null;
1610
- }
1611
-
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();
1616
-
1617
- // 检查每个推荐词映射
1618
- for (var rec_word in rec_words) {
1619
- if (rec_words.hasOwnProperty(rec_word)) {
1620
- var original_words = rec_words[rec_word];
1621
-
1622
- // 检查名称是否包含任何一个原词
1623
- for (var i = 0; i < original_words.length; i++) {
1624
- var original_word = original_words[i].toLowerCase();
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
- };
1651
- }
1652
- }
1653
- }
1654
- }
1655
-
1656
- return null;
1657
- } catch (error) {
1658
- console.error("检查并推荐更合适的词汇时出错:", error);
1659
- return null;
1660
- }
1661
- };
1662
-
1663
- /**
1664
- * 检查值是否为基础值类型
1665
- * @param {object} val_node 值节点
1666
- * @returns {boolean} 是否为基础值
1667
- */
1668
- Detector.prototype._isBaseValue = function (val_node) {
1669
- try {
1670
- if (!val_node) {
1671
- return false;
1672
- }
1673
-
1674
- // 检查是否为基础值类型
1675
- var is_base_value = false;
1676
-
1677
- switch (val_node.type) {
1678
- case "Literal": // 字面量:数字、字符串、布尔值
1679
- is_base_value = true;
1680
- break;
1681
- case "ArrayExpression": // 数组字面量
1682
- is_base_value = true;
1683
- break;
1684
- case "ObjectExpression": // 对象字面量
1685
- is_base_value = true;
1686
- break;
1687
- case "UnaryExpression": // 一元表达式(如 -1, +100)
1688
- if (val_node.operator === "-" || val_node.operator === "+") {
1689
- is_base_value = true;
1690
- }
1691
- break;
1692
- default:
1693
- is_base_value = false;
1694
- }
1695
-
1696
- return is_base_value;
1697
- } catch (error) {
1698
- console.error("检查值是否为基础值类型时出错:", error);
1699
- return false;
1700
- }
1701
- };
1702
-
1703
- /**
1704
- * 检查是否应该使用let而不是const声明变量
1705
- * @param {object} node 变量声明节点
1706
- * @param {object} val_node 值节点
1707
- * @returns {boolean} 是否应该使用let
1708
- */
1709
- Detector.prototype._shouldUseLetInsteadOfConst = function (node, val_node) {
1710
- try {
1711
- if (!node || !val_node) {
1712
- return false;
1713
- }
1714
-
1715
- // 检查是否为模块导入(需要排除的情况)
1716
- var is_module_import = this._isModuleImport(node, val_node);
1717
- if (is_module_import) {
1718
- return false;
1719
- }
1720
-
1721
- // 检查是否为解构赋值
1722
- var is_destructuring = false;
1723
- if (node.parent && node.parent.type === "VariableDeclarator") {
1724
- var declarator = node.parent;
1725
- if (
1726
- declarator.id &&
1727
- (declarator.id.type === "ObjectPattern" ||
1728
- declarator.id.type === "ArrayPattern")
1729
- ) {
1730
- is_destructuring = true;
1731
- }
1732
- }
1733
-
1734
- // 应该使用let的情况:
1735
- // 1. 函数调用(CallExpression)- 返回值可能变化
1736
- // 2. 变量引用(Identifier)- 可能被重新赋值
1737
- // 3. 条件表达式等可能产生不同结果的情况
1738
-
1739
- var should_use_let = false;
1740
-
1741
- // 检查是否为函数调用
1742
- if (val_node.type === "CallExpression") {
1743
- should_use_let = true;
1744
- }
1745
-
1746
- // 检查是否为变量引用
1747
- if (val_node.type === "Identifier") {
1748
- should_use_let = true;
1749
- }
1750
-
1751
- // 检查是否为解构赋值且右侧是复杂类型
1752
- var is_complex_type = this._isComplexType(val_node);
1753
- if (is_destructuring && is_complex_type) {
1754
- should_use_let = true;
1755
- }
1756
-
1757
- return should_use_let;
1758
- } catch (error) {
1759
- console.error("检查是否应该使用let时出错:", error);
1760
- return false;
1761
- }
1762
- };
1763
-
1764
- /**
1765
- * 检查值是否为复杂类型(方法、函数、实例等)
1766
- * @param {object} val_node 值节点
1767
- * @returns {boolean} 是否为复杂类型
1768
- */
1769
- Detector.prototype._isComplexType = function (val_node) {
1770
- try {
1771
- if (!val_node) {
1772
- return false;
1773
- }
1774
-
1775
- // 检查是否为复杂类型
1776
- var is_complex_type = false;
1777
-
1778
- switch (val_node.type) {
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": // 模板字符串
1788
- is_complex_type = true;
1789
- break;
1790
- default:
1791
- is_complex_type = false;
1792
- }
1793
-
1794
- return is_complex_type;
1795
- } catch (error) {
1796
- console.error("检查值是否为复杂类型时出错:", error);
1797
- return false;
1798
- }
1799
- };
1800
-
1801
- /**
1802
- * 检查是否为模块导入(需要排除const检测的情况)
1803
- * @param {object} node 变量声明节点
1804
- * @param {object} val_node 值节点
1805
- * @returns {boolean} 是否为模块导入
1806
- */
1807
- Detector.prototype._isModuleImport = function (node, val_node) {
1808
- try {
1809
- if (!node || !val_node) {
1810
- return false;
1811
- }
1812
-
1813
- // 情况1:const xxx = require('module') - 直接模块导入
1814
- if (val_node.type === "CallExpression" && val_node.callee) {
1815
- // 检查是否为require调用
1816
- if (
1817
- val_node.callee.type === "Identifier" &&
1818
- val_node.callee.name === "require"
1819
- ) {
1820
- return true;
1821
- }
1822
-
1823
- // 检查是否为import()动态导入
1824
- if (val_node.callee.type === "Import") {
1825
- return true;
1826
- }
1827
- }
1828
-
1829
- // 情况2:const {xxx} = require('module') - 解构模块导入
1830
- if (node.parent && node.parent.type === "VariableDeclarator") {
1831
- var declarator = node.parent;
1832
-
1833
- // 检查是否为解构赋值
1834
- if (declarator.id && declarator.id.type === "ObjectPattern") {
1835
- // 检查右侧是否为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
- ) {
1841
- return true;
1842
- }
1843
- }
1844
- }
1845
- }
1846
-
1847
- return false;
1848
- } catch (error) {
1849
- console.error("检查是否为模块导入时出错:", error);
1850
- return false;
1851
- }
1852
- };
1853
-
1854
- /**
1855
- * 检查标识符是否为模块导入变量
1856
- * @param {object} node AST节点(Identifier类型)
1857
- * @returns {boolean} 是否为模块导入变量
1858
- */
1859
- Detector.prototype._isModuleImportVariable = function (node) {
1860
- try {
1861
- if (!node || node.type !== "Identifier") {
1862
- return false;
1863
- }
1864
-
1865
- // 检查变量声明是否为模块导入
1866
- if (node.parent && node.parent.parent) {
1867
- var variable_declaration = node.parent.parent;
1868
-
1869
- // 检查是否为const声明
1870
- if (
1871
- variable_declaration.type === "VariableDeclaration" &&
1872
- variable_declaration.kind === "const"
1873
- ) {
1874
- // 检查声明中是否有require调用
1875
- var declarators = variable_declaration.declarations;
1876
- for (var i = 0; i < declarators.length; i++) {
1877
- var declarator = declarators[i];
1878
- if (declarator.init && declarator.init.type === "CallExpression") {
1879
- var init_call = declarator.init;
1880
- if (
1881
- init_call.callee &&
1882
- init_call.callee.type === "Identifier" &&
1883
- init_call.callee.name === "require"
1884
- ) {
1885
- return true;
1886
- }
1887
- }
1888
- }
1889
- }
1890
- }
1891
-
1892
- return false;
1893
- } catch (error) {
1894
- console.error("检查是否为模块导入变量时出错:", error);
1895
- return false;
1896
- }
1897
- };
1898
-
1899
- /**
1900
- * 检查是否为解构导入
1901
- * @param {object} node AST节点
1902
- * @returns {boolean} 是否为解构导入
1903
- */
1904
- Detector.prototype._isDestructuredImport = function (node) {
1905
- try {
1906
- if (!node || !node.parent) {
1907
- return false;
1908
- }
1909
-
1910
- // 检查是否为解构导入模式
1911
- var is_destructured = false;
1912
-
1913
- // 情况1:节点是Property.key(解构赋值中的属性键)
1914
- if (node.parent.type === "Property" && node.parent.key === node) {
1915
- var property = node.parent;
1916
-
1917
- // 检查Property的父节点是否为ObjectPattern
1918
- if (property.parent && property.parent.type === "ObjectPattern") {
1919
- var object_pattern = property.parent;
1920
-
1921
- // 检查ObjectPattern的父节点是否为VariableDeclarator
1922
- if (
1923
- object_pattern.parent &&
1924
- object_pattern.parent.type === "VariableDeclarator"
1925
- ) {
1926
- var declarator = object_pattern.parent;
1927
-
1928
- // 检查右侧是否为require调用或其他模块导入
1929
- if (declarator.init) {
1930
- var init_type = declarator.init.type;
1931
-
1932
- // 常见的模块导入方式
1933
- if (
1934
- init_type === "CallExpression" &&
1935
- declarator.init.callee &&
1936
- declarator.init.callee.name === "require"
1937
- ) {
1938
- is_destructured = true;
1939
- }
1940
-
1941
- // 如果是ImportDeclaration(ES6导入)
1942
- if (init_type === "ImportExpression") {
1943
- is_destructured = true;
1944
- }
1945
- }
1946
- }
1947
- }
1948
- }
1949
-
1950
- // 情况2:节点是VariableDeclarator(简单变量声明)
1951
- else if (node.parent.type === "VariableDeclarator") {
1952
- var declarator = node.parent;
1953
-
1954
- // 检查是否为解构模式(ObjectPattern或ArrayPattern)
1955
- if (declarator.id && declarator.id.type === "ObjectPattern") {
1956
- // 检查右侧是否为require调用或其他模块导入
1957
- if (declarator.init) {
1958
- var init_type = declarator.init.type;
1959
-
1960
- // 常见的模块导入方式
1961
- if (
1962
- init_type === "CallExpression" &&
1963
- declarator.init.callee &&
1964
- declarator.init.callee.name === "require"
1965
- ) {
1966
- is_destructured = true;
1967
- }
1968
-
1969
- // 如果是ImportDeclaration(ES6导入)
1970
- if (init_type === "ImportExpression") {
1971
- is_destructured = true;
1972
- }
1973
- }
1974
- }
1975
- }
1976
-
1977
- return is_destructured;
1978
- } catch (error) {
1979
- console.error("检查是否为解构导入时出错:", error);
1980
- return false;
1981
- }
1982
- };
1983
-
1984
- /**
1985
- * 检查是否为解构导入中的属性
1986
- * @param {object} node 属性节点
1987
- * @param {object} parent_node 父节点
1988
- * @returns {boolean} 是否为解构导入中的属性
1989
- */
1990
- Detector.prototype._isDestructuredImportProperty = function (
1991
- node,
1992
- parent_node,
1993
- ) {
1994
- try {
1995
- // 处理新的父节点信息结构(包含node和parent属性)
1996
- var actual_parent_node = parent_node;
1997
- if (parent_node && typeof parent_node === "object" && parent_node.node) {
1998
- actual_parent_node = parent_node.node;
1999
- }
2000
-
2001
- if (!node || !actual_parent_node) {
2002
- return false;
2003
- }
2004
-
2005
- // 检查父节点是否为ObjectPattern(解构模式)
2006
- if (actual_parent_node.type === "ObjectPattern") {
2007
- // 检查父节点的父节点是否为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
- ) {
2017
- var declarator = actual_parent_parent;
2018
-
2019
- // 检查右侧是否为require调用或其他模块导入
2020
- if (declarator.init) {
2021
- var init_type = declarator.init.type;
2022
-
2023
- // 常见的模块导入方式
2024
- if (
2025
- init_type === "CallExpression" &&
2026
- declarator.init.callee &&
2027
- declarator.init.callee.name === "require"
2028
- ) {
2029
- return true;
2030
- }
2031
-
2032
- // 如果是ImportDeclaration(ES6导入)
2033
- if (init_type === "ImportExpression") {
2034
- return true;
2035
- }
2036
- }
2037
- }
2038
- }
2039
-
2040
- return false;
2041
- } catch (error) {
2042
- console.error("检查是否为解构导入中的属性时出错:", error);
2043
- return false;
2044
- }
2045
- };
2046
-
2047
- /**
2048
- * 检查是否为函数赋值(函数表达式或箭头函数)
2049
- * @param {object} node AST节点
2050
- * @returns {boolean} 是否为函数赋值
2051
- */
2052
- Detector.prototype._isFunctionAssignment = function (node) {
2053
- try {
2054
- if (!node) {
2055
- return false;
2056
- }
2057
-
2058
- // 检查节点是否为解构赋值中的属性
2059
- if (node.type === "Property" && node.key === node) {
2060
- // 检查父节点是否为ObjectPattern
2061
- if (node.parent && node.parent.type === "ObjectPattern") {
2062
- // 检查父节点的父节点是否为VariableDeclarator
2063
- if (
2064
- node.parent.parent &&
2065
- node.parent.parent.type === "VariableDeclarator"
2066
- ) {
2067
- var declarator = node.parent.parent;
2068
-
2069
- // 检查右侧是否为函数表达式或箭头函数
2070
- if (declarator.init) {
2071
- var init_type = declarator.init.type;
2072
-
2073
- // 函数表达式
2074
- if (init_type === "FunctionExpression") {
2075
- return true;
2076
- }
2077
-
2078
- // 箭头函数
2079
- if (init_type === "ArrowFunctionExpression") {
2080
- return true;
2081
- }
2082
-
2083
- // 函数调用(可能返回函数)
2084
- if (init_type === "CallExpression") {
2085
- return true;
2086
- }
2087
- }
2088
- }
2089
- }
2090
- }
2091
-
2092
- // 检查节点是否为解构赋值中的数组元素
2093
- if (
2094
- node.type === "Identifier" &&
2095
- node.parent &&
2096
- node.parent.type === "ArrayPattern"
2097
- ) {
2098
- // 检查父节点的父节点是否为VariableDeclarator
2099
- if (
2100
- node.parent.parent &&
2101
- node.parent.parent.type === "VariableDeclarator"
2102
- ) {
2103
- var declarator = node.parent.parent;
2104
-
2105
- // 检查右侧是否为函数表达式或箭头函数
2106
- if (declarator.init) {
2107
- var init_type = declarator.init.type;
2108
-
2109
- // 函数表达式
2110
- if (init_type === "FunctionExpression") {
2111
- return true;
2112
- }
2113
-
2114
- // 箭头函数
2115
- if (init_type === "ArrowFunctionExpression") {
2116
- return true;
2117
- }
2118
-
2119
- // 函数调用(可能返回函数)
2120
- if (init_type === "CallExpression") {
2121
- return true;
2122
- }
2123
- }
2124
- }
2125
- }
2126
-
2127
- return false;
2128
- } catch (error) {
2129
- console.error("检查是否为函数赋值时出错:", error);
2130
- return false;
2131
- }
2132
- };
2133
-
2134
- /**
2135
- * 检查常量名是否符合规范
2136
- * @param {string} constant_name 常量名
2137
- * @returns {boolean} 是否符合规范
2138
- */
2139
- Detector.prototype._isConstantNameValid = function (constant_name) {
2140
- try {
2141
- var rule = this.config.getRule("constant-name");
2142
- if (!rule) {
2143
- return false;
2144
- }
2145
-
2146
- // 检查命名风格
2147
- var style_err = this._validate_naming_style(
2148
- constant_name,
2149
- rule.styles,
2150
- "constant-name",
2151
- );
2152
- return !style_err;
2153
- } catch (error) {
2154
- console.error("检查常量名是否符合规范时出错:", error);
2155
- return false;
2156
- }
2157
- };
2158
-
2159
- /**
2160
- * 检查是否为忽略词
2161
- * @param {string} name 名称
2162
- * @param {string} name_type 名称类型
2163
- * @returns {boolean} 是否为忽略词
2164
- */
2165
- Detector.prototype._isIgnoredWord = function (name, name_type) {
2166
- try {
2167
- var ignored_words = this.config.getIgnoredWords(name_type);
2168
- if (!ignored_words || !Array.isArray(ignored_words)) {
2169
- return false;
2170
- }
2171
-
2172
- var name_lower = name.toLowerCase();
2173
- for (var i = 0; i < ignored_words.length; i++) {
2174
- if (ignored_words[i].toLowerCase() === name_lower) {
2175
- return true;
2176
- }
2177
- }
2178
-
2179
- return false;
2180
- } catch (error) {
2181
- console.error("检查是否为忽略词时出错:", error);
2182
- return false;
2183
- }
2184
- };
2185
-
2186
- /**
2187
- * 生成推荐命名
2188
- * @param {string} original_name 原始名称
2189
- * @param {string} long_word 过长的单词
2190
- * @param {string} name_type 名称类型
2191
- * @returns {string|null} 推荐命名或null
2192
- */
2193
- Detector.prototype._generateRecommendedName = function (
2194
- original_name,
2195
- long_word,
2196
- name_type,
2197
- ) {
2198
- try {
2199
- // 获取推荐词映射
2200
- var recommended_words = this.config.getRecommendedWords(name_type);
2201
- if (!recommended_words || Object.keys(recommended_words).length === 0) {
2202
- return null;
2203
- }
2204
-
2205
- var long_word_lower = long_word.toLowerCase();
2206
- var is_private = original_name.startsWith("_");
2207
- var original_name_without_prefix = is_private
2208
- ? original_name.substring(1)
2209
- : original_name;
2210
-
2211
- // 检查推荐词映射中是否有对应的缩写
2212
- for (var short_word in recommended_words) {
2213
- if (recommended_words.hasOwnProperty(short_word)) {
2214
- var original_words = recommended_words[short_word];
2215
-
2216
- // 检查过长的单词是否在推荐词的原词列表中
2217
- for (var i = 0; i < original_words.length; i++) {
2218
- var original_word = original_words[i].toLowerCase();
2219
- if (long_word_lower === original_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;
2226
- return recommended_name;
2227
- }
2228
- }
2229
- }
2230
- }
2231
-
2232
- return null;
2233
- } catch (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);
2500
- return null;
2501
- }
2502
- };
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
-
2860
- /**
2861
- * 检测解构赋值中的常量名
2862
- * @param {string} constant_name 常量名
2863
- * @param {object} node AST节点
2864
- * @returns {object|null} 错误信息或null
2865
- */
2866
- Detector.prototype._checkConstantNameForDestructuring = function (
2867
- constant_name,
2868
- node,
2869
- ) {
2870
- try {
2871
- // 解构赋值中的变量应该使用变量规则,而不是常量规则
2872
- var rule = this.config.getRule("variable-name");
2873
- if (!rule) {
2874
- return null;
2875
- }
2876
-
2877
- // 检查是否为忽略词
2878
- if (this._isIgnoredWord(constant_name, "variable-name")) {
2879
- return null;
2880
- }
2881
-
2882
- // 检查是否为解构导入(从模块导入的变量)
2883
- var is_destructured_import = this._isDestructuredImport(node);
2884
-
2885
- // 如果是解构导入,则不进行变量检测
2886
- if (is_destructured_import) {
2887
- return null;
2888
- }
2889
-
2890
- // 检查是否为函数赋值(函数表达式或箭头函数)
2891
- var is_function_assignment = this._isFunctionAssignment(node);
2892
-
2893
- // 如果是函数赋值,允许camelCase命名风格
2894
- var allowed_styles = [];
2895
- if (is_function_assignment) {
2896
- allowed_styles = ["camelCase", "UPPER_SNAKE_CASE"];
2897
- } else {
2898
- allowed_styles = rule.styles;
2899
- }
2900
-
2901
- // 检查命名风格
2902
- var style_err = this._validate_naming_style(
2903
- constant_name,
2904
- allowed_styles,
2905
- "variable-name",
2906
- );
2907
- if (style_err) {
2908
- return {
2909
- node: node,
2910
- message: style_err,
2911
- };
2912
- }
2913
-
2914
- // 检查并推荐更合适的词汇(作为命名风格检查的补充)
2915
- var recommend_info = this._checkAndRecommend(
2916
- constant_name,
2917
- "variable-name",
2918
- );
2919
- if (recommend_info) {
2920
- // 如果有推荐建议,在错误消息中提示可以使用更简洁的词汇
2921
- return {
2922
- node: node,
2923
- message:
2924
- "变量名'" +
2925
- constant_name +
2926
- "'长度过长,最大长度为20字符,建议使用: " +
2927
- recommend_info.recommended_name,
2928
- };
2929
- }
2930
-
2931
- // 检查长度
2932
- var len_err = this._checkNameLength(
2933
- constant_name,
2934
- rule.min,
2935
- rule.max,
2936
- "variable-name",
2937
- );
2938
- if (len_err) {
2939
- return {
2940
- node: node,
2941
- message: len_err,
2942
- };
2943
- }
2944
-
2945
- // 检查单词长度
2946
- var word_err = this._checkWordLength(
2947
- constant_name,
2948
- rule.single_word_len,
2949
- "constant-name",
2950
- );
2951
- if (word_err) {
2952
- return {
2953
- node: node,
2954
- message: word_err,
2955
- };
2956
- }
2957
-
2958
- // 检查禁止词汇
2959
- var forbid_err = this._checkForbiddenWords(constant_name, "constant-name");
2960
- if (forbid_err) {
2961
- return {
2962
- node: node,
2963
- message: forbid_err,
2964
- };
2965
- }
2966
-
2967
- return null;
2968
- } catch (error) {
2969
- console.error("检测解构赋值常量名时出错:", error);
2970
- return null;
2971
- }
2972
- };
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
-
3664
- module.exports = { Detector };
1
+
2
+ const { Config } = require('./config');
3
+ const { Validator } = require('./validator');
4
+ const { Corrector } = require('./corrector');
5
+ const { Tip } = require('./tip');
6
+
7
+ /**
8
+ * 命名规范检测器类
9
+ * 负责检测命名类型
10
+ */
11
+ class Detector {
12
+ /**
13
+ * 构造函数
14
+ * @param {object} config 配置对象
15
+ */
16
+ constructor(config) {
17
+ this.config = config || new Config();
18
+ this.validator = new Validator(config);
19
+ this.corrector = new Corrector(config);
20
+ this.tip = new Tip(config);
21
+ }
22
+ }
23
+
24
+ /**
25
+ * 获取原始类型
26
+ * @param {object} node AST节点
27
+ * @returns {string} 原始类型
28
+ */
29
+ Detector.prototype._getOriginalType = function (node) {
30
+ if (!node) {
31
+ return 'variable';
32
+ }
33
+
34
+ // 检查是否为属性节点
35
+ var is_property = false;
36
+ var current_node = node;
37
+
38
+ // 特殊处理:类中的实例方法应该视为属性函数
39
+ var is_class_method = false;
40
+ var is_static_method = false;
41
+
42
+ if (node.type === 'MethodDefinition') {
43
+ is_class_method = true;
44
+ is_static_method = node.static || false;
45
+ }
46
+
47
+ while (current_node.parent) {
48
+ // 如果是属性节点或成员表达式,且不是顶层声明
49
+ if (current_node.parent.type === 'Property' ||
50
+ current_node.parent.type === 'MemberExpression') {
51
+ is_property = true;
52
+ break;
53
+ }
54
+ // 如果是对象表达式,但父级不是变量声明,则视为属性
55
+ if (current_node.parent.type === 'ObjectExpression' &&
56
+ current_node.parent.parent &&
57
+ current_node.parent.parent.type !== 'VariableDeclarator') {
58
+ is_property = true;
59
+ break;
60
+ }
61
+ // 类中的实例方法应该视为属性函数,但静态方法保持静态函数类型
62
+ if (current_node.parent.type === 'ClassBody' ||
63
+ current_node.parent.type === 'ClassDeclaration' ||
64
+ current_node.parent.type === 'ClassExpression') {
65
+ // 如果是类中的方法,但不是静态方法,则视为属性
66
+ if (is_class_method && !is_static_method) {
67
+ is_property = true;
68
+ }
69
+ break;
70
+ }
71
+ current_node = current_node.parent;
72
+ }
73
+
74
+ // 根据AST节点类型映射到配置文件中定义的命名类型
75
+ switch (node.type) {
76
+ case 'ClassDeclaration':
77
+ case 'ClassExpression':
78
+ return is_property ? 'property-class' : 'class';
79
+
80
+ case 'MethodDefinition':
81
+ // 检查是否是静态方法
82
+ if (node.static) {
83
+ return is_property ? 'property-static-function' : 'static-function';
84
+ }
85
+ // 私有方法使用与普通方法相同的命名规则
86
+ return is_property ? 'property-function' : 'function';
87
+
88
+ case 'FunctionDeclaration':
89
+ case 'FunctionExpression':
90
+ case 'ArrowFunctionExpression':
91
+ return is_property ? 'property-function' : 'function';
92
+
93
+ case 'VariableDeclarator':
94
+ return this._getVariableDeclaratorType(node);
95
+
96
+ case 'Property':
97
+ // 属性节点需要根据属性值类型进一步判断
98
+ return this._getPropertyType(node);
99
+
100
+ case 'NewExpression':
101
+ return is_property ? 'property-class-instance' : 'class-instance';
102
+
103
+ case 'AssignmentExpression':
104
+ // 赋值表达式:根据赋值右侧的类型判断
105
+ return this._getAssignmentPropertyType(node);
106
+
107
+ case 'PropertyDefinition':
108
+ // 类属性:根据属性值的类型判断
109
+ if (node.value && node.value.type === 'NewExpression') {
110
+ // 如果是new表达式,则根据是否为静态属性判断类型
111
+ if (node.static) {
112
+ return 'static-class-instance'; // 静态类字段实例
113
+ }
114
+ return 'property-class-instance'; // 普通类字段实例
115
+ }
116
+
117
+ // 检查是否为函数类型的属性值
118
+ if (node.value) {
119
+ var function_types = ['FunctionExpression', 'ArrowFunctionExpression'];
120
+ if (function_types.includes(node.value.type)) {
121
+ // 类属性函数:根据是否为静态属性判断类型
122
+ if (node.static) {
123
+ return 'static-function'; // 静态类字段函数
124
+ }
125
+ return 'property-function'; // 普通类字段函数
126
+ }
127
+ }
128
+
129
+ // 类属性:根据是否为静态属性判断类型
130
+ if (node.static) {
131
+ return 'static-variable';
132
+ }
133
+ return 'property-variable';
134
+
135
+ case 'Identifier':
136
+ // 如果是属性名标识符
137
+ if (node.parent && node.parent.type === 'Property' && node.parent.key === node) {
138
+ // 根据属性值的类型判断属性类型
139
+ return this._getPropertyType(node.parent);
140
+ }
141
+
142
+ // 如果是赋值表达式中的属性名标识符
143
+ if (node.parent && node.parent.type === 'MemberExpression' &&
144
+ node.parent.property === node && node.parent.parent &&
145
+ node.parent.parent.type === 'AssignmentExpression') {
146
+ // 根据赋值右侧的类型判断属性类型
147
+ return this._getAssignmentPropertyType(node.parent.parent);
148
+ }
149
+
150
+ // 如果是类名标识符
151
+ if (node.parent && (node.parent.type === 'ClassDeclaration' ||
152
+ node.parent.type === 'ClassExpression')) {
153
+ return is_property ? 'property-class' : 'class';
154
+ }
155
+
156
+ // 如果是变量声明标识符
157
+ if (node.parent && node.parent.type === 'VariableDeclarator' &&
158
+ node.parent.id === node) {
159
+ return this._getVariableDeclaratorType(node.parent, is_property);
160
+ }
161
+
162
+ // 如果是参数节点(函数声明、函数表达式中的参数)
163
+ if (node.parent && (node.parent.type === 'FunctionDeclaration' ||
164
+ node.parent.type === 'FunctionExpression' ||
165
+ node.parent.type === 'ArrowFunctionExpression')) {
166
+ // 检查是否是函数参数(不是函数名)
167
+ if (node.parent.params && node.parent.params.includes(node)) {
168
+ return 'param';
169
+ }
170
+ // 如果不是参数,则是函数名
171
+ return is_property ? 'property-function' : 'function';
172
+ }
173
+
174
+ // 如果是函数调用中的函数名标识符
175
+ if (node.parent && node.parent.type === 'CallExpression' &&
176
+ node.parent.callee === node) {
177
+ return is_property ? 'property-function' : 'function';
178
+ }
179
+
180
+ // 如果是方法参数节点
181
+ if (node.parent && node.parent.type === 'MethodDefinition') {
182
+ // 检查是否是方法参数(不是方法名)
183
+ if (node.parent.value && node.parent.value.params && node.parent.value.params.includes(node)) {
184
+ return 'param';
185
+ }
186
+ }
187
+
188
+ // 其他标识符根据上下文判断
189
+ return is_property ? 'property-variable' : 'variable';
190
+
191
+ default:
192
+ return is_property ? 'property-variable' : 'variable';
193
+ }
194
+ };
195
+
196
+ /**
197
+ * 检测命名规范
198
+ * @param {string} name 名称
199
+ * @param {object} node AST节点
200
+ * @param {string} expected_type 期望的命名类型
201
+ * @returns {object} 检测结果
202
+ */
203
+ Detector.prototype.detect = function (name, node, expected_type = null) {
204
+ // 根据AST节点类型自动推断命名类型
205
+ var original_type = this._getOriginalType(node);
206
+
207
+ // 如果指定了期望类型,但推断类型不匹配,则返回null
208
+ if (expected_type && original_type !== expected_type) {
209
+ return null;
210
+ }
211
+
212
+ var error = this.validator.validate(name, original_type);
213
+ if (!error) {
214
+ return null;
215
+ }
216
+ var fix_suggestion = this.corrector.getSuggestion(error);
217
+ var message = this.tip.getFullMessage(error, fix_suggestion);
218
+ return {
219
+ node,
220
+ message,
221
+ error_type: error.type,
222
+ severity: error.severity,
223
+ fix_suggestion: fix_suggestion,
224
+ original_type: original_type
225
+ }
226
+ }
227
+
228
+ /**
229
+ * 获取变量声明类型
230
+ * @param {object} node 变量声明节点
231
+ * @param {boolean} is_property 是否为属性节点
232
+ * @returns {string} 原始类型
233
+ */
234
+ Detector.prototype._getVariableDeclaratorType = function (node, is_property = false) {
235
+ // 检查是否为类表达式赋值
236
+ if (node.init && node.init.type === 'ClassExpression') {
237
+ return is_property ? 'property-class' : 'class'; // 类表达式赋值 -> 类类型
238
+ }
239
+
240
+ // 检查是否为函数赋值
241
+ if (node.init && (node.init.type === 'FunctionExpression' ||
242
+ node.init.type === 'ArrowFunctionExpression')) {
243
+ // 特殊处理:检查是否为混入类(返回类表达式的箭头函数)
244
+ if (node.init.type === 'ArrowFunctionExpression' &&
245
+ node.init.body && node.init.body.type === 'ClassExpression') {
246
+ return is_property ? 'property-class' : 'class'; // 混入类 -> 类类型
247
+ }
248
+ return is_property ? 'property-function' : 'function'; // 函数赋值 -> 函数类型
249
+ }
250
+
251
+ // 检查是否为类实例赋值
252
+ if (node.init && node.init.type === 'NewExpression') {
253
+ return is_property ? 'property-class-instance' : 'class-instance'; // 类实例赋值 -> 类实例类型
254
+ }
255
+
256
+ // 检查是否为正则表达式字面量(RegExp实例)
257
+ if (node.init && node.init.type === 'Literal' && node.init.regex) {
258
+ return is_property ? 'property-class-instance' : 'class-instance'; // 正则表达式字面量 -> 类实例类型
259
+ }
260
+
261
+ // 检查是否为包含函数的对象(类实例)
262
+ if (node.init && node.init.type === 'ObjectExpression' &&
263
+ node.init.properties && node.init.properties.length > 0) {
264
+ for (var i = 0; i < node.init.properties.length; i++) {
265
+ var property = node.init.properties[i];
266
+ if (property.value && (property.value.type === 'FunctionExpression' ||
267
+ property.value.type === 'ArrowFunctionExpression' ||
268
+ property.value.type === 'ClassExpression')) {
269
+ return is_property ? 'property-class-instance' : 'class-instance'; // 包含函数的对象 -> 类实例
270
+ }
271
+ }
272
+ }
273
+
274
+ // 检查是否为字面量赋值
275
+ if (node.init && this._isLiteralValue(node.init)) {
276
+ // 只有纯字面量才能被识别为变量或常量
277
+ if (node.parent && node.parent.kind === 'const') {
278
+ return is_property ? 'property-constant' : 'constant'; // const 声明的字面量 -> 常量
279
+ }
280
+ return is_property ? 'property-variable' : 'variable'; // let/var 声明的字面量 -> 变量
281
+ }
282
+
283
+ // 检查是否为函数调用赋值
284
+ if (node.init && node.init.type === 'CallExpression') {
285
+ // 特殊处理:检查是否为Object.freeze/Object.seal调用
286
+ var callee = node.init.callee;
287
+ if (callee.type === 'MemberExpression') {
288
+ var object_name = callee.object.name;
289
+ var property_name = callee.property.name;
290
+ if (object_name === 'Object' &&
291
+ (property_name === 'freeze' || property_name === 'seal')) {
292
+ // Object.freeze/Object.seal包装的字面量应该视为常量
293
+ if (node.parent && node.parent.kind === 'const') {
294
+ return is_property ? 'property-constant' : 'constant';
295
+ }
296
+ }
297
+ }
298
+ // 其他函数调用赋值应该视为变量
299
+ return is_property ? 'property-variable' : 'variable';
300
+ }
301
+
302
+ // 检查是否为标识符赋值(如 undefined、null 等)
303
+ if (node.init && node.init.type === 'Identifier') {
304
+ // 特殊标识符赋值应该视为变量
305
+ var identifier_name = node.init.name;
306
+ if (identifier_name === 'undefined' || identifier_name === 'null' || identifier_name === 'NaN' || identifier_name === 'Infinity') {
307
+ return is_property ? 'property-variable' : 'variable';
308
+ }
309
+ // 其他标识符赋值视为类实例
310
+ return is_property ? 'property-class-instance' : 'class-instance';
311
+ }
312
+
313
+ // 其他非字面量赋值视为类实例
314
+ return is_property ? 'property-class-instance' : 'class-instance';
315
+ };
316
+
317
+ /**
318
+ * 获取赋值表达式中的属性类型
319
+ * @param {object} node 赋值表达式节点
320
+ * @returns {string} 原始类型
321
+ */
322
+ Detector.prototype._getAssignmentPropertyType = function (node) {
323
+ if (!node.right) {
324
+ return 'property-variable';
325
+ }
326
+
327
+ // 根据赋值右侧的类型判断属性类型
328
+ switch (node.right.type) {
329
+ case 'FunctionExpression':
330
+ case 'ArrowFunctionExpression':
331
+ // 检查是否为原型方法赋值
332
+ if (node.left &&
333
+ node.left.type === 'MemberExpression' &&
334
+ node.left.object &&
335
+ node.left.object.type === 'MemberExpression' &&
336
+ node.left.object.property &&
337
+ node.left.object.property.type === 'Identifier' &&
338
+ node.left.object.property.name === 'prototype') {
339
+ return 'prototype-function';
340
+ }
341
+ return 'property-function';
342
+
343
+ case 'ClassExpression':
344
+ return 'property-class';
345
+
346
+ case 'NewExpression':
347
+ return 'property-class-instance';
348
+
349
+ case 'CallExpression':
350
+ // 函数调用:根据函数名推断返回值类型
351
+ // 如果函数名以'create'、'get'、'make'等开头,可能返回实例
352
+ if (node.right.callee && node.right.callee.type === 'Identifier') {
353
+ var func_name = node.right.callee.name.toLowerCase();
354
+ if (func_name.startsWith('create') || func_name.startsWith('get') ||
355
+ func_name.startsWith('make') || func_name.startsWith('build')) {
356
+ return 'property-class-instance';
357
+ }
358
+ }
359
+ return 'property-variable';
360
+
361
+ case 'Literal':
362
+ case 'TemplateLiteral':
363
+ case 'ArrayExpression':
364
+ case 'ObjectExpression':
365
+ // 字面量值:根据属性名判断类型
366
+ if (node.left && node.left.type === 'MemberExpression' &&
367
+ node.left.property && node.left.property.type === 'Identifier') {
368
+ var property_name = node.left.property.name;
369
+
370
+ // 检查属性名是否为常量名规范(UPPER_SNAKE_CASE)
371
+ var constant_name_regex = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/;
372
+ if (constant_name_regex.test(property_name)) {
373
+ return 'property-constant';
374
+ }
375
+
376
+ // 检查属性名是否为类名规范(PascalCase)
377
+ var class_name_regex = /^[A-Z][a-z]*([A-Z][a-z]*)*$/;
378
+ if (class_name_regex.test(property_name)) {
379
+ return 'property-class';
380
+ }
381
+ }
382
+ return 'property-variable';
383
+
384
+ case 'Identifier':
385
+ // 检查标识符是否为类引用
386
+ // 如果标识符名称符合类名规范(PascalCase),则视为类引用
387
+ var class_name_regex = /^[A-Z][a-z]*([A-Z][a-z]*)*$/;
388
+
389
+ // 检查标识符是否为常量引用
390
+ // 如果标识符名称符合常量名规范(UPPER_SNAKE_CASE),则视为常量引用
391
+ var constant_name_regex = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/;
392
+
393
+ // 检查是否为解构赋值的情况(node.right可能不存在)
394
+ if (node.right && node.right.name) {
395
+ if (class_name_regex.test(node.right.name)) {
396
+ return 'property-class';
397
+ }
398
+ if (constant_name_regex.test(node.right.name)) {
399
+ return 'property-constant';
400
+ }
401
+ }
402
+
403
+ // 对于解构赋值中的标识符,直接根据标识符名称判断
404
+ if (node.value && node.value.name) {
405
+ if (class_name_regex.test(node.value.name)) {
406
+ return 'property-class';
407
+ }
408
+ if (constant_name_regex.test(node.value.name)) {
409
+ return 'property-constant';
410
+ }
411
+ }
412
+
413
+ return 'property-variable';
414
+
415
+ case 'Literal':
416
+ case 'TemplateLiteral':
417
+ case 'ArrayExpression':
418
+ case 'ObjectExpression':
419
+ // 检查是否为字面量值,并根据父级对象类型判断属性类型
420
+ if (this._isLiteralValue(node.value)) {
421
+ // 首先获取属性所在对象的类型
422
+ var parent_object_type = this._getParentObjectType(node);
423
+
424
+ // 如果父级对象是类实例,字面量属性值应该识别为变量属性
425
+ if (parent_object_type === 'class-instance' || parent_object_type === 'property-class-instance') {
426
+ return 'property-variable';
427
+ }
428
+
429
+ // 如果父级对象是常量,字面量属性值应该识别为常量属性
430
+ if (parent_object_type === 'constant' || parent_object_type === 'property-constant') {
431
+ return 'property-constant';
432
+ }
433
+
434
+ // 其他情况都视为变量属性
435
+ return 'property-variable';
436
+ }
437
+ return 'property-variable';
438
+
439
+ default:
440
+ return 'property-variable';
441
+ }
442
+ };
443
+
444
+ /**
445
+ * 获取属性所在对象的类型
446
+ * @param {object} node 属性节点
447
+ * @returns {string} 对象类型
448
+ */
449
+ Detector.prototype._getParentObjectType = function (node) {
450
+ var current_node = node;
451
+
452
+ // 向上遍历父节点,找到对象表达式或变量声明
453
+ while (current_node.parent) {
454
+ current_node = current_node.parent;
455
+
456
+ // 如果是对象表达式,继续向上找变量声明
457
+ if (current_node.type === 'ObjectExpression') {
458
+ continue;
459
+ }
460
+
461
+ // 如果是变量声明,获取其类型
462
+ if (current_node.type === 'VariableDeclarator') {
463
+ return this._getVariableDeclaratorType(current_node, true); // true 表示是属性
464
+ }
465
+
466
+ // 如果是赋值表达式,获取其类型
467
+ if (current_node.type === 'AssignmentExpression') {
468
+ return this._getAssignmentPropertyType(current_node);
469
+ }
470
+ }
471
+
472
+ return 'unknown';
473
+ };
474
+
475
+ /**
476
+ * 获取属性所在对象的声明类型
477
+ * @param {object} node 属性节点
478
+ * @returns {string} 声明类型('const'、'let'、'var' 或 'unknown')
479
+ */
480
+ Detector.prototype._getParentDeclarationType = function (node) {
481
+ var current_node = node;
482
+
483
+ // 向上遍历父节点,找到变量声明或赋值表达式
484
+ while (current_node.parent) {
485
+ current_node = current_node.parent;
486
+
487
+ // 如果是变量声明
488
+ if (current_node.type === 'VariableDeclarator') {
489
+ if (current_node.parent && current_node.parent.kind) {
490
+ return current_node.parent.kind; // 'const', 'let', 'var'
491
+ }
492
+ }
493
+
494
+ // 如果是赋值表达式
495
+ if (current_node.type === 'AssignmentExpression') {
496
+ return 'variable'; // 赋值表达式视为变量
497
+ }
498
+
499
+ // 如果是函数参数
500
+ if (current_node.type === 'FunctionDeclaration' ||
501
+ current_node.type === 'FunctionExpression' ||
502
+ current_node.type === 'ArrowFunctionExpression') {
503
+ return 'param'; // 函数参数
504
+ }
505
+ }
506
+
507
+ return 'unknown';
508
+ };
509
+
510
+ /**
511
+ * 获取属性类型
512
+ * @param {object} node 属性节点
513
+ * @returns {string} 原始类型
514
+ */
515
+ Detector.prototype._getPropertyType = function (node) {
516
+ if (!node.value) {
517
+ return 'property-variable';
518
+ }
519
+
520
+ // 根据属性值的类型判断属性类型
521
+ switch (node.value.type) {
522
+ case 'FunctionExpression':
523
+ case 'ArrowFunctionExpression':
524
+ return 'property-function';
525
+
526
+ case 'ClassExpression':
527
+ return 'property-class';
528
+
529
+ case 'NewExpression':
530
+ return 'property-class-instance';
531
+
532
+ case 'Identifier':
533
+ // 检查标识符是否为类引用
534
+ // 如果标识符名称符合类名规范(PascalCase),则视为类引用
535
+ var class_name_regex = /^[A-Z][a-z]*([A-Z][a-z]*)*$/;
536
+
537
+ // 检查是否为解构赋值的情况(node.right可能不存在)
538
+ if (node.right && node.right.name && class_name_regex.test(node.right.name)) {
539
+ return 'property-class';
540
+ }
541
+
542
+ // 对于解构赋值中的标识符,直接根据标识符名称判断
543
+ if (node.value.name && class_name_regex.test(node.value.name)) {
544
+ return 'property-class';
545
+ }
546
+
547
+ // 检查标识符是否为函数参数引用
548
+ if (this._isParameterName(node.value)) {
549
+ return 'property-variable'; // 函数参数引用应该视为变量属性
550
+ }
551
+
552
+ return 'property-variable';
553
+
554
+ case 'Literal':
555
+ case 'TemplateLiteral':
556
+ case 'ArrayExpression':
557
+ case 'ObjectExpression':
558
+ // 检查是否为字面量值,并根据属性名判断类型
559
+ if (this._isLiteralValue(node.value)) {
560
+ // 首先根据属性名判断类型
561
+ if (node.key && node.key.type === 'Identifier') {
562
+ var property_name = node.key.name;
563
+
564
+ // 检查属性名是否为常量名规范(UPPER_SNAKE_CASE)
565
+ var constant_name_regex = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/;
566
+ if (constant_name_regex.test(property_name)) {
567
+ return 'property-constant';
568
+ }
569
+
570
+ // 检查属性名是否为类名规范(PascalCase)
571
+ var class_name_regex = /^[A-Z][a-z]*([A-Z][a-z]*)*$/;
572
+ if (class_name_regex.test(property_name)) {
573
+ return 'property-class';
574
+ }
575
+ }
576
+
577
+ // 如果属性名不符合特定规范,再根据父级对象类型判断
578
+ var parent_object_type = this._getParentObjectType(node);
579
+
580
+ // 如果父级对象是类实例,字面量属性值应该识别为变量属性
581
+ if (parent_object_type === 'class-instance' || parent_object_type === 'property-class-instance') {
582
+ return 'property-variable';
583
+ }
584
+
585
+ // 如果父级对象是常量,字面量属性值应该识别为常量属性
586
+ if (parent_object_type === 'constant' || parent_object_type === 'property-constant') {
587
+ return 'property-constant';
588
+ }
589
+
590
+ // 其他情况都视为变量属性
591
+ return 'property-variable';
592
+ }
593
+ return 'property-variable';
594
+
595
+ default:
596
+ return 'property-variable';
597
+ }
598
+ };
599
+
600
+ /**
601
+ * 判断是否为字面量值
602
+ * @param {object} node AST节点
603
+ * @returns {boolean} 是否为字面量
604
+ */
605
+ Detector.prototype._isLiteralValue = function (node) {
606
+ if (!node) {
607
+ return false;
608
+ }
609
+
610
+ switch (node.type) {
611
+ case 'Literal':
612
+ // 布尔型、字符串型、数字型字面量
613
+ // 排除正则表达式字面量(应该视为类实例)
614
+ if (node.regex) {
615
+ // 正则表达式字面量有regex属性,应该视为类实例,不是普通字面量
616
+ return false;
617
+ }
618
+ return true;
619
+
620
+ case 'TemplateLiteral':
621
+ // 模板字符串字面量
622
+ return true;
623
+
624
+ case 'Identifier':
625
+ // 特殊字面量标识符:undefined、null、Infinity、NaN等
626
+ var literal_identifiers = ['undefined', 'null', 'Infinity', 'NaN', 'true', 'false'];
627
+ if (literal_identifiers.includes(node.name)) {
628
+ return true;
629
+ }
630
+ return false;
631
+
632
+ case 'ArrayExpression':
633
+ // 数组型字面量:检查所有元素是否都是字面量
634
+ if (node.elements && node.elements.length > 0) {
635
+ for (var i = 0; i < node.elements.length; i++) {
636
+ if (!this._isLiteralValue(node.elements[i])) {
637
+ return false;
638
+ }
639
+ }
640
+ return true;
641
+ }
642
+ return true; // 空数组也是字面量
643
+
644
+ case 'ObjectExpression':
645
+ // 对象型字面量:检查所有属性值是否都是字面量
646
+ if (node.properties && node.properties.length > 0) {
647
+ for (var i = 0; i < node.properties.length; i++) {
648
+ var property = node.properties[i];
649
+ if (property.value && !this._isLiteralValue(property.value)) {
650
+ return false;
651
+ }
652
+ }
653
+ return true;
654
+ }
655
+ return true; // 空对象也是字面量
656
+
657
+ default:
658
+ return false;
659
+ }
660
+ };
661
+
662
+ /**
663
+ * 检查节点是否为参数名或参数引用
664
+ * @param {object} node AST节点
665
+ * @returns {boolean} 是否为参数名或参数引用
666
+ */
667
+ Detector.prototype._isParameterName = function (node) {
668
+ if (!node || !node.parent) {
669
+ return false;
670
+ }
671
+
672
+ // 检查是否为函数参数声明
673
+ var parent = node.parent;
674
+ if (parent.type === 'FunctionDeclaration' ||
675
+ parent.type === 'FunctionExpression' ||
676
+ parent.type === 'ArrowFunctionExpression') {
677
+ if (parent.params && Array.isArray(parent.params)) {
678
+ for (var i = 0; i < parent.params.length; i++) {
679
+ if (parent.params[i] === node) {
680
+ return true;
681
+ }
682
+ }
683
+ }
684
+ }
685
+
686
+ // 检查是否为函数参数引用(在函数体中使用参数)
687
+ var current_node = node;
688
+ while (current_node.parent) {
689
+ // 检查是否在函数体内
690
+ if (current_node.parent.type === 'FunctionDeclaration' ||
691
+ current_node.parent.type === 'FunctionExpression' ||
692
+ current_node.parent.type === 'ArrowFunctionExpression') {
693
+
694
+ // 检查标识符名称是否与函数参数匹配
695
+ var function_node = current_node.parent;
696
+ if (function_node.params && Array.isArray(function_node.params)) {
697
+ for (var i = 0; i < function_node.params.length; i++) {
698
+ var param = function_node.params[i];
699
+ // 对于普通参数
700
+ if (param.type === 'Identifier' && param.name === node.name) {
701
+ return true;
702
+ }
703
+ // 对于解构参数,需要递归检查
704
+ if ((param.type === 'ObjectPattern' || param.type === 'ArrayPattern') &&
705
+ this._isParameterInDestructuredPattern(param, node.name)) {
706
+ return true;
707
+ }
708
+ }
709
+ }
710
+ break;
711
+ }
712
+ current_node = current_node.parent;
713
+ }
714
+
715
+ return false;
716
+ }
717
+
718
+ /**
719
+ * 检查是否为真正的常量(const标签且值为字面量)
720
+ * @param {string} constant_name 常量名
721
+ * @param {object} decl 声明节点
722
+ * @returns {boolean} 是否为真正的常量
723
+ */
724
+ Detector.prototype._isTrueConstant = function (constant_name, decl) {
725
+ // 检查是否为字面量值
726
+ var is_literal = false;
727
+ if (decl.init) {
728
+ // 基本字面量类型
729
+ var literal_types = ['Literal', 'RegExpLiteral', 'TemplateLiteral'];
730
+ if (literal_types.includes(decl.init.type)) {
731
+ is_literal = true;
732
+ }
733
+
734
+ // 函数类型不是字面量,应该被识别为函数而不是常量
735
+ var function_types = ['FunctionExpression', 'ArrowFunctionExpression'];
736
+ if (function_types.includes(decl.init.type)) {
737
+ return false; // 函数赋值不是字面量,不是真正的常量
738
+ }
739
+
740
+ // 对象字面量 - 只有当所有属性值都是字面量时才视为常量
741
+ if (decl.init.type === 'ObjectExpression') {
742
+ var all_properties_literal = true;
743
+ if (decl.init.properties && decl.init.properties.length > 0) {
744
+ decl.init.properties.forEach(function (prop) {
745
+ if (prop.value) {
746
+ // 检查属性值是否为非字面量类型
747
+ var non_literal_types = ['NewExpression', 'CallExpression', 'FunctionExpression', 'ArrowFunctionExpression', 'ClassExpression'];
748
+ if (non_literal_types.includes(prop.value.type)) {
749
+ all_properties_literal = false;
750
+ }
751
+ // 如果属性值是对象或数组,递归检查
752
+ else if (prop.value.type === 'ObjectExpression' || prop.value.type === 'ArrayExpression') {
753
+ // 创建一个假的声明节点来递归检查
754
+ var fake_decl = { init: prop.value };
755
+ if (!_isTrueConstant('', fake_decl)) {
756
+ all_properties_literal = false;
757
+ }
758
+ }
759
+ }
760
+ });
761
+ }
762
+ is_literal = all_properties_literal;
763
+ }
764
+
765
+ // 数组字面量 - 只有当所有元素都是字面量时才视为常量
766
+ if (decl.init.type === 'ArrayExpression') {
767
+ var all_elements_literal = true;
768
+ if (decl.init.elements && decl.init.elements.length > 0) {
769
+ decl.init.elements.forEach(function (element) {
770
+ if (element) {
771
+ // 检查元素是否为非字面量类型
772
+ var non_literal_types = ['NewExpression', 'CallExpression', 'FunctionExpression', 'ArrowFunctionExpression', 'ClassExpression', 'AssignmentExpression'];
773
+ if (non_literal_types.includes(element.type)) {
774
+ all_elements_literal = false;
775
+ }
776
+ // 如果元素是对象或数组,递归检查
777
+ else if (element.type === 'ObjectExpression' || element.type === 'ArrayExpression') {
778
+ // 创建一个假的声明节点来递归检查
779
+ var fake_decl = { init: element };
780
+ if (!_isTrueConstant('', fake_decl)) {
781
+ all_elements_literal = false;
782
+ }
783
+ }
784
+ }
785
+ });
786
+ }
787
+ is_literal = all_elements_literal;
788
+ }
789
+
790
+ // Object.freeze/Object.seal包装的字面量
791
+ if (decl.init.type === 'CallExpression') {
792
+ var callee = decl.init.callee;
793
+ if (callee.type === 'MemberExpression') {
794
+ var object_name = callee.object.name;
795
+ var property_name = callee.property.name;
796
+ if (object_name === 'Object' &&
797
+ (property_name === 'freeze' || property_name === 'seal')) {
798
+ // 检查第一个参数是否为字面量
799
+ var args = decl.init.arguments;
800
+ if (args && args.length > 0) {
801
+ var first_arg = args[0];
802
+ if (first_arg.type === 'ObjectExpression' ||
803
+ first_arg.type === 'ArrayExpression') {
804
+ // 创建一个假的声明节点来检查参数是否为字面量
805
+ var fake_decl = { init: first_arg };
806
+ is_literal = _isTrueConstant('', fake_decl);
807
+ }
808
+ }
809
+ }
810
+ }
811
+ }
812
+ }
813
+
814
+ // 真正的常量是const声明且值为字面量
815
+ return is_literal;
816
+ }
817
+
818
+ /**
819
+ * 获取变量验证类型
820
+ * @param {object} node 变量声明节点
821
+ * @returns {string} 验证类型
822
+ */
823
+ Detector.prototype._getVariableValidationType = function (node) {
824
+ // 检查是否为常量声明
825
+ if (node.parent && node.parent.kind === 'const') {
826
+ // 检查是否为字面量赋值
827
+ if (node.init && this._isLiteralValue(node.init)) {
828
+ return 'constant';
829
+ }
830
+ return 'variable'; // const 声明的非字面量视为变量
831
+ }
832
+
833
+ // 检查是否为参数
834
+ if (node.parent && (node.parent.type === 'FunctionDeclaration' ||
835
+ node.parent.type === 'FunctionExpression' ||
836
+ node.parent.type === 'ArrowFunctionExpression')) {
837
+ return 'param';
838
+ }
839
+
840
+ return 'variable';
841
+ };
842
+
843
+ /**
844
+ * 获取赋值验证类型
845
+ * @param {object} node 赋值表达式节点
846
+ * @returns {string} 验证类型
847
+ */
848
+ Detector.prototype._getAssignmentValidationType = function (node) {
849
+ // 检查是否为类实例赋值
850
+ if (node.right && node.right.type === 'NewExpression') {
851
+ return 'class-instance'; // 类实例使用类实例命名规则
852
+ }
853
+
854
+ // 检查是否为函数赋值
855
+ if (node.right && (node.right.type === 'FunctionExpression' ||
856
+ node.right.type === 'ArrowFunctionExpression')) {
857
+ return 'function';
858
+ }
859
+
860
+ return 'variable';
861
+ };
862
+
863
+ /**
864
+ * 获取导出验证类型
865
+ * @param {object} node 导出声明节点
866
+ * @returns {string} 验证类型
867
+ */
868
+ Detector.prototype._getExportValidationType = function (node) {
869
+ // 根据导出内容的类型决定验证类型
870
+ if (node.declaration) {
871
+ switch (node.declaration.type) {
872
+ case 'ClassDeclaration':
873
+ case 'ClassExpression':
874
+ return 'class';
875
+
876
+ case 'FunctionDeclaration':
877
+ case 'FunctionExpression':
878
+ return 'function';
879
+
880
+ case 'VariableDeclaration':
881
+ // 检查是否为常量导出
882
+ if (node.declaration.kind === 'const') {
883
+ return 'constant';
884
+ }
885
+ return 'variable';
886
+
887
+ default:
888
+ return 'variable';
889
+ }
890
+ }
891
+
892
+ return 'variable';
893
+ };
894
+
895
+ /**
896
+ * 获取默认导出验证类型
897
+ * @param {object} node 默认导出节点
898
+ * @returns {string} 验证类型
899
+ */
900
+ Detector.prototype._getExportDefaultValidationType = function (node) {
901
+ // 根据默认导出内容的类型决定验证类型
902
+ if (node.declaration) {
903
+ switch (node.declaration.type) {
904
+ case 'ClassDeclaration':
905
+ case 'ClassExpression':
906
+ return 'class';
907
+
908
+ case 'FunctionDeclaration':
909
+ case 'FunctionExpression':
910
+ return 'function';
911
+
912
+ default:
913
+ return 'class'; // 默认导出通常使用类名规则
914
+ }
915
+ }
916
+
917
+ return 'class'; // 默认使用类名规则
918
+ };
919
+
920
+ /**
921
+ * 获取导入验证类型
922
+ * @param {object} node 导入节点
923
+ * @returns {string} 验证类型
924
+ */
925
+ Detector.prototype._getImportValidationType = function (node) {
926
+ // 根据导入内容的类型决定验证类型
927
+
928
+ // 默认导入通常导入类或默认导出
929
+ if (node.type === 'ImportDefaultSpecifier') {
930
+ return 'class';
931
+ }
932
+
933
+ // 命名空间导入使用变量名规则
934
+ if (node.type === 'ImportNamespaceSpecifier') {
935
+ return 'variable';
936
+ }
937
+
938
+ // 命名导入根据导入名称推断类型
939
+ if (node.type === 'ImportSpecifier') {
940
+ var imported_name = node.imported ? node.imported.name : '';
941
+
942
+ // 如果导入的名称以大写字母开头,可能是类
943
+ if (/^[A-Z]/.test(imported_name)) {
944
+ return 'class';
945
+ }
946
+
947
+ // 如果导入的名称包含特定关键词,可能是函数
948
+ var function_keywords = ['get', 'set', 'is', 'has', 'on', 'handle', 'callback'];
949
+ var lower_name = imported_name.toLowerCase();
950
+ for (var i = 0; i < function_keywords.length; i++) {
951
+ if (lower_name.includes(function_keywords[i])) {
952
+ return 'function';
953
+ }
954
+ }
955
+
956
+ // 如果导入的名称全大写,可能是常量
957
+ if (imported_name === imported_name.toUpperCase()) {
958
+ return 'constant';
959
+ }
960
+ }
961
+
962
+ // 默认使用变量名规则
963
+ return 'variable';
964
+ };
965
+
966
+ /**
967
+ * 检测参数类型并返回正确的验证类型
968
+ * @param {string} name 参数名
969
+ * @param {object} node 参数节点
970
+ * @returns {string} 验证类型
971
+ */
972
+ Detector.prototype._getParamValidationType = function (name, node) {
973
+ // 根据参数名推断参数类型
974
+ // 1. 如果参数名以大写字母开头,可能是类类型参数
975
+ if (/^[A-Z]/.test(name)) {
976
+ return 'class';
977
+ }
978
+
979
+ // 2. 如果参数名包含'on'、'handle'、'callback'等,可能是函数类型参数
980
+ var function_keywords = ['on', 'handle', 'callback', 'func', 'fn', 'cb'];
981
+ var lower_name = name.toLowerCase();
982
+ for (var i = 0; i < function_keywords.length; i++) {
983
+ if (lower_name.includes(function_keywords[i])) {
984
+ return 'function';
985
+ }
986
+ }
987
+
988
+ // 3. 默认使用变量类型参数规则
989
+ return 'variable';
990
+ };
991
+
992
+ /**
993
+ * 检查是否为真正的常量(const标签且值为字面量)
994
+ * @param {string} constant_name 常量名
995
+ * @param {object} decl 声明节点
996
+ * @returns {boolean} 是否为真正的常量
997
+ */
998
+ Detector.prototype._isTrueConstant = function (constant_name, decl) {
999
+ // 检查是否为字面量值
1000
+ var is_literal = false;
1001
+ if (decl.init) {
1002
+ // 基本字面量类型
1003
+ var literal_types = ['Literal', 'RegExpLiteral', 'TemplateLiteral'];
1004
+ if (literal_types.includes(decl.init.type)) {
1005
+ is_literal = true;
1006
+ }
1007
+
1008
+ // 函数类型不是字面量,应该被识别为函数而不是常量
1009
+ var function_types = ['FunctionExpression', 'ArrowFunctionExpression'];
1010
+ if (function_types.includes(decl.init.type)) {
1011
+ return false; // 函数赋值不是字面量,不是真正的常量
1012
+ }
1013
+
1014
+ // 对象字面量 - 只有当所有属性值都是字面量时才视为常量
1015
+ if (decl.init.type === 'ObjectExpression') {
1016
+ var all_properties_literal = true;
1017
+ if (decl.init.properties && decl.init.properties.length > 0) {
1018
+ decl.init.properties.forEach(function (prop) {
1019
+ if (prop.value) {
1020
+ // 检查属性值是否为非字面量类型
1021
+ var non_literal_types = ['NewExpression', 'CallExpression', 'FunctionExpression', 'ArrowFunctionExpression', 'ClassExpression'];
1022
+ if (non_literal_types.includes(prop.value.type)) {
1023
+ all_properties_literal = false;
1024
+ }
1025
+ // 如果属性值是对象或数组,递归检查
1026
+ else if (prop.value.type === 'ObjectExpression' || prop.value.type === 'ArrayExpression') {
1027
+ // 创建一个假的声明节点来递归检查
1028
+ var fake_decl = { init: prop.value };
1029
+ if (!this._isLiteralValue(prop.value)) {
1030
+ all_properties_literal = false;
1031
+ }
1032
+ }
1033
+ }
1034
+ }.bind(this));
1035
+ }
1036
+ is_literal = all_properties_literal;
1037
+ }
1038
+
1039
+ // 数组字面量 - 只有当所有元素都是字面量时才视为常量
1040
+ if (decl.init.type === 'ArrayExpression') {
1041
+ var all_elements_literal = true;
1042
+ if (decl.init.elements && decl.init.elements.length > 0) {
1043
+ decl.init.elements.forEach(function (element) {
1044
+ if (element) {
1045
+ // 检查元素是否为非字面量类型
1046
+ var non_literal_types = ['NewExpression', 'CallExpression', 'FunctionExpression', 'ArrowFunctionExpression', 'ClassExpression', 'AssignmentExpression'];
1047
+ if (non_literal_types.includes(element.type)) {
1048
+ all_elements_literal = false;
1049
+ }
1050
+ // 如果元素是对象或数组,递归检查
1051
+ else if (element.type === 'ObjectExpression' || element.type === 'ArrayExpression') {
1052
+ // 检查元素是否为字面量
1053
+ if (!this._isLiteralValue(element)) {
1054
+ all_elements_literal = false;
1055
+ }
1056
+ }
1057
+ }
1058
+ }.bind(this));
1059
+ }
1060
+ is_literal = all_elements_literal;
1061
+ }
1062
+
1063
+ // Object.freeze/Object.seal包装的字面量
1064
+ if (decl.init.type === 'CallExpression') {
1065
+ var callee = decl.init.callee;
1066
+ if (callee.type === 'MemberExpression') {
1067
+ var object_name = callee.object.name;
1068
+ var property_name = callee.property.name;
1069
+ if (object_name === 'Object' &&
1070
+ (property_name === 'freeze' || property_name === 'seal')) {
1071
+ // 检查第一个参数是否为字面量
1072
+ var args = decl.init.arguments;
1073
+ if (args && args.length > 0) {
1074
+ var first_arg = args[0];
1075
+ if (first_arg.type === 'ObjectExpression' ||
1076
+ first_arg.type === 'ArrayExpression') {
1077
+ // 检查参数是否为字面量
1078
+ is_literal = this._isLiteralValue(first_arg);
1079
+ }
1080
+ }
1081
+ }
1082
+ }
1083
+ }
1084
+ }
1085
+
1086
+ // 真正的常量是const声明且值为字面量
1087
+ return is_literal;
1088
+ };
1089
+
1090
+
1091
+
1092
+
1093
+
1094
+ /**
1095
+ * 检查变量是否为类实例
1096
+ * @param {object} decl 变量声明节点
1097
+ * @returns {boolean} 是否为类实例
1098
+ */
1099
+ Detector.prototype._isClassInstance = function (decl) {
1100
+ if (!decl.id || decl.id.type !== 'Identifier') {
1101
+ return false;
1102
+ }
1103
+
1104
+ // 检查变量是否被赋值为类实例(new ClassName())
1105
+ if (decl.init && decl.init.type === 'NewExpression') {
1106
+ return true;
1107
+ }
1108
+
1109
+ // 检查变量是否被赋值为函数返回的类实例
1110
+ if (decl.init && decl.init.type === 'CallExpression') {
1111
+ var callee = decl.init.callee;
1112
+
1113
+ // 检查是否为成员表达式调用(如 Math.random())
1114
+ if (callee.type === 'MemberExpression') {
1115
+ var object_name = callee.object.name;
1116
+ var property_name = callee.property.name;
1117
+
1118
+ // 排除常见的内置对象方法调用
1119
+ if (object_name === 'Math' || object_name === 'Date' ||
1120
+ object_name === 'String' || object_name === 'Number' ||
1121
+ object_name === 'Array' || object_name === 'Object') {
1122
+ return false;
1123
+ }
1124
+ }
1125
+
1126
+ // 检查是否为标识符调用
1127
+ if (callee.type === 'Identifier') {
1128
+ // 排除内置的数学函数
1129
+ if (callee.name === 'random' || callee.name === 'now' ||
1130
+ callee.name === 'floor' || callee.name === 'ceil' ||
1131
+ callee.name === 'round' || callee.name === 'abs') {
1132
+ return false;
1133
+ }
1134
+
1135
+ // 排除常见的内置函数
1136
+ var non_instance_functions = ['parseInt', 'parseFloat', 'encodeURI', 'decodeURI',
1137
+ 'encodeURIComponent', 'decodeURIComponent', 'isNaN',
1138
+ 'isFinite', 'eval', 'setTimeout', 'setInterval'];
1139
+ if (non_instance_functions.includes(callee.name)) {
1140
+ return false;
1141
+ }
1142
+
1143
+ // 如果函数名包含create、get、build等关键词,可能是返回类实例的函数
1144
+ if (callee.name.match(/^(create|get|build|make|new|init)/i)) {
1145
+ return true;
1146
+ }
1147
+ }
1148
+
1149
+ // 默认情况下,函数调用不视为类实例
1150
+ return false;
1151
+ }
1152
+
1153
+ // 检查是否为内置类的实例(RegExp字面量、Array字面量等)
1154
+ if (decl.init) {
1155
+ // RegExp字面量 - 视为类实例
1156
+ if (decl.init.type === 'Literal' && decl.init.regex) {
1157
+ return true;
1158
+ }
1159
+ // Array字面量 [] - 只有当所有元素都是字面量时才视为变量
1160
+ if (decl.init.type === 'ArrayExpression') {
1161
+ return !this._isLiteralValue(decl.init);
1162
+ }
1163
+ // Object字面量 {} - 检查是否包含函数(类实例)
1164
+ if (decl.init.type === 'ObjectExpression') {
1165
+ // 如果对象包含函数,则视为类实例
1166
+ if (decl.init.properties && decl.init.properties.length > 0) {
1167
+ for (var i = 0; i < decl.init.properties.length; i++) {
1168
+ var property = decl.init.properties[i];
1169
+ if (property.value && (property.value.type === 'FunctionExpression' ||
1170
+ property.value.type === 'ArrowFunctionExpression' ||
1171
+ property.value.type === 'ClassExpression')) {
1172
+ return true; // 包含函数的对象 -> 类实例
1173
+ }
1174
+ }
1175
+ }
1176
+ return false; // 纯字面量对象不是类实例
1177
+ }
1178
+ // 模板字面量 - 视为变量(基础值字符串类型)
1179
+ if (decl.init.type === 'TemplateLiteral') {
1180
+ return false;
1181
+ }
1182
+ }
1183
+
1184
+ return false;
1185
+ };
1186
+
1187
+ /**
1188
+ * 检查标识符是否在解构参数模式中
1189
+ * @param {object} pattern 解构模式节点
1190
+ * @param {string} identifier_name 标识符名称
1191
+ * @returns {boolean} 是否在解构参数中
1192
+ */
1193
+ Detector.prototype._isParameterInDestructuredPattern = function (pattern, identifier_name) {
1194
+ if (!pattern) {
1195
+ return false;
1196
+ }
1197
+
1198
+ // 处理对象解构模式
1199
+ if (pattern.type === 'ObjectPattern' && pattern.properties) {
1200
+ for (var i = 0; i < pattern.properties.length; i++) {
1201
+ var property = pattern.properties[i];
1202
+ // 检查属性键名是否匹配
1203
+ if (property.key && property.key.type === 'Identifier' && property.key.name === identifier_name) {
1204
+ return true;
1205
+ }
1206
+ // 检查属性值是否匹配(对于别名解构)
1207
+ if (property.value && property.value.type === 'Identifier' && property.value.name === identifier_name) {
1208
+ return true;
1209
+ }
1210
+ // 递归检查嵌套解构
1211
+ if (property.value && (property.value.type === 'ObjectPattern' || property.value.type === 'ArrayPattern')) {
1212
+ if (this._isParameterInDestructuredPattern(property.value, identifier_name)) {
1213
+ return true;
1214
+ }
1215
+ }
1216
+ }
1217
+ }
1218
+
1219
+ // 处理数组解构模式
1220
+ if (pattern.type === 'ArrayPattern' && pattern.elements) {
1221
+ for (var i = 0; i < pattern.elements.length; i++) {
1222
+ var element = pattern.elements[i];
1223
+ // 检查数组元素是否匹配
1224
+ if (element && element.type === 'Identifier' && element.name === identifier_name) {
1225
+ return true;
1226
+ }
1227
+ // 递归检查嵌套解构
1228
+ if (element && (element.type === 'ObjectPattern' || element.type === 'ArrayPattern')) {
1229
+ if (this._isParameterInDestructuredPattern(element, identifier_name)) {
1230
+ return true;
1231
+ }
1232
+ }
1233
+ }
1234
+ }
1235
+
1236
+ return false;
1237
+ };
1238
+
1239
+ module.exports = { Detector };