mm_eslint 1.4.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/config.js +78 -44
  2. package/detector.js +2602 -367
  3. package/index.js +984 -78
  4. package/package.json +1 -1
  5. package/README_EN.md +0 -410
package/index.js CHANGED
@@ -14,6 +14,75 @@ function createNamingRules() {
14
14
  var config = new Config({});
15
15
  var detector = new Detector(config);
16
16
 
17
+ /**
18
+ * 检查节点是否为参数名或参数引用
19
+ * @param {object} node AST节点
20
+ * @returns {boolean} 是否为参数名或参数引用
21
+ */
22
+ function _isParameterName(node) {
23
+ if (!node || !node.parent) {
24
+ return false;
25
+ }
26
+
27
+ // 检查是否为函数参数声明
28
+ var parent = node.parent;
29
+ if (parent.type === 'FunctionDeclaration' ||
30
+ parent.type === 'FunctionExpression' ||
31
+ parent.type === 'ArrowFunctionExpression') {
32
+ if (parent.params && Array.isArray(parent.params)) {
33
+ for (var i = 0; i < parent.params.length; i++) {
34
+ if (parent.params[i] === node) {
35
+ return true;
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+ // 检查是否为变量声明中的参数
42
+ if (parent.type === 'VariableDeclarator' && parent.id === node) {
43
+ var grand_parent = parent.parent;
44
+ if (grand_parent && grand_parent.type === 'VariableDeclaration') {
45
+ // 检查是否为函数参数
46
+ var great_grand_parent = grand_parent.parent;
47
+ if (great_grand_parent &&
48
+ (great_grand_parent.type === 'FunctionDeclaration' ||
49
+ great_grand_parent.type === 'FunctionExpression' ||
50
+ great_grand_parent.type === 'ArrowFunctionExpression')) {
51
+ return true;
52
+ }
53
+ }
54
+ }
55
+
56
+ // 检查是否为参数引用(在函数调用中)
57
+ if (node.type === 'Identifier') {
58
+ // 检查是否在函数调用表达式中
59
+ if (parent.type === 'CallExpression' && parent.callee === node) {
60
+ // 检查是否在函数作用域内
61
+ var current_scope = parent;
62
+ while (current_scope) {
63
+ // 检查当前作用域是否为函数
64
+ if (current_scope.type === 'FunctionDeclaration' ||
65
+ current_scope.type === 'FunctionExpression' ||
66
+ current_scope.type === 'ArrowFunctionExpression') {
67
+ // 检查函数参数中是否有同名参数
68
+ if (current_scope.params && Array.isArray(current_scope.params)) {
69
+ for (var i = 0; i < current_scope.params.length; i++) {
70
+ var param = current_scope.params[i];
71
+ if (param.type === 'Identifier' && param.name === node.name) {
72
+ return true;
73
+ }
74
+ }
75
+ }
76
+ break;
77
+ }
78
+ current_scope = current_scope.parent;
79
+ }
80
+ }
81
+ }
82
+
83
+ return false;
84
+ }
85
+
17
86
  return {
18
87
  'class-name': {
19
88
  meta: {
@@ -23,6 +92,7 @@ function createNamingRules() {
23
92
  category: 'Stylistic Issues',
24
93
  recommended: true,
25
94
  },
95
+ fixable: 'code',
26
96
  schema: [],
27
97
  },
28
98
  create: function (context) {
@@ -31,10 +101,23 @@ function createNamingRules() {
31
101
  var class_name = node.id.name;
32
102
  var err = detector._checkClassName(class_name, node);
33
103
  if (err) {
34
- context.report({
104
+ // 获取修复建议
105
+ var fix_suggestion = detector._getFixSuggestion(class_name, 'class-name', err.message);
106
+
107
+ var report_obj = {
35
108
  node: err.node,
36
109
  message: err.message,
37
- });
110
+ };
111
+
112
+ // 如果有修复建议,添加修复功能
113
+ if (fix_suggestion) {
114
+ report_obj.fix = function(fixer) {
115
+ return fixer.replaceText(node.id, fix_suggestion.fixed_name);
116
+ };
117
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
118
+ }
119
+
120
+ context.report(report_obj);
38
121
  }
39
122
  },
40
123
  };
@@ -49,6 +132,7 @@ function createNamingRules() {
49
132
  category: 'Stylistic Issues',
50
133
  recommended: true,
51
134
  },
135
+ fixable: 'code',
52
136
  schema: [],
53
137
  },
54
138
  create: function (context) {
@@ -58,10 +142,26 @@ function createNamingRules() {
58
142
  var function_name = node.id.name;
59
143
  var err = detector._checkFunctionName(function_name, node);
60
144
  if (err) {
61
- context.report({
145
+ // 获取修复建议
146
+ var fix_suggestion = detector._getFixSuggestion(function_name, 'function-name', err.message);
147
+
148
+ var report_obj = {
62
149
  node: err.node,
63
150
  message: err.message,
64
- });
151
+ };
152
+
153
+ // 如果有修复建议,添加修复功能
154
+ if (fix_suggestion) {
155
+ report_obj.fix = function(fixer) {
156
+ return fixer.replaceText(node.id, fix_suggestion.fixed_name);
157
+ };
158
+ // 只有当错误消息中不包含建议时才添加建议
159
+ if (!err.message.includes('建议使用:')) {
160
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
161
+ }
162
+ }
163
+
164
+ context.report(report_obj);
65
165
  }
66
166
  }
67
167
  },
@@ -70,10 +170,90 @@ function createNamingRules() {
70
170
  var function_name = node.id.name;
71
171
  var err = detector._checkFunctionName(function_name, node);
72
172
  if (err) {
73
- context.report({
173
+ // 获取修复建议
174
+ var fix_suggestion = detector._getFixSuggestion(function_name, 'function-name', err.message);
175
+
176
+ var report_obj = {
74
177
  node: err.node,
75
178
  message: err.message,
76
- });
179
+ };
180
+
181
+ // 如果有修复建议,添加修复功能
182
+ if (fix_suggestion) {
183
+ report_obj.fix = function(fixer) {
184
+ return fixer.replaceText(node.id, fix_suggestion.fixed_name);
185
+ };
186
+ // 只有当错误消息中不包含建议时才添加建议
187
+ if (!err.message.includes('建议使用:')) {
188
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
189
+ }
190
+ }
191
+
192
+ context.report(report_obj);
193
+ }
194
+ }
195
+ },
196
+ };
197
+ },
198
+ },
199
+
200
+ 'function-call-name': {
201
+ meta: {
202
+ type: 'suggestion',
203
+ docs: {
204
+ description: '检测函数调用名是否符合命名规范',
205
+ category: 'Stylistic Issues',
206
+ recommended: true,
207
+ },
208
+ fixable: 'code',
209
+ schema: [],
210
+ },
211
+ create: function (context) {
212
+ var self = this;
213
+
214
+ return {
215
+ CallExpression: function (node) {
216
+ if (node.callee && node.callee.type === 'Identifier') {
217
+ var function_name = node.callee.name;
218
+
219
+ // 检查是否为参数名,如果是参数名则跳过检测(避免与参数名规则冲突)
220
+ if (_isParameterName(node.callee)) {
221
+ return;
222
+ }
223
+
224
+ // 只检测函数调用名中的明显错误,如大写开头或蛇形命名
225
+ var err = detector._checkFunctionName(function_name, node);
226
+ if (err && (err.message.includes('不符合camelCase命名风格') || err.message.includes('不符合命名规范'))) {
227
+ // 获取修复建议
228
+ var fix_suggestion = detector._getFixSuggestion(function_name, 'function-name', err.message);
229
+
230
+ // 根据错误类型生成具体的错误消息
231
+ var error_detail = '';
232
+ if (err.message.includes('不符合camelCase命名风格')) {
233
+ error_detail = '不符合camelCase命名风格';
234
+ } else if (err.message.includes('长度过长')) {
235
+ error_detail = '长度过长,最大长度为20字符';
236
+ } else if (err.message.includes('长度过短')) {
237
+ error_detail = '长度过短,最小长度为1字符';
238
+ } else if (err.message.includes('单词过长')) {
239
+ error_detail = '包含的单词过长,最大长度为8字符';
240
+ } else {
241
+ error_detail = '不符合命名规范';
242
+ }
243
+
244
+ var report_obj = {
245
+ node: node.callee,
246
+ message: '函数调用名\'' + function_name + '\'' + error_detail + ',建议使用: ' + (fix_suggestion ? fix_suggestion.fixed_name : '符合规范的名称'),
247
+ };
248
+
249
+ // 如果有修复建议,添加修复功能
250
+ if (fix_suggestion) {
251
+ report_obj.fix = function(fixer) {
252
+ return fixer.replaceText(node.callee, fix_suggestion.fixed_name);
253
+ };
254
+ }
255
+
256
+ context.report(report_obj);
77
257
  }
78
258
  }
79
259
  },
@@ -89,6 +269,7 @@ function createNamingRules() {
89
269
  category: 'Stylistic Issues',
90
270
  recommended: true,
91
271
  },
272
+ fixable: 'code',
92
273
  schema: [],
93
274
  },
94
275
  create: function (context) {
@@ -98,10 +279,113 @@ function createNamingRules() {
98
279
  var method_name = node.key.name;
99
280
  var err = detector._checkMethodName(method_name, node);
100
281
  if (err) {
101
- context.report({
282
+ // 获取修复建议
283
+ var fix_suggestion = detector._getFixSuggestion(method_name, 'method-name', err.message);
284
+
285
+ var report_obj = {
102
286
  node: err.node,
103
287
  message: err.message,
104
- });
288
+ };
289
+
290
+ // 如果有修复建议,添加修复功能
291
+ if (fix_suggestion) {
292
+ report_obj.fix = function(fixer) {
293
+ return fixer.replaceText(node.key, fix_suggestion.fixed_name);
294
+ };
295
+ // 只有当错误消息中不包含建议时才添加建议
296
+ if (!err.message.includes('建议使用:')) {
297
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
298
+ }
299
+ }
300
+
301
+ context.report(report_obj);
302
+ }
303
+ }
304
+ },
305
+
306
+ // 处理原型方法定义:ClassName.prototype.method_name = function() {}
307
+ AssignmentExpression: function (node) {
308
+ if (node.left &&
309
+ node.left.type === 'MemberExpression' &&
310
+ node.left.object &&
311
+ node.left.object.type === 'MemberExpression' &&
312
+ node.left.object.property &&
313
+ node.left.object.property.name === 'prototype' &&
314
+ node.left.property &&
315
+ node.left.property.type === 'Identifier' &&
316
+ node.right &&
317
+ (node.right.type === 'FunctionExpression' || node.right.type === 'ArrowFunctionExpression')) {
318
+
319
+ var method_name = node.left.property.name;
320
+ var err = detector._checkMethodName(method_name, node);
321
+ if (err) {
322
+ // 检查是否为建议类型(不是错误)
323
+ if (err.type === 'suggestion') {
324
+ // 建议性提示,直接使用返回的错误信息
325
+ var report_obj = {
326
+ node: node.left.property,
327
+ message: err.message,
328
+ };
329
+ } else {
330
+ // 错误性提示,直接使用检测器返回的错误信息(已经包含推荐建议)
331
+ var report_obj = {
332
+ node: node.left.property,
333
+ message: err.message,
334
+ };
335
+
336
+ // 如果有修复建议,添加修复功能
337
+ var fix_suggestion = detector._getFixSuggestion(method_name, 'method-name', err.message);
338
+ if (fix_suggestion) {
339
+ report_obj.fix = function(fixer) {
340
+ return fixer.replaceText(node.left.property, fix_suggestion.fixed_name);
341
+ };
342
+ }
343
+ }
344
+
345
+ context.report(report_obj);
346
+ }
347
+ }
348
+
349
+ // 处理类实例方法定义:this.method_name = function() {}
350
+ if (node.left &&
351
+ node.left.type === 'MemberExpression' &&
352
+ node.left.object &&
353
+ node.left.object.type === 'ThisExpression' &&
354
+ node.left.property &&
355
+ node.left.property.type === 'Identifier' &&
356
+ node.right &&
357
+ (node.right.type === 'FunctionExpression' || node.right.type === 'ArrowFunctionExpression')) {
358
+
359
+ var method_name = node.left.property.name;
360
+ var err = detector._checkMethodName(method_name, node);
361
+ if (err) {
362
+ // 获取修复建议
363
+ var fix_suggestion = detector._getFixSuggestion(method_name, 'method-name', err.message);
364
+
365
+ // 检查错误信息是否包含推荐词
366
+ var recommendation_match = err.message.match(/建议使用'([^']+)'/);
367
+ var recommended_name = recommendation_match ? recommendation_match[1] : null;
368
+
369
+ var suggestion_text = '符合规范的名称';
370
+ if (fix_suggestion) {
371
+ suggestion_text = fix_suggestion.fixed_name;
372
+ } else if (recommended_name) {
373
+ suggestion_text = recommended_name;
374
+ }
375
+
376
+ var report_obj = {
377
+ node: node.left.property,
378
+ message: '方法名\'' + method_name + '\'不符合命名规范,建议使用: ' + suggestion_text,
379
+ };
380
+
381
+ // 如果有修复建议,添加修复功能
382
+ if (fix_suggestion) {
383
+ report_obj.fix = function(fixer) {
384
+ return fixer.replaceText(node.left.property, fix_suggestion.fixed_name);
385
+ };
386
+ }
387
+
388
+ context.report(report_obj);
105
389
  }
106
390
  }
107
391
  },
@@ -117,6 +401,7 @@ function createNamingRules() {
117
401
  category: 'Stylistic Issues',
118
402
  recommended: true,
119
403
  },
404
+ fixable: 'code',
120
405
  schema: [],
121
406
  },
122
407
  create: function (context) {
@@ -130,10 +415,23 @@ function createNamingRules() {
130
415
  var variable_name = decl.id.name;
131
416
  var err = detector._checkVariableName(variable_name, decl);
132
417
  if (err) {
133
- context.report({
418
+ // 获取修复建议
419
+ var fix_suggestion = detector._getFixSuggestion(variable_name, 'variable-name', err.message);
420
+
421
+ var report_obj = {
134
422
  node: decl.id,
135
423
  message: err.message,
136
- });
424
+ };
425
+
426
+ // 如果有修复建议,添加修复功能
427
+ if (fix_suggestion) {
428
+ report_obj.fix = function(fixer) {
429
+ return fixer.replaceText(decl.id, fix_suggestion.fixed_name);
430
+ };
431
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
432
+ }
433
+
434
+ context.report(report_obj);
137
435
  }
138
436
  }
139
437
  // 处理解构赋值 - ObjectPattern
@@ -143,10 +441,23 @@ function createNamingRules() {
143
441
  var variable_name = property.key.name;
144
442
  var err = detector._checkVariableName(variable_name, decl);
145
443
  if (err) {
146
- context.report({
444
+ // 获取修复建议
445
+ var fix_suggestion = detector._getFixSuggestion(variable_name, 'variable-name', err.message);
446
+
447
+ var report_obj = {
147
448
  node: property.key,
148
449
  message: err.message,
149
- });
450
+ };
451
+
452
+ // 如果有修复建议,添加修复功能
453
+ if (fix_suggestion) {
454
+ report_obj.fix = function(fixer) {
455
+ return fixer.replaceText(property.key, fix_suggestion.fixed_name);
456
+ };
457
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
458
+ }
459
+
460
+ context.report(report_obj);
150
461
  }
151
462
  }
152
463
  });
@@ -158,10 +469,23 @@ function createNamingRules() {
158
469
  var variable_name = element.name;
159
470
  var err = detector._checkVariableName(variable_name, decl);
160
471
  if (err) {
161
- context.report({
472
+ // 获取修复建议
473
+ var fix_suggestion = detector._getFixSuggestion(variable_name, 'variable-name', err.message);
474
+
475
+ var report_obj = {
162
476
  node: element,
163
477
  message: err.message,
164
- });
478
+ };
479
+
480
+ // 如果有修复建议,添加修复功能
481
+ if (fix_suggestion) {
482
+ report_obj.fix = function(fixer) {
483
+ return fixer.replaceText(element, fix_suggestion.fixed_name);
484
+ };
485
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
486
+ }
487
+
488
+ context.report(report_obj);
165
489
  }
166
490
  }
167
491
  });
