mm_eslint 1.2.7 → 1.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/config.js +523 -0
  2. package/detector.js +1214 -0
  3. package/index.js +88 -20
  4. package/package.json +3 -1
package/detector.js ADDED
@@ -0,0 +1,1214 @@
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(class_name, rule.styles, 'class-name');
49
+ if (style_err) {
50
+ return {
51
+ node: node,
52
+ message: style_err,
53
+ };
54
+ }
55
+
56
+ // 检查并推荐更合适的词汇
57
+ var rec_err = this._checkAndRecommend(class_name, 'class-name');
58
+ if (rec_err) {
59
+ return {
60
+ node: node,
61
+ message: rec_err,
62
+ };
63
+ }
64
+
65
+ // 检查长度
66
+ var len_err = this._checkNameLength(class_name, rule.min, rule.max, 'class-name');
67
+ if (len_err) {
68
+ return {
69
+ node: node,
70
+ message: len_err,
71
+ };
72
+ }
73
+
74
+ // 检查单词长度
75
+ var word_err = this._checkWordLength(class_name, rule.single_word_len, 'class-name');
76
+ if (word_err) {
77
+ return {
78
+ node: node,
79
+ message: word_err,
80
+ };
81
+ }
82
+
83
+ // 检查禁止词汇
84
+ var forbid_err = this._checkForbiddenWords(class_name, 'class-name');
85
+ if (forbid_err) {
86
+ return {
87
+ node: node,
88
+ message: forbid_err,
89
+ };
90
+ }
91
+
92
+ return null;
93
+ } catch (error) {
94
+ console.error('检测类名时出错:', error);
95
+ return null;
96
+ }
97
+ };
98
+
99
+ /**
100
+ * 检测方法名
101
+ * @param {string} method_name 方法名
102
+ * @param {object} node AST节点
103
+ * @returns {object|null} 错误信息或null
104
+ */
105
+ Detector.prototype._checkMethodName = function (method_name, node) {
106
+ try {
107
+ var rule = this.config.getRule('method-name');
108
+ if (!rule) {
109
+ return null;
110
+ }
111
+
112
+ // 检查是否为忽略词(在所有检测之前)
113
+ if (this._isIgnoredWord(method_name, 'method-name')) {
114
+ return null;
115
+ }
116
+
117
+ // 检查命名风格(支持公开方法和私有方法)
118
+ var style_err = null;
119
+ if (method_name.startsWith('_')) {
120
+ // 私有方法:检查是否符合私有方法命名规范
121
+ style_err = this._validate_naming_style(method_name, ['_camelCase'], 'method-name');
122
+ } else {
123
+ // 公开方法:检查是否符合公开方法命名规范
124
+ style_err = this._validate_naming_style(method_name, rule.styles, 'method-name');
125
+ }
126
+
127
+ if (style_err) {
128
+ return {
129
+ node: node,
130
+ message: style_err,
131
+ };
132
+ }
133
+
134
+ // 检查长度
135
+ var len_err = this._checkNameLength(method_name, rule.min, rule.max, 'method-name');
136
+ if (len_err) {
137
+ return {
138
+ node: node,
139
+ message: len_err,
140
+ };
141
+ }
142
+
143
+ // 检查单词长度
144
+ var word_err = this._checkWordLength(method_name, rule.single_word_len, 'method-name');
145
+ if (word_err) {
146
+ return {
147
+ node: node,
148
+ message: word_err,
149
+ };
150
+ }
151
+
152
+ // 检查禁止词汇
153
+ var forbid_err = this._checkForbiddenWords(method_name, 'method-name');
154
+ if (forbid_err) {
155
+ return {
156
+ node: node,
157
+ message: forbid_err,
158
+ };
159
+ }
160
+
161
+ // 检查并推荐更合适的词汇
162
+ var recommend_err = this._checkAndRecommend(method_name, 'method-name');
163
+ if (recommend_err) {
164
+ return {
165
+ node: node,
166
+ message: recommend_err,
167
+ };
168
+ }
169
+
170
+ return null;
171
+ } catch (error) {
172
+ console.error('检测方法名时出错:', error);
173
+ return null;
174
+ }
175
+ };
176
+
177
+ /**
178
+ * 检测函数名
179
+ * @param {string} function_name 函数名
180
+ * @param {object} node AST节点
181
+ * @returns {object|null} 错误信息或null
182
+ */
183
+ Detector.prototype._checkFunctionName = function (function_name, node) {
184
+ try {
185
+ var rule = this.config.getRule('function-name');
186
+ if (!rule) {
187
+ return null;
188
+ }
189
+
190
+ // 检查是否为忽略词
191
+ if (this._isIgnoredWord(function_name, 'function-name')) {
192
+ return null;
193
+ }
194
+
195
+ // 检查命名风格
196
+ var style_err = this._validate_naming_style(function_name, rule.styles, 'function-name');
197
+ if (style_err) {
198
+ return {
199
+ node: node,
200
+ message: style_err,
201
+ };
202
+ }
203
+
204
+ // 检查长度
205
+ var len_err = this._checkNameLength(function_name, rule.min, rule.max, 'function-name');
206
+ if (len_err) {
207
+ return {
208
+ node: node,
209
+ message: len_err,
210
+ };
211
+ }
212
+
213
+ // 检查单词长度
214
+ var word_err = this._checkWordLength(function_name, rule.single_word_len, 'function-name');
215
+ if (word_err) {
216
+ return {
217
+ node: node,
218
+ message: word_err,
219
+ };
220
+ }
221
+
222
+ // 检查禁止词汇
223
+ var forbid_err = this._checkForbiddenWords(
224
+ function_name,
225
+ 'function-name',
226
+ );
227
+ if (forbid_err) {
228
+ return {
229
+ node: node,
230
+ message: forbid_err,
231
+ };
232
+ }
233
+
234
+ // 检查并推荐更合适的词汇
235
+ var recommend_err = this._checkAndRecommend(function_name, 'function-name');
236
+ if (recommend_err) {
237
+ return {
238
+ node: node,
239
+ message: recommend_err,
240
+ };
241
+ }
242
+
243
+ return null;
244
+ } catch (error) {
245
+ console.error('检测函数名时出错:', error);
246
+ return null;
247
+ }
248
+ };
249
+
250
+ /**
251
+ * 检测变量名
252
+ * @param {string} variable_name 变量名
253
+ * @param {object} node AST节点
254
+ * @returns {object|null} 错误信息或null
255
+ */
256
+ Detector.prototype._checkVariableName = function (variable_name, node) {
257
+ try {
258
+ var rule = this.config.getRule('variable-name');
259
+ if (!rule) {
260
+ return null;
261
+ }
262
+
263
+ // 检查是否为忽略词
264
+ if (this._isIgnoredWord(variable_name, 'variable-name')) {
265
+ return null;
266
+ }
267
+
268
+ // 检查命名风格
269
+ var style_err = this._validate_naming_style(variable_name, rule.styles, 'variable-name');
270
+ if (style_err) {
271
+ return {
272
+ node: node,
273
+ message: style_err,
274
+ };
275
+ }
276
+
277
+ // 检查长度
278
+ var len_err = this._checkNameLength(variable_name, rule.min, rule.max, 'variable-name');
279
+ if (len_err) {
280
+ return {
281
+ node: node,
282
+ message: len_err,
283
+ };
284
+ }
285
+
286
+ // 检查单词长度
287
+ var word_err = this._checkWordLength(variable_name, rule.single_word_len, 'variable-name');
288
+ if (word_err) {
289
+ return {
290
+ node: node,
291
+ message: word_err,
292
+ };
293
+ }
294
+
295
+ // 检查禁止词汇
296
+ var forbid_err = this._checkForbiddenWords(
297
+ variable_name,
298
+ 'variable-name',
299
+ );
300
+ if (forbid_err) {
301
+ return {
302
+ node: node,
303
+ message: forbid_err,
304
+ };
305
+ }
306
+
307
+ return null;
308
+ } catch (error) {
309
+ console.error('检测变量名时出错:', error);
310
+ return null;
311
+ }
312
+ };
313
+
314
+ /**
315
+ * 检测参数名
316
+ * @param {string} param_name 参数名
317
+ * @param {object} node AST节点
318
+ * @returns {object|null} 错误信息或null
319
+ */
320
+ Detector.prototype._checkParamName = function (param_name, node) {
321
+ try {
322
+ var rule = this.config.getRule('param-name');
323
+ if (!rule) {
324
+ return null;
325
+ }
326
+
327
+ // 检查是否为忽略词
328
+ if (this._isIgnoredWord(param_name, 'param-name')) {
329
+ return null;
330
+ }
331
+
332
+ // 检查命名风格
333
+ var style_err = this._validate_naming_style(param_name, rule.styles, 'param-name');
334
+ if (style_err) {
335
+ return {
336
+ node: node,
337
+ message: style_err,
338
+ };
339
+ }
340
+
341
+ // 检查长度
342
+ var len_err = this._checkNameLength(param_name, rule.min, rule.max, 'param-name');
343
+ if (len_err) {
344
+ return {
345
+ node: node,
346
+ message: len_err,
347
+ };
348
+ }
349
+
350
+ // 检查单词长度
351
+ var word_err = this._checkWordLength(param_name, rule.single_word_len, 'param-name');
352
+ if (word_err) {
353
+ return {
354
+ node: node,
355
+ message: word_err,
356
+ };
357
+ }
358
+
359
+ // 检查禁止词汇
360
+ var forbid_err = this._checkForbiddenWords(param_name, 'param-name');
361
+ if (forbid_err) {
362
+ return {
363
+ node: node,
364
+ message: forbid_err,
365
+ };
366
+ }
367
+
368
+ return null;
369
+ } catch (error) {
370
+ console.error('检测参数名时出错:', error);
371
+ return null;
372
+ }
373
+ };
374
+
375
+ /**
376
+ * 检测常量名
377
+ * @param {string} constant_name 常量名
378
+ * @param {object} node AST节点
379
+ * @param {object} val_node 值节点(用于识别基础值)
380
+ * @returns {object|null} 错误信息或null
381
+ */
382
+ Detector.prototype._checkConstantName = function (constant_name, node, val_node) {
383
+ try {
384
+ var rule = this.config.getRule('constant-name');
385
+ if (!rule) {
386
+ return null;
387
+ }
388
+
389
+ // 检查是否为忽略词
390
+ if (this._isIgnoredWord(constant_name, 'constant-name')) {
391
+ return null;
392
+ }
393
+
394
+ // 检查是否为解构导入(从模块导入的变量)
395
+ var is_destructured_import = this._isDestructuredImport(node);
396
+
397
+ // 如果是解构导入,则不进行常量检测
398
+ if (is_destructured_import) {
399
+ return null;
400
+ }
401
+
402
+ // 检查是否为复杂类型(方法、函数、实例等)
403
+ var is_complex_type = this._isComplexType(val_node);
404
+
405
+ // 如果是复杂类型,则不进行常量检测
406
+ if (is_complex_type) {
407
+ return null;
408
+ }
409
+
410
+ // 检查是否为基础值类型
411
+ var is_base_value = this._isBaseValue(val_node);
412
+
413
+ // 如果不是基础值也不是复杂类型(可能是其他类型),则不进行常量检测
414
+ if (!is_base_value) {
415
+ return null;
416
+ }
417
+
418
+ // 检查命名风格
419
+ var style_err = this._validate_naming_style(constant_name, rule.styles, 'constant-name');
420
+ if (style_err) {
421
+ return {
422
+ node: node,
423
+ message: style_err,
424
+ };
425
+ }
426
+
427
+ // 检查长度
428
+ var len_err = this._checkNameLength(constant_name, rule.min, rule.max, 'constant-name');
429
+ if (len_err) {
430
+ return {
431
+ node: node,
432
+ message: len_err,
433
+ };
434
+ }
435
+
436
+ // 检查单词长度
437
+ var word_err = this._checkWordLength(constant_name, rule.single_word_len, 'constant-name');
438
+ if (word_err) {
439
+ return {
440
+ node: node,
441
+ message: word_err,
442
+ };
443
+ }
444
+
445
+ // 检查禁止词汇
446
+ var forbid_err = this._checkForbiddenWords(constant_name, 'constant-name');
447
+ if (forbid_err) {
448
+ return {
449
+ node: node,
450
+ message: forbid_err,
451
+ };
452
+ }
453
+
454
+ // 检查并推荐更合适的词汇
455
+ var rec_err = this._checkAndRecommend(constant_name, 'constant-name');
456
+ if (rec_err) {
457
+ return {
458
+ node: node,
459
+ message: rec_err,
460
+ };
461
+ }
462
+
463
+ return null;
464
+ } catch (error) {
465
+ console.error('检测常量名时出错:', error);
466
+ return null;
467
+ }
468
+ };
469
+
470
+ /**
471
+ * 验证命名风格
472
+ * @param {string} name 名称
473
+ * @param {Array} styles 允许的风格列表
474
+ * @param {string} name_type 名称类型
475
+ * @returns {string|null} 错误信息或null
476
+ */
477
+ Detector.prototype._validate_naming_style = function (name, styles, name_type) {
478
+ if (!name || !styles || !Array.isArray(styles)) {
479
+ return null;
480
+ }
481
+
482
+ for (var i = 0; i < styles.length; i++) {
483
+ var style = styles[i];
484
+ var regex = this.config.getRegex(style);
485
+ if (regex && regex.test(name)) {
486
+ return null;
487
+ }
488
+ }
489
+
490
+ var style_names = styles.join('或');
491
+
492
+ var name_type_desc = this.config.name_type_map[name_type] || '名称';
493
+
494
+ return name_type_desc + '\'' + name + '\'不符合' + style_names + '命名风格';
495
+ };
496
+
497
+ /**
498
+ * 检查名称长度
499
+ * @param {string} name 名称
500
+ * @param {number} min 最小长度
501
+ * @param {number} max 最大长度
502
+ * @returns {string|null} 错误信息或null
503
+ */
504
+ Detector.prototype._checkNameLength = function (name, min, max, name_type) {
505
+ if (!name) {
506
+ return '名称不能为空';
507
+ }
508
+
509
+ var name_type_desc = this.config.name_type_map[name_type] || '名称';
510
+ var len = name.length;
511
+ if (len < min) {
512
+ return name_type_desc + '\'' + name + '\'长度过短,最小长度为' + min + '字符';
513
+ }
514
+
515
+ if (len > max) {
516
+ return name_type_desc + '\'' + name + '\'长度过长,最大长度为' + max + '字符';
517
+ }
518
+
519
+ return null;
520
+ };
521
+
522
+ /**
523
+ * 检查单词长度
524
+ * @param {string} name 名称
525
+ * @param {number} max_word_len 最大单词长度
526
+ * @returns {string|null} 错误信息或null
527
+ */
528
+ Detector.prototype._checkWordLength = function (name, max_word_len, name_type) {
529
+ if (!name || !max_word_len) {
530
+ return null;
531
+ }
532
+
533
+ var name_type_desc = this.config.name_type_map[name_type] || '名称';
534
+ // 分割单词(根据命名风格)
535
+ var words = [];
536
+
537
+ // 处理私有标识符(开头的下划线)
538
+ var processed_name = name;
539
+ var has_private_prefix = false;
540
+
541
+ if (name.startsWith('_')) {
542
+ has_private_prefix = true;
543
+ processed_name = name.substring(1); // 去掉开头的下划线
544
+ }
545
+
546
+ if (processed_name.includes('_')) {
547
+ words = processed_name.split('_');
548
+ } else if (processed_name.includes('-')) {
549
+ words = processed_name.split('-');
550
+ } else {
551
+ // 驼峰命名法分割(保持原词大小写)
552
+ words = processed_name.split(/(?=[A-Z])/);
553
+ }
554
+
555
+ // 如果存在私有标识符,添加空字符串表示私有标识符(不检查长度)
556
+ if (has_private_prefix) {
557
+ words.unshift('_');
558
+ }
559
+
560
+ for (var i = 0; i < words.length; i++) {
561
+ var word = words[i];
562
+ // 跳过空字符串和私有标识符(单个下划线)
563
+ if (!word || word === '_') {
564
+ continue;
565
+ }
566
+
567
+ if (word.length > max_word_len) {
568
+ // 生成推荐命名
569
+ var recommended_name = this._generateRecommendedName(name, word, name_type);
570
+ var recommendation_text = '';
571
+ if (recommended_name) {
572
+ recommendation_text = ',推荐名为\'' + recommended_name + '\'';
573
+ }
574
+
575
+ return (
576
+ name_type_desc +
577
+ '\'' +
578
+ name +
579
+ '\'中的单词\'' +
580
+ word +
581
+ '\'过长,最大长度为' +
582
+ max_word_len +
583
+ '字符' +
584
+ recommendation_text
585
+ );
586
+ }
587
+ }
588
+
589
+ return null;
590
+ };
591
+
592
+ /**
593
+ * 检查禁止词汇
594
+ * @param {string} name 名称
595
+ * @param {string} name_type 名称类型
596
+ * @returns {string|null} 错误信息或null
597
+ */
598
+ Detector.prototype._checkForbiddenWords = function (name, name_type) {
599
+ if (!name || !name_type) {
600
+ return null;
601
+ }
602
+
603
+ var forbidden_words = this.config.getForbiddenWords(name_type);
604
+ if (!forbidden_words || !Array.isArray(forbidden_words)) {
605
+ return null;
606
+ }
607
+
608
+ var name_type_desc = this.config.name_type_map[name_type] || '名称';
609
+ var name_lower = name.toLowerCase();
610
+
611
+ // 如果名称本身就是禁止词汇(即单个单词),则允许使用
612
+ for (var i = 0; i < forbidden_words.length; i++) {
613
+ var forbidden_word = forbidden_words[i].toLowerCase();
614
+ if (name_lower === forbidden_word) {
615
+ return null; // 单个单词允许使用
616
+ }
617
+ }
618
+
619
+ // 检查名称是否包含禁止词汇作为拼接词(即名称由多个单词组成)
620
+ for (var i = 0; i < forbidden_words.length; i++) {
621
+ var forbidden_word = forbidden_words[i].toLowerCase();
622
+ if (name_lower.includes(forbidden_word) && name_lower !== forbidden_word) {
623
+ return name_type_desc + '\'' + name + '\'包含禁止拼接词\'' + forbidden_word + '\'';
624
+ }
625
+ }
626
+
627
+ return null;
628
+ };
629
+
630
+ /**
631
+ * 获取属性类型
632
+ * @param {object} val_node 属性值节点
633
+ * @param {string} prop_name 属性名
634
+ * @param {object} parent_node 父节点
635
+ * @returns {string} 属性类型
636
+ */
637
+ Detector.prototype._getPropType = function (val_node, prop_name, parent_node) {
638
+ if (!val_node) {
639
+ return 'undefined_value'; // 未赋值类型
640
+ }
641
+
642
+ // 检查是否为null值
643
+ if (val_node.type === 'NullLiteral') {
644
+ return 'null_value'; // null值类型
645
+ }
646
+
647
+ // 检查是否为对象方法(在对象字面量中的函数)
648
+ if (
649
+ val_node &&
650
+ (val_node.type === 'FunctionExpression' ||
651
+ val_node.type === 'ArrowFunctionExpression')
652
+ ) {
653
+ return 'method'; // 对象方法类型
654
+ }
655
+
656
+ // 检查是否为类引用(属性类)
657
+ if (
658
+ val_node.type === 'Identifier' &&
659
+ val_node.name &&
660
+ val_node.name[0] === val_node.name[0].toUpperCase()
661
+ ) {
662
+ // 检查是否是类名引用(通常类名使用PascalCase)
663
+ return 'class'; // 属性类类型
664
+ }
665
+
666
+ // 检查是否为类实例(new表达式)
667
+ if (val_node.type === 'NewExpression') {
668
+ return 'instance_class'; // 属性实例类类型
669
+ }
670
+
671
+ // 检查是否为函数调用(可能返回实例)
672
+ if (val_node.type === 'CallExpression') {
673
+ // 检查是否调用的是构造函数
674
+ if (
675
+ val_node.callee &&
676
+ val_node.callee.type === 'Identifier' &&
677
+ val_node.callee.name &&
678
+ val_node.callee.name[0] === val_node.callee.name[0].toUpperCase()
679
+ ) {
680
+ return 'instance_class'; // 属性实例类类型
681
+ }
682
+ return 'value'; // 默认值类型
683
+ }
684
+
685
+ return 'value';
686
+ };
687
+
688
+ /**
689
+ * 检测属性名
690
+ * @param {string} prop_name 属性名
691
+ * @param {object} node AST节点
692
+ * @param {object} val_node 属性值节点
693
+ * @param {object} parent_node 父节点
694
+ * @returns {object|null} 错误信息或null
695
+ */
696
+ Detector.prototype._checkPropertyName = function (
697
+ prop_name,
698
+ node,
699
+ val_node,
700
+ parent_node,
701
+ ) {
702
+ try {
703
+ // 检查是否为解构导入中的属性
704
+ var is_destructured_import = this._isDestructuredImportProperty(node, parent_node);
705
+
706
+ // 如果是解构导入中的属性,则不进行属性名检测
707
+ if (is_destructured_import) {
708
+ return null;
709
+ }
710
+
711
+ // 获取属性类型
712
+ var prop_type = this._getPropType(val_node, prop_name, parent_node);
713
+ var rule_type = '';
714
+
715
+ // 根据属性类型选择对应的规则
716
+ // 对于null值和未赋值属性,直接跳过命名规范检测
717
+ if (prop_type === 'null_value' || prop_type === 'undefined_value') {
718
+ return null; // 不进行命名规范检测
719
+ }
720
+
721
+ switch (prop_type) {
722
+ case 'class':
723
+ rule_type = 'property-class-name';
724
+ break;
725
+ case 'instance_class':
726
+ rule_type = 'property-instance-class-name';
727
+ break;
728
+ case 'method':
729
+ rule_type = 'property-method-name';
730
+ break;
731
+ case 'value':
732
+ default:
733
+ rule_type = 'property-value-name';
734
+ break;
735
+ }
736
+
737
+ var rule = this.config.getRule(rule_type);
738
+ if (!rule) {
739
+ return null;
740
+ }
741
+
742
+ // 检查命名风格
743
+ var style_err = null;
744
+
745
+ if (rule_type === 'property-value-name') {
746
+ // 对于属性值名,支持私有变量命名规范(_snake_case)、变量命名规范(snake_case)或常量命名规范(UPPER_SNAKE_CASE)
747
+ var private_style_err = this._validate_naming_style(prop_name, ['_snake_case'], rule_type);
748
+ var variable_style_err = this._validate_naming_style(prop_name, ['snake_case'], rule_type);
749
+ var constant_style_err = this._validate_naming_style(prop_name, ['UPPER_SNAKE_CASE'], rule_type);
750
+
751
+ // 只有当所有风格检查都失败时才报错
752
+ if (private_style_err && variable_style_err && constant_style_err) {
753
+ style_err = '属性值名\'' + prop_name + '\'不符合_snake_case、snake_case或UPPER_SNAKE_CASE命名风格';
754
+ }
755
+ } else if (rule_type === 'property-method-name') {
756
+ // 属性方法:支持公开方法(camelCase)和私有方法(_camelCase)
757
+ if (prop_name.startsWith('_')) {
758
+ // 私有方法:检查是否符合私有方法命名规范
759
+ style_err = this._validate_naming_style(prop_name, ['_camelCase'], rule_type);
760
+ } else {
761
+ // 公开方法:检查是否符合公开方法命名规范
762
+ style_err = this._validate_naming_style(prop_name, rule.styles, rule_type);
763
+ }
764
+ } else {
765
+ // 其他属性类型:使用原有逻辑
766
+ style_err = this._validate_naming_style(prop_name, rule.styles, rule_type);
767
+ }
768
+
769
+ if (style_err) {
770
+ return {
771
+ node: node,
772
+ message: style_err,
773
+ };
774
+ }
775
+
776
+ // 检查长度
777
+ var len_err = this._checkNameLength(prop_name, rule.min, rule.max, rule_type);
778
+ if (len_err) {
779
+ return {
780
+ node: node,
781
+ message: len_err,
782
+ };
783
+ }
784
+
785
+ // 检查单词长度
786
+ var word_err = this._checkWordLength(prop_name, rule.single_word_len, rule_type);
787
+ if (word_err) {
788
+ return {
789
+ node: node,
790
+ message: word_err,
791
+ };
792
+ }
793
+
794
+ // 检查禁止词汇
795
+ var forbid_err = this._checkForbiddenWords(prop_name, rule_type);
796
+ if (forbid_err) {
797
+ return {
798
+ node: node,
799
+ message: forbid_err,
800
+ };
801
+ }
802
+
803
+ return null;
804
+ } catch (error) {
805
+ console.error('检测属性名时出错:', error);
806
+ return null;
807
+ }
808
+ };
809
+
810
+ /**
811
+ * 检查并推荐更合适的词汇
812
+ * @param {string} name 名称
813
+ * @param {string} name_type 名称类型
814
+ * @returns {string|null} 推荐信息或null
815
+ */
816
+ Detector.prototype._checkAndRecommend = function (name, name_type) {
817
+ try {
818
+ var rec_words = this.config.getRecommendedWords(name_type);
819
+ if (!rec_words || Object.keys(rec_words).length === 0) {
820
+ return null;
821
+ }
822
+
823
+ var name_lower = name.toLowerCase();
824
+
825
+ var name_type_desc = this.config.name_type_map[name_type] || '名称';
826
+ // 检查每个推荐词映射
827
+ for (var rec_word in rec_words) {
828
+ if (rec_words.hasOwnProperty(rec_word)) {
829
+ var original_words = rec_words[rec_word];
830
+
831
+ // 检查名称是否包含任何一个原词
832
+ for (var i = 0; i < original_words.length; i++) {
833
+ var original_word = original_words[i].toLowerCase();
834
+ if (name_lower.includes(original_word)) {
835
+ return name_type_desc + '建议使用\'' + rec_word + '\'替代\'' + original_words[i] + '\'以获得更短的命名';
836
+ }
837
+ }
838
+ }
839
+ }
840
+
841
+ return null;
842
+ } catch (error) {
843
+ console.error('检查并推荐更合适的词汇时出错:', error);
844
+ return null;
845
+ }
846
+ };
847
+
848
+ /**
849
+ * 检查值是否为基础值类型
850
+ * @param {object} val_node 值节点
851
+ * @returns {boolean} 是否为基础值
852
+ */
853
+ Detector.prototype._isBaseValue = function (val_node) {
854
+ try {
855
+ if (!val_node) {
856
+ return false;
857
+ }
858
+
859
+ // 检查是否为基础值类型
860
+ var is_base_value = false;
861
+
862
+ switch (val_node.type) {
863
+ case 'Literal': // 字面量:数字、字符串、布尔值
864
+ is_base_value = true;
865
+ break;
866
+ case 'ArrayExpression': // 数组字面量
867
+ is_base_value = true;
868
+ break;
869
+ case 'ObjectExpression': // 对象字面量
870
+ is_base_value = true;
871
+ break;
872
+ case 'UnaryExpression': // 一元表达式(如 -1, +100)
873
+ if (val_node.operator === '-' || val_node.operator === '+') {
874
+ is_base_value = true;
875
+ }
876
+ break;
877
+ default:
878
+ is_base_value = false;
879
+ }
880
+
881
+ return is_base_value;
882
+ } catch (error) {
883
+ console.error('检查值是否为基础值类型时出错:', error);
884
+ return false;
885
+ }
886
+ };
887
+
888
+ /**
889
+ * 检查值是否为复杂类型(方法、函数、实例等)
890
+ * @param {object} val_node 值节点
891
+ * @returns {boolean} 是否为复杂类型
892
+ */
893
+ Detector.prototype._isComplexType = function (val_node) {
894
+ try {
895
+ if (!val_node) {
896
+ return false;
897
+ }
898
+
899
+ // 检查是否为复杂类型
900
+ var is_complex_type = false;
901
+
902
+ switch (val_node.type) {
903
+ case 'FunctionExpression': // 函数表达式
904
+ case 'ArrowFunctionExpression': // 箭头函数
905
+ case 'NewExpression': // new 实例化
906
+ case 'CallExpression': // 函数调用
907
+ case 'MemberExpression': // 成员表达式
908
+ case 'Identifier': // 标识符(可能是变量或函数)
909
+ case 'ClassExpression': // 类表达式
910
+ case 'ThisExpression': // this表达式
911
+ case 'TemplateLiteral': // 模板字符串
912
+ is_complex_type = true;
913
+ break;
914
+ default:
915
+ is_complex_type = false;
916
+ }
917
+
918
+ return is_complex_type;
919
+ } catch (error) {
920
+ console.error('检查值是否为复杂类型时出错:', error);
921
+ return false;
922
+ }
923
+ };
924
+
925
+ /**
926
+ * 检查是否为解构导入
927
+ * @param {object} node AST节点
928
+ * @returns {boolean} 是否为解构导入
929
+ */
930
+ Detector.prototype._isDestructuredImport = function (node) {
931
+ try {
932
+ if (!node || !node.parent) {
933
+ return false;
934
+ }
935
+
936
+ // 检查是否为解构导入模式
937
+ var is_destructured = false;
938
+
939
+ // 情况1:节点是Property.key(解构赋值中的属性键)
940
+ if (node.parent.type === 'Property' && node.parent.key === node) {
941
+ var property = node.parent;
942
+
943
+ // 检查Property的父节点是否为ObjectPattern
944
+ if (property.parent && property.parent.type === 'ObjectPattern') {
945
+ var object_pattern = property.parent;
946
+
947
+ // 检查ObjectPattern的父节点是否为VariableDeclarator
948
+ if (object_pattern.parent && object_pattern.parent.type === 'VariableDeclarator') {
949
+ var declarator = object_pattern.parent;
950
+
951
+ // 检查右侧是否为require调用或其他模块导入
952
+ if (declarator.init) {
953
+ var init_type = declarator.init.type;
954
+
955
+ // 常见的模块导入方式
956
+ if (init_type === 'CallExpression' &&
957
+ declarator.init.callee &&
958
+ declarator.init.callee.name === 'require') {
959
+ is_destructured = true;
960
+ }
961
+
962
+ // 如果是ImportDeclaration(ES6导入)
963
+ if (init_type === 'ImportExpression') {
964
+ is_destructured = true;
965
+ }
966
+ }
967
+ }
968
+ }
969
+ }
970
+
971
+ // 情况2:节点是VariableDeclarator(简单变量声明)
972
+ else if (node.parent.type === 'VariableDeclarator') {
973
+ var declarator = node.parent;
974
+
975
+ // 检查是否为解构模式(ObjectPattern或ArrayPattern)
976
+ if (declarator.id && declarator.id.type === 'ObjectPattern') {
977
+ // 检查右侧是否为require调用或其他模块导入
978
+ if (declarator.init) {
979
+ var init_type = declarator.init.type;
980
+
981
+ // 常见的模块导入方式
982
+ if (init_type === 'CallExpression' &&
983
+ declarator.init.callee &&
984
+ declarator.init.callee.name === 'require') {
985
+ is_destructured = true;
986
+ }
987
+
988
+ // 如果是ImportDeclaration(ES6导入)
989
+ if (init_type === 'ImportExpression') {
990
+ is_destructured = true;
991
+ }
992
+ }
993
+ }
994
+ }
995
+
996
+ return is_destructured;
997
+ } catch (error) {
998
+ console.error('检查是否为解构导入时出错:', error);
999
+ return false;
1000
+ }
1001
+ };
1002
+
1003
+ /**
1004
+ * 检查是否为解构导入中的属性
1005
+ * @param {object} node 属性节点
1006
+ * @param {object} parent_node 父节点
1007
+ * @returns {boolean} 是否为解构导入中的属性
1008
+ */
1009
+ Detector.prototype._isDestructuredImportProperty = function (node, parent_node) {
1010
+ try {
1011
+ if (!node || !parent_node) {
1012
+ return false;
1013
+ }
1014
+
1015
+ // 检查父节点是否为ObjectPattern(解构模式)
1016
+ if (parent_node.type === 'ObjectPattern') {
1017
+ // 检查父节点的父节点是否为VariableDeclarator
1018
+ if (parent_node.parent && parent_node.parent.type === 'VariableDeclarator') {
1019
+ var declarator = parent_node.parent;
1020
+
1021
+ // 检查右侧是否为require调用或其他模块导入
1022
+ if (declarator.init) {
1023
+ var init_type = declarator.init.type;
1024
+
1025
+ // 常见的模块导入方式
1026
+ if (init_type === 'CallExpression' &&
1027
+ declarator.init.callee &&
1028
+ declarator.init.callee.name === 'require') {
1029
+ return true;
1030
+ }
1031
+
1032
+ // 如果是ImportDeclaration(ES6导入)
1033
+ if (init_type === 'ImportExpression') {
1034
+ return true;
1035
+ }
1036
+ }
1037
+ }
1038
+ }
1039
+
1040
+ return false;
1041
+ } catch (error) {
1042
+ console.error('检查是否为解构导入中的属性时出错:', error);
1043
+ return false;
1044
+ }
1045
+ };
1046
+
1047
+ /**
1048
+ * 检查常量名是否符合规范
1049
+ * @param {string} constant_name 常量名
1050
+ * @returns {boolean} 是否符合规范
1051
+ */
1052
+ Detector.prototype._isConstantNameValid = function (constant_name) {
1053
+ try {
1054
+ var rule = this.config.getRule('constant-name');
1055
+ if (!rule) {
1056
+ return false;
1057
+ }
1058
+
1059
+ // 检查命名风格
1060
+ var style_err = this._validate_naming_style(constant_name, rule.styles, 'constant-name');
1061
+ return !style_err;
1062
+ } catch (error) {
1063
+ console.error('检查常量名是否符合规范时出错:', error);
1064
+ return false;
1065
+ }
1066
+ };
1067
+
1068
+ /**
1069
+ * 检查是否为忽略词
1070
+ * @param {string} name 名称
1071
+ * @param {string} name_type 名称类型
1072
+ * @returns {boolean} 是否为忽略词
1073
+ */
1074
+ Detector.prototype._isIgnoredWord = function (name, name_type) {
1075
+ try {
1076
+ var ignored_words = this.config.getIgnoredWords(name_type);
1077
+ if (!ignored_words || !Array.isArray(ignored_words)) {
1078
+ return false;
1079
+ }
1080
+
1081
+ var name_lower = name.toLowerCase();
1082
+ for (var i = 0; i < ignored_words.length; i++) {
1083
+ if (ignored_words[i].toLowerCase() === name_lower) {
1084
+ return true;
1085
+ }
1086
+ }
1087
+
1088
+ return false;
1089
+ } catch (error) {
1090
+ console.error('检查是否为忽略词时出错:', error);
1091
+ return false;
1092
+ }
1093
+ };
1094
+
1095
+ /**
1096
+ * 生成推荐命名
1097
+ * @param {string} original_name 原始名称
1098
+ * @param {string} long_word 过长的单词
1099
+ * @param {string} name_type 名称类型
1100
+ * @returns {string|null} 推荐命名或null
1101
+ */
1102
+ Detector.prototype._generateRecommendedName = function (original_name, long_word, name_type) {
1103
+ try {
1104
+ // 获取推荐词映射
1105
+ var recommended_words = this.config.getRecommendedWords(name_type);
1106
+ if (!recommended_words || Object.keys(recommended_words).length === 0) {
1107
+ return null;
1108
+ }
1109
+
1110
+ var long_word_lower = long_word.toLowerCase();
1111
+
1112
+ // 检查推荐词映射中是否有对应的缩写
1113
+ for (var short_word in recommended_words) {
1114
+ if (recommended_words.hasOwnProperty(short_word)) {
1115
+ var original_words = recommended_words[short_word];
1116
+
1117
+ // 检查过长的单词是否在推荐词的原词列表中
1118
+ for (var i = 0; i < original_words.length; i++) {
1119
+ var original_word = original_words[i].toLowerCase();
1120
+ if (long_word_lower === original_word) {
1121
+ // 生成推荐命名:将原始名称中的长单词替换为推荐的缩写
1122
+ var recommended_name = original_name.replace(long_word, short_word);
1123
+ return recommended_name;
1124
+ }
1125
+ }
1126
+ }
1127
+ }
1128
+
1129
+ return null;
1130
+ } catch (error) {
1131
+ console.error('生成推荐命名时出错:', error);
1132
+ return null;
1133
+ }
1134
+ };
1135
+
1136
+ /**
1137
+ * 检测解构赋值中的常量名
1138
+ * @param {string} constant_name 常量名
1139
+ * @param {object} node AST节点
1140
+ * @returns {object|null} 错误信息或null
1141
+ */
1142
+ Detector.prototype._checkConstantNameForDestructuring = function (constant_name, node) {
1143
+ try {
1144
+ var rule = this.config.getRule('constant-name');
1145
+ if (!rule) {
1146
+ return null;
1147
+ }
1148
+
1149
+ // 检查是否为忽略词
1150
+ if (this._isIgnoredWord(constant_name, 'constant-name')) {
1151
+ return null;
1152
+ }
1153
+
1154
+ // 检查是否为解构导入(从模块导入的变量)
1155
+ var is_destructured_import = this._isDestructuredImport(node);
1156
+
1157
+ // 如果是解构导入,则不进行常量检测
1158
+ if (is_destructured_import) {
1159
+ return null;
1160
+ }
1161
+
1162
+ // 检查命名风格
1163
+ var style_err = this._validate_naming_style(constant_name, rule.styles, 'constant-name');
1164
+ if (style_err) {
1165
+ return {
1166
+ node: node,
1167
+ message: style_err,
1168
+ };
1169
+ }
1170
+
1171
+ // 检查并推荐更合适的词汇
1172
+ var rec_err = this._checkAndRecommend(constant_name, 'constant-name');
1173
+ if (rec_err) {
1174
+ return {
1175
+ node: node,
1176
+ message: rec_err,
1177
+ };
1178
+ }
1179
+
1180
+ // 检查长度
1181
+ var len_err = this._checkNameLength(constant_name, rule.min, rule.max, 'constant-name');
1182
+ if (len_err) {
1183
+ return {
1184
+ node: node,
1185
+ message: len_err,
1186
+ };
1187
+ }
1188
+
1189
+ // 检查单词长度
1190
+ var word_err = this._checkWordLength(constant_name, rule.single_word_len, 'constant-name');
1191
+ if (word_err) {
1192
+ return {
1193
+ node: node,
1194
+ message: word_err,
1195
+ };
1196
+ }
1197
+
1198
+ // 检查禁止词汇
1199
+ var forbid_err = this._checkForbiddenWords(constant_name, 'constant-name');
1200
+ if (forbid_err) {
1201
+ return {
1202
+ node: node,
1203
+ message: forbid_err,
1204
+ };
1205
+ }
1206
+
1207
+ return null;
1208
+ } catch (error) {
1209
+ console.error('检测解构赋值常量名时出错:', error);
1210
+ return null;
1211
+ }
1212
+ };
1213
+
1214
+ module.exports = { Detector };