@@ -181,60 +505,19 @@ function createNamingRules() {
181
505
  category: 'Stylistic Issues',
182
506
  recommended: true,
183
507
  },
508
+ fixable: 'code',
184
509
  schema: [],
185
510
  },
186
511
  create: function (context) {
187
512
  return {
188
513
  FunctionDeclaration: function (node) {
189
- if (node.params) {
190
- for (var i = 0; i < node.params.length; i++) {
191
- var param = node.params[i];
192
- if (param.name) {
193
- var param_name = param.name;
194
- var err = detector._checkParamName(param_name, param);
195
- if (err) {
196
- context.report({
197
- node: err.node,
198
- message: err.message,
199
- });
200
- }
201
- }
202
- }
203
- }
514
+ _fixParamAndReferences(context, node, detector);
204
515
  },
205
516
  FunctionExpression: function (node) {
206
- if (node.params) {
207
- for (var i = 0; i < node.params.length; i++) {
208
- var param = node.params[i];
209
- if (param.name) {
210
- var param_name = param.name;
211
- var err = detector._checkParamName(param_name, param);
212
- if (err) {
213
- context.report({
214
- node: err.node,
215
- message: err.message,
216
- });
217
- }
218
- }
219
- }
220
- }
517
+ _fixParamAndReferences(context, node, detector);
221
518
  },
222
519
  ArrowFunctionExpression: function (node) {
223
- if (node.params) {
224
- for (var i = 0; i < node.params.length; i++) {
225
- var param = node.params[i];
226
- if (param.name) {
227
- var param_name = param.name;
228
- var err = detector._checkParamName(param_name, param);
229
- if (err) {
230
- context.report({
231
- node: err.node,
232
- message: err.message,
233
- });
234
- }
235
- }
236
- }
237
- }
520
+ _fixParamAndReferences(context, node, detector);
238
521
  },
239
522
  };
240
523
  },
@@ -248,6 +531,7 @@ function createNamingRules() {
248
531
  category: 'Stylistic Issues',
249
532
  recommended: true,
250
533
  },
534
+ fixable: 'code',
251
535
  schema: [],
252
536
  },
253
537
  create: function (context) {
@@ -260,10 +544,60 @@ function createNamingRules() {
260
544
  var constant_name = decl.id.name;
261
545
  var err = detector._checkConstantName(constant_name, decl, decl.init);
262
546
  if (err) {
263
- context.report({
547
+ var report_obj = {
264
548
  node: decl.id,
265
549
  message: err.message,
266
- });
550
+ };
551
+
552
+ // 如果错误是"应该使用let而不是const",提供const→let修复功能
553
+ if (err.message.includes('应该使用let而不是const')) {
554
+ report_obj.fix = function(fixer) {
555
+ // 替换const为let
556
+ var const_range = [node.range[0], node.range[0] + 5]; // const的位置
557
+ return fixer.replaceTextRange(const_range, 'let');
558
+ };
559
+ report_obj.message += ',建议将const改为let';
560
+ }
561
+ // 否则提供命名风格修复建议
562
+ else {
563
+ // 使用检测器返回的规则类型(优先)
564
+ var rule_type = err.rule_type || 'constant-name';
565
+
566
+ // 如果没有返回规则类型,根据错误信息确定正确的规则类型
567
+ if (!err.rule_type) {
568
+ if (err.message.includes('函数名')) {
569
+ rule_type = 'function-name';
570
+ } else if (err.message.includes('变量名')) {
571
+ rule_type = 'variable-name';
572
+ } else if (err.message.includes('类名')) {
573
+ rule_type = 'class-name';
574
+ } else if (err.message.includes('属性名')) {
575
+ rule_type = 'property-name';
576
+ } else if (err.message.includes('方法名')) {
577
+ rule_type = 'method-name';
578
+ }
579
+ }
580
+
581
+ // 获取修复建议
582
+ var fix_suggestion = detector._getFixSuggestion(constant_name, rule_type, err.message);
583
+
584
+ // 如果有修复建议,添加修复功能
585
+ if (fix_suggestion) {
586
+ report_obj.fix = function(fixer) {
587
+ return fixer.replaceText(decl.id, fix_suggestion.fixed_name);
588
+ };
589
+
590
+ // 只有当错误消息中不包含建议时才添加建议
591
+ if (!err.message.includes('建议使用:')) {
592
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
593
+ }
594
+ }
595
+
596
+ // 设置正确的规则类型用于ESLint报告
597
+ report_obj.ruleId = 'mm_eslint/' + rule_type;
598
+ }
599
+
600
+ context.report(report_obj);
267
601
  }
268
602
  }
269
603
  // 处理解构赋值 - ObjectPattern
@@ -274,10 +608,49 @@ function createNamingRules() {
274
608
  // 对于解构赋值,使用专门的检测方法
275
609
  var err = detector._checkConstantNameForDestructuring(constant_name, property.key);
276
610
  if (err) {
277
- context.report({
611
+ var report_obj = {
278
612
  node: property.key,
279
613
  message: err.message,
280
- });
614
+ };
615
+
616
+ // 如果错误是"应该使用let而不是const",提供const→let修复功能
617
+ if (err.message.includes('应该使用let而不是const')) {
618
+ report_obj.fix = function(fixer) {
619
+ // 替换const为let
620
+ var const_range = [node.range[0], node.range[0] + 5]; // const的位置
621
+ return fixer.replaceTextRange(const_range, 'let');
622
+ };
623
+ report_obj.message += ',建议将const改为let';
624
+ }
625
+ // 否则提供命名风格修复建议
626
+ else {
627
+ // 根据错误信息确定正确的规则类型
628
+ var rule_type = 'constant-name';
629
+ if (err.message.includes('函数名')) {
630
+ rule_type = 'function-name';
631
+ } else if (err.message.includes('变量名')) {
632
+ rule_type = 'variable-name';
633
+ } else if (err.message.includes('类名')) {
634
+ rule_type = 'class-name';
635
+ } else if (err.message.includes('属性名')) {
636
+ rule_type = 'property-name';
637
+ } else if (err.message.includes('方法名')) {
638
+ rule_type = 'method-name';
639
+ }
640
+
641
+ // 获取修复建议
642
+ var fix_suggestion = detector._getFixSuggestion(constant_name, rule_type, err.message);
643
+
644
+ // 如果有修复建议,添加修复功能
645
+ if (fix_suggestion) {
646
+ report_obj.fix = function(fixer) {
647
+ return fixer.replaceText(property.key, fix_suggestion.fixed_name);
648
+ };
649
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
650
+ }
651
+ }
652
+
653
+ context.report(report_obj);
281
654
  }
282
655
  }
283
656
  });
@@ -290,10 +663,37 @@ function createNamingRules() {
290
663
  // 对于解构赋值,使用专门的检测方法
291
664
  var err = detector._checkConstantNameForDestructuring(constant_name, element);
292
665
  if (err) {
293
- context.report({
294
- node: element,
295
- message: err.message,
296
- });
666
+ // 根据错误信息确定正确的规则类型
667
+ var rule_type = 'variable-name';
668
+ if (err.message.includes('函数名')) {
669
+ rule_type = 'function-name';
670
+ } else if (err.message.includes('变量名')) {
671
+ rule_type = 'variable-name';
672
+ } else if (err.message.includes('类名')) {
673
+ rule_type = 'class-name';
674
+ } else if (err.message.includes('属性名')) {
675
+ rule_type = 'property-name';
676
+ } else if (err.message.includes('方法名')) {
677
+ rule_type = 'method-name';
678
+ }
679
+
680
+ // 获取修复建议
681
+ var fix_suggestion = detector._getFixSuggestion(constant_name, rule_type, err.message);
682
+
683
+ var report_obj = {
684
+ node: element,
685
+ message: err.message,
686
+ };
687
+
688
+ // 如果有修复建议,添加修复功能
689
+ if (fix_suggestion) {
690
+ report_obj.fix = function(fixer) {
691
+ return fixer.replaceText(element, fix_suggestion.fixed_name);
692
+ };
693
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
694
+ }
695
+
696
+ context.report(report_obj);
297
697
  }
298
698
  }
299
699
  });
@@ -305,15 +705,16 @@ function createNamingRules() {
305
705
  },
306
706
  },
307
707
 
308
- 'property-name': {
708
+ 'property-value-name': {
309
709
  meta: {
310
710
  type: 'suggestion',
311
711
  docs: {
312
- description: '检测属性名是否符合命名规范',
712
+ description: '属性值名命名规范检测',
313
713
  category: 'Stylistic Issues',
314
- recommended: true,
714
+ recommended: true
315
715
  },
316
- schema: [],
716
+ fixable: 'code',
717
+ schema: []
317
718
  },
318
719
  create: function (context) {
319
720
  return {
@@ -331,21 +732,96 @@ function createNamingRules() {
331
732
  return;
332
733
  }
333
734
 
735
+ // 传递祖父节点信息,用于第三方库排除检测
736
+ var parent_info = {
737
+ node: node.parent,
738
+ parent: node.parent ? node.parent.parent : null
739
+ };
740
+
334
741
  var err = detector._checkPropertyName(
335
742
  prop_name,
336
743
  node,
337
744
  node.value,
338
- node.parent,
745
+ parent_info,
339
746
  );
340
747
 
341
- if (err) {
342
- context.report({
748
+ // 只处理属性值名相关的错误
749
+ if (err && err.rule_type === 'property-value-name') {
750
+ // 获取修复建议
751
+ var fix_suggestion = detector._getFixSuggestion(prop_name, 'property-value-name', err.message);
752
+
753
+ var report_obj = {
343
754
  node: err.node,
344
755
  message: err.message,
345
- });
756
+ };
757
+
758
+ // 如果有修复建议,添加修复功能
759
+ if (fix_suggestion) {
760
+ report_obj.fix = function(fixer) {
761
+ return fixer.replaceText(node.key, fix_suggestion.fixed_name);
762
+ };
763
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
764
+ }
765
+
766
+ context.report(report_obj);
346
767
  }
347
768
  }
348
769
  },
770
+ // 检测类实例属性 (this.xxx)
771
+ AssignmentExpression: function (node) {
772
+ // 检查是否是 this.xxx = value 形式的赋值
773
+ if (node.left && node.left.type === 'MemberExpression' &&
774
+ node.left.object && node.left.object.type === 'ThisExpression' &&
775
+ node.left.property && node.left.property.type === 'Identifier') {
776
+
777
+ // 排除类实例方法:this.method_name = function() {}
778
+ var is_instance_method =
779
+ node.right &&
780
+ (node.right.type === 'FunctionExpression' || node.right.type === 'ArrowFunctionExpression');
781
+
782
+ if (is_instance_method) {
783
+ // 类实例方法由 method-name 规则处理,跳过
784
+ return;
785
+ }
786
+
787
+ var prop_name = node.left.property.name;
788
+
789
+ var parent_info = {
790
+ node: node.parent,
791
+ parent: node.parent ? node.parent.parent : null
792
+ };
793
+
794
+ var err = detector._checkPropertyName(
795
+ prop_name,
796
+ node.left.property,
797
+ node.right,
798
+ parent_info,
799
+ );
800
+
801
+ // 处理所有属性相关的错误类型,但排除 property-instance-class-name(由专门规则处理)
802
+ if (err && err.rule_type && err.rule_type.startsWith('property-') &&
803
+ err.rule_type !== 'property-instance-class-name') {
804
+ // 获取修复建议
805
+ var fix_suggestion = detector._getFixSuggestion(prop_name, err.rule_type, err.message);
806
+
807
+ var report_obj = {
808
+ node: node.left.property,
809
+ message: err.message,
810
+ };
811
+
812
+ // 如果有修复建议,添加修复功能
813
+ if (fix_suggestion) {
814
+ report_obj.fix = function(fixer) {
815
+ return fixer.replaceText(node.left.property, fix_suggestion.fixed_name);
816
+ };
817
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
818
+ }
819
+
820
+ context.report(report_obj);
821
+ }
822
+ }
823
+ },
824
+ // 检测普通属性赋值,排除原型方法
349
825
  AssignmentExpression: function (node) {
350
826
  if (
351
827
  node.left &&
@@ -353,6 +829,20 @@ function createNamingRules() {
353
829
  node.left.property &&
354
830
  node.left.property.name
355
831
  ) {
832
+ // 排除原型方法:ClassName.prototype.method_name = function() {}
833
+ var is_prototype_method =
834
+ node.left.object &&
835
+ node.left.object.type === 'MemberExpression' &&
836
+ node.left.object.property &&
837
+ node.left.object.property.name === 'prototype' &&
838
+ node.right &&
839
+ (node.right.type === 'FunctionExpression' || node.right.type === 'ArrowFunctionExpression');
840
+
841
+ if (is_prototype_method) {
842
+ // 原型方法由 method-name 规则处理,跳过
843
+ return;
844
+ }
845
+
356
846
  var prop_name = node.left.property.name;
357
847
 
358
848
  // 直接跳过null值和未赋值属性的检测
@@ -372,20 +862,436 @@ function createNamingRules() {
372
862
  node.parent,
373
863
  );
374
864
 
375
- if (err) {
376
- context.report({
865
+ // 只处理属性值名相关的错误
866
+ if (err && err.rule_type === 'property-value-name') {
867
+ // 获取修复建议
868
+ var fix_suggestion = detector._getFixSuggestion(prop_name, 'property-value-name', err.message);
869
+
870
+ var report_obj = {
871
+ node: err.node,
872
+ message: err.message,
873
+ };
874
+
875
+ // 如果有修复建议,添加修复功能
876
+ if (fix_suggestion) {
877
+ report_obj.fix = function(fixer) {
878
+ return fixer.replaceText(node.left.property, fix_suggestion.fixed_name);
879
+ };
880
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
881
+ }
882
+
883
+ context.report(report_obj);
884
+ }
885
+ }
886
+ },
887
+ };
888
+ },
889
+ },
890
+
891
+ 'property-method-name': {
892
+ meta: {
893
+ type: 'suggestion',
894
+ docs: {
895
+ description: '属性方法名命名规范检测',
896
+ category: 'Stylistic Issues',
897
+ recommended: true
898
+ },
899
+ fixable: 'code',
900
+ schema: []
901
+ },
902
+ create: function (context) {
903
+ return {
904
+ Property: function (node) {
905
+ if (node.key && node.key.name) {
906
+ var prop_name = node.key.name;
907
+
908
+ // 传递祖父节点信息,用于第三方库排除检测
909
+ var parent_info = {
910
+ node: node.parent,
911
+ parent: node.parent ? node.parent.parent : null
912
+ };
913
+
914
+ var err = detector._checkPropertyName(
915
+ prop_name,
916
+ node,
917
+ node.value,
918
+ parent_info,
919
+ );
920
+
921
+ // 只处理属性方法名相关的错误
922
+ if (err && err.rule_type === 'property-method-name') {
923
+ // 获取修复建议
924
+ var fix_suggestion = detector._getFixSuggestion(prop_name, 'property-method-name', err.message);
925
+
926
+ var report_obj = {
927
+ node: err.node,
928
+ message: err.message,
929
+ };
930
+
931
+ // 如果有修复建议,添加修复功能
932
+ if (fix_suggestion) {
933
+ report_obj.fix = function(fixer) {
934
+ return fixer.replaceText(node.key, fix_suggestion.fixed_name);
935
+ };
936
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
937
+ }
938
+
939
+ context.report(report_obj);
940
+ }
941
+ }
942
+ },
943
+ };
944
+ },
945
+ },
946
+
947
+ 'property-class-name': {
948
+ meta: {
949
+ type: 'suggestion',
950
+ docs: {
951
+ description: '属性类名命名规范检测',
952
+ category: 'Stylistic Issues',
953
+ recommended: true
954
+ },
955
+ fixable: 'code',
956
+ schema: []
957
+ },
958
+ create: function (context) {
959
+ return {
960
+ Property: function (node) {
961
+ if (node.key && node.key.name) {
962
+ var prop_name = node.key.name;
963
+
964
+ // 传递祖父节点信息,用于第三方库排除检测
965
+ var parent_info = {
966
+ node: node.parent,
967
+ parent: node.parent ? node.parent.parent : null
968
+ };
969
+
970
+ var err = detector._checkPropertyName(
971
+ prop_name,
972
+ node,
973
+ node.value,
974
+ parent_info,
975
+ );
976
+
977
+ // 只处理属性类名相关的错误
978
+ if (err && err.rule_type === 'property-class-name') {
979
+ // 获取修复建议
980
+ var fix_suggestion = detector._getFixSuggestion(prop_name, 'property-class-name', err.message);
981
+
982
+ var report_obj = {
377
983
  node: err.node,
378
984
  message: err.message,
379
- });
985
+ };
986
+
987
+ // 如果有修复建议,添加修复功能
988
+ if (fix_suggestion) {
989
+ report_obj.fix = function(fixer) {
990
+ return fixer.replaceText(node.key, fix_suggestion.fixed_name);
991
+ };
992
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
993
+ }
994
+
995
+ context.report(report_obj);
380
996
  }
381
997
  }
382
998
  },
383
999
  };
384
1000
  },
385
1001
  },
1002
+
1003
+ 'property-instance-class-name': {
1004
+ meta: {
1005
+ type: 'suggestion',
1006
+ docs: {
1007
+ description: '属性实例类名命名规范检测',
1008
+ category: 'Stylistic Issues',
1009
+ recommended: true
1010
+ },
1011
+ fixable: 'code',
1012
+ schema: []
1013
+ },
1014
+ create: function (context) {
1015
+ return {
1016
+ // 检测对象字面量中的属性实例类名
1017
+ Property: function (node) {
1018
+ if (node.key && node.key.name) {
1019
+ var prop_name = node.key.name;
1020
+
1021
+ // 传递祖父节点信息,用于第三方库排除检测
1022
+ var parent_info = {
1023
+ node: node.parent,
1024
+ parent: node.parent ? node.parent.parent : null
1025
+ };
1026
+
1027
+ // 检测属性命名
1028
+ var err = detector._checkPropertyName(
1029
+ prop_name,
1030
+ node.key,
1031
+ node.value,
1032
+ parent_info,
1033
+ );
1034
+
1035
+ // 只处理属性实例类名相关的错误
1036
+ if (err && err.rule_type === 'property-instance-class-name') {
1037
+ // 获取修复建议
1038
+ var fix_suggestion = detector._getFixSuggestion(prop_name, 'property-instance-class-name', err.message);
1039
+
1040
+ var report_obj = {
1041
+ node: err.node,
1042
+ message: err.message,
1043
+ };
1044
+
1045
+ // 如果有修复建议,添加修复功能
1046
+ if (fix_suggestion) {
1047
+ report_obj.fix = function(fixer) {
1048
+ return fixer.replaceText(node.key, fix_suggestion.fixed_name);
1049
+ };
1050
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
1051
+ }
1052
+
1053
+ context.report(report_obj);
1054
+ }
1055
+ }
1056
+ },
1057
+
1058
+ // 检测类实例属性中的属性实例类名 (this.xxx)
1059
+ AssignmentExpression: function (node) {
1060
+ // 检查是否是 this.xxx = value 形式的赋值
1061
+ if (node.left && node.left.type === 'MemberExpression' &&
1062
+ node.left.object && node.left.object.type === 'ThisExpression' &&
1063
+ node.left.property && node.left.property.type === 'Identifier') {
1064
+
1065
+ // 排除类实例方法:this.method_name = function() {}
1066
+ var is_instance_method =
1067
+ node.right &&
1068
+ (node.right.type === 'FunctionExpression' || node.right.type === 'ArrowFunctionExpression');
1069
+
1070
+ if (is_instance_method) {
1071
+ // 类实例方法由 method-name 规则处理,跳过
1072
+ return;
1073
+ }
1074
+
1075
+ var prop_name = node.left.property.name;
1076
+
1077
+ var parent_info = {
1078
+ node: node.parent,
1079
+ parent: node.parent ? node.parent.parent : null
1080
+ };
1081
+
1082
+ // 检测属性命名
1083
+ var err = detector._checkPropertyName(
1084
+ prop_name,
1085
+ node.left.property,
1086
+ node.right,
1087
+ parent_info,
1088
+ );
1089
+
1090
+ // 只处理属性实例类名相关的错误
1091
+ if (err && err.rule_type === 'property-instance-class-name') {
1092
+ // 获取修复建议
1093
+ var fix_suggestion = detector._getFixSuggestion(prop_name, 'property-instance-class-name', err.message);
1094
+
1095
+ var report_obj = {
1096
+ node: err.node,
1097
+ message: err.message,
1098
+ };
1099
+
1100
+ // 如果有修复建议,添加修复功能
1101
+ if (fix_suggestion) {
1102
+ report_obj.fix = function(fixer) {
1103
+ return fixer.replaceText(node.left.property, fix_suggestion.fixed_name);
1104
+ };
1105
+ report_obj.message += ',建议使用: ' + fix_suggestion.fixed_name;
1106
+ }
1107
+
1108
+ context.report(report_obj);
1109
+ }
1110
+ }
1111
+ },
1112
+ };
1113
+ },
1114
+ },
1115
+
1116
+ 'param-reference-consistency': {
1117
+ meta: {
1118
+ type: 'problem',
1119
+ docs: {
1120
+ description: '检测参数声明与函数内部引用是否一致',
1121
+ category: 'Possible Errors',
1122
+ recommended: true,
1123
+ },
1124
+ fixable: 'code',
1125
+ schema: [],
1126
+ },
1127
+ create: function (context) {
1128
+ return {
1129
+ FunctionDeclaration: function (node) {
1130
+ detector._checkParamReferences(context, node);
1131
+ },
1132
+ FunctionExpression: function (node) {
1133
+ detector._checkParamReferences(context, node);
1134
+ },
1135
+ ArrowFunctionExpression: function (node) {
1136
+ detector._checkParamReferences(context, node);
1137
+ },
1138
+ };
1139
+ },
1140
+ },
386
1141
  };
387
1142
  }
388
1143
 
1144
+ /**
1145
+ * 修复参数声明和所有相关引用
1146
+ * @param {object} context ESLint上下文
1147
+ * @param {object} node 函数节点
1148
+ * @param {object} detector 检测器实例
1149
+ */
1150
+ function _fixParamAndReferences(context, node, detector) {
1151
+ if (!node.params || !node.body) return;
1152
+
1153
+ // 收集需要修复的参数映射
1154
+ var param_fixes = [];
1155
+
1156
+ node.params.forEach(function(param) {
1157
+ if (param.name) {
1158
+ var param_name = param.name;
1159
+ var err = detector._checkParamName(param_name, param);
1160
+ if (err) {
1161
+ var fix_suggestion = detector._getFixSuggestion(param_name, 'param-name', err.message);
1162
+ if (fix_suggestion && fix_suggestion.fixed_name !== param_name) {
1163
+ param_fixes.push({
1164
+ param_node: param,
1165
+ old_name: param_name,
1166
+ new_name: fix_suggestion.fixed_name,
1167
+ message: err.message + ',建议使用: ' + fix_suggestion.fixed_name
1168
+ });
1169
+ }
1170
+ }
1171
+ }
1172
+ });
1173
+
1174
+ // 如果没有需要修复的参数,直接返回
1175
+ if (param_fixes.length === 0) return;
1176
+
1177
+ // 分步修复:先修复参数声明,然后单独检测引用不一致问题
1178
+ param_fixes.forEach(function(fix_info) {
1179
+ // 第一步:修复参数声明
1180
+ context.report({
1181
+ node: fix_info.param_node,
1182
+ message: fix_info.message,
1183
+ fix: function(fixer) {
1184
+ return fixer.replaceText(fix_info.param_node, fix_info.new_name);
1185
+ }
1186
+ });
1187
+
1188
+ // 第二步:检测并修复函数体内的引用不一致问题
1189
+ _checkParamReferenceInconsistencies(context, node, fix_info);
1190
+ });
1191
+ }
1192
+
1193
+ /**
1194
+ * 检查并修复参数引用不一致问题
1195
+ * @param {object} context ESLint上下文
1196
+ * @param {object} node 函数节点
1197
+ * @param {object} fix_info 修复信息
1198
+ */
1199
+ function _checkParamReferenceInconsistencies(context, node, fix_info) {
1200
+ var source_code = context.getSourceCode();
1201
+
1202
+ // 使用深度优先搜索遍历AST
1203
+ function findIdentifierReferences(astNode, oldName) {
1204
+ var references = [];
1205
+ var visited = new Set();
1206
+
1207
+ function traverse(currentNode) {
1208
+ // 防止循环引用导致的无限递归
1209
+ if (!currentNode || visited.has(currentNode) || typeof currentNode !== 'object') {
1210
+ return;
1211
+ }
1212
+ visited.add(currentNode);
1213
+
1214
+ // 检查当前节点是否为标识符节点
1215
+ if (currentNode.type === 'Identifier' && currentNode.name === oldName) {
1216
+ // 排除参数声明节点本身
1217
+ if (currentNode !== fix_info.param_node) {
1218
+ references.push(currentNode);
1219
+ }
1220
+ }
1221
+
1222
+ // 深度优先遍历所有子节点
1223
+ var stack = [currentNode];
1224
+
1225
+ while (stack.length > 0) {
1226
+ var current = stack.pop();
1227
+
1228
+ // 遍历当前节点的所有属性
1229
+ Object.keys(current).forEach(function(key) {
1230
+ // 跳过可能引起循环的属性
1231
+ if (key === 'parent' || key === 'range' || key === 'loc' || key === 'comments') {
1232
+ return;
1233
+ }
1234
+
1235
+ var child = current[key];
1236
+
1237
+ if (child && typeof child === 'object') {
1238
+ if (Array.isArray(child)) {
1239
+ // 将数组元素逆序压入栈中,保持遍历顺序
1240
+ for (var i = child.length - 1; i >= 0; i--) {
1241
+ var item = child[i];
1242
+ if (item && typeof item === 'object' && !visited.has(item)) {
1243
+ visited.add(item);
1244
+
1245
+ // 检查是否为标识符节点
1246
+ if (item.type === 'Identifier' && item.name === oldName && item !== fix_info.param_node) {
1247
+ references.push(item);
1248
+ }
1249
+
1250
+ stack.push(item);
1251
+ }
1252
+ }
1253
+ } else if (!visited.has(child)) {
1254
+ visited.add(child);
1255
+
1256
+ // 检查是否为标识符节点
1257
+ if (child.type === 'Identifier' && child.name === oldName && child !== fix_info.param_node) {
1258
+ references.push(child);
1259
+ }
1260
+
1261
+ stack.push(child);
1262
+ }
1263
+ }
1264
+ });
1265
+ }
1266
+ }
1267
+
1268
+ traverse(astNode);
1269
+ return references;
1270
+ }
1271
+
1272
+ // 查找函数体内的所有引用
1273
+ var references = findIdentifierReferences(node.body, fix_info.old_name);
1274
+
1275
+ // 如果找到引用,创建一个包含所有修复的单一修复函数
1276
+ if (references.length > 0) {
1277
+ context.report({
1278
+ node: node,
1279
+ message: '参数引用不一致:' + fix_info.old_name + ' 应该使用 ' + fix_info.new_name + ' (找到 ' + references.length + ' 个引用)',
1280
+ fix: function(fixer) {
1281
+ var fixes = [];
1282
+
1283
+ // 为每个引用添加修复
1284
+ references.forEach(function(refNode) {
1285
+ fixes.push(fixer.replaceText(refNode, fix_info.new_name));
1286
+ });
1287
+
1288
+ // 返回所有修复的数组
1289
+ return fixes;
1290
+ }
1291
+ });
1292
+ }
1293
+ }
1294
+
389
1295
  module.exports = {
390
1296
  rules: createNamingRules(),
391
1297
  };