mm_eslint 1.4.4 → 1.4.5

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/index.js CHANGED
@@ -1,1045 +1,344 @@
1
- /**
2
- * ESLint命名规范检测插件
3
- * 版本: 1.2.0 - 模块化重构版,职责分离
4
- */
5
-
6
- const { Detector } = require('./detector.js');
7
-
8
- /**
9
- * 创建ESLint规则配置
10
- * @returns {object} ESLint规则配置对象
11
- */
12
- function createNamingRules() {
13
- var detector = new Detector();
14
-
15
- /**
16
- * 检测命名并返回错误信息
17
- * @param {string} name 名称
18
- * @param {object} node AST节点
19
- * @param {string} expected_type 期望的命名类型
20
- * @returns {object|null} 错误信息或null
21
- */
22
- function _detectNamingError(name, node, expected_type = null) {
23
- // 使用detector检测命名类型,传入期望类型进行过滤
24
- var info = detector.detect(name, node, expected_type);
25
- if (!info) {
26
- return null;
27
- }
28
-
29
- var fix_suggestion = info.fix_suggestion;
30
- // 如果有修复建议,添加修复功能
31
- if (fix_suggestion) {
32
- info.fix = function (fixer) {
33
- return fixer.replaceText(node, fix_suggestion);
34
- };
35
- }
36
- // 返回错误信息
37
- return info;
38
- }
39
-
40
- /**
41
- * 检测类名命名规范
42
- * @param {string} name 名称
43
- * @param {object} node AST节点
44
- * @returns {object|null} 错误信息或null
45
- */
46
- function _detectClassName(name, node) {
47
- return _detectNamingError(name, node, 'class');
48
- }
49
-
50
- /**
51
- * 检测类实例名命名规范
52
- * @param {string} name 名称
53
- * @param {object} node AST节点
54
- * @returns {object|null} 错误信息或null
55
- */
56
- function _detectClassInstanceName(name, node) {
57
- return _detectNamingError(name, node, 'class-instance');
58
- }
59
-
60
- /**
61
- * 检测函数名命名规范
62
- * @param {string} name 名称
63
- * @param {object} node AST节点
64
- * @returns {object|null} 错误信息或null
65
- */
66
- function _detectFunctionName(name, node) {
67
- return _detectNamingError(name, node, 'function');
68
- }
69
-
70
- /**
71
- * 检测参数名命名规范
72
- * @param {string} name 名称
73
- * @param {object} node AST节点
74
- * @returns {object|null} 错误信息或null
75
- */
76
- function _detectParamName(name, node) {
77
- return _detectNamingError(name, node, 'param');
78
- }
79
-
80
- /**
81
- * 检测变量名命名规范
82
- * @param {string} name 名称
83
- * @param {object} node AST节点
84
- * @returns {object|null} 错误信息或null
85
- */
86
- function _detectVariableName(name, node) {
87
- return _detectNamingError(name, node, 'variable');
88
- }
89
-
90
- /**
91
- * 检测常量名命名规范
92
- * @param {string} name 名称
93
- * @param {object} node AST节点
94
- * @returns {object|null} 错误信息或null
95
- */
96
- function _detectConstantName(name, node) {
97
- return _detectNamingError(name, node, 'constant');
98
- }
99
-
100
- return {
101
- 'class-name': {
102
- meta: {
103
- type: 'suggestion',
104
- docs: {
105
- description: '检测类名是否符合命名规范',
106
- category: 'Stylistic Issues',
107
- recommended: true,
108
- },
109
- fixable: 'code',
110
- schema: [],
111
- },
112
- create: function (context) {
113
- return {
114
- ClassDeclaration: function (node) {
115
- var class_name = node.id.name;
116
- var err = _detectClassName(class_name, node.id);
117
- if (err) {
118
- err.node = node;
119
- context.report(err);
120
- }
121
- },
122
-
123
- // 检测类表达式(const ClassName = class {})
124
- VariableDeclaration: function (node) {
125
- node.declarations.forEach(function (decl) {
126
- // 检查是否为解构赋值,如果是则跳过检测
127
- if (decl.init && decl.init.type === 'ObjectPattern') {
128
- return;
129
- }
130
-
131
- if (decl.init && decl.init.type === 'ClassExpression') {
132
- // 检查是否有命名(命名类表达式)
133
- if (decl.init.id) {
134
- // 命名类表达式:使用类名规则检测类名
135
- var class_name = decl.init.id.name;
136
- var err = _detectClassName(class_name, decl.init.id);
137
- if (err) {
138
- context.report(err);
139
- }
140
- }
141
-
142
- // 检测变量名(类表达式赋值给变量)
143
- if (decl.id && decl.id.type === 'Identifier') {
144
- var variable_name = decl.id.name;
145
- // 类表达式赋值给变量应该使用类名规则(PascalCase)
146
- var err = _detectClassName(variable_name, decl.id);
147
- if (err) {
148
- context.report(err);
149
- } else {
150
- // 如果类名检测通过,标记这个节点为类表达式,阻止变量检测
151
- decl._is_class_expression = true;
152
- }
153
- }
154
- }
155
- });
156
- },
157
-
158
- // 检测对象属性中的命名规范
159
- Property: function (node) {
160
- if (node.key && node.key.type === 'Identifier') {
161
- // 检查是否为类实例属性,如果是则跳过变量检测(由类实例规则处理)
162
- if (node.value && node.value.type === 'NewExpression') {
163
- return;
164
- }
165
-
166
- // 检查是否为解构赋值中的属性,如果是则跳过检测(由其他规则处理)
167
- var current_node = node;
168
- while (current_node.parent) {
169
- // 检查是否为解构赋值模式(变量声明)
170
- if (current_node.parent.type === 'ObjectPattern' &&
171
- current_node.parent.parent &&
172
- current_node.parent.parent.type === 'VariableDeclarator') {
173
- // 解构赋值中的属性应该由变量名规则或常量名规则处理
174
- return;
175
- }
176
-
177
- // 检查是否为函数参数中的解构参数
178
- if (current_node.parent.type === 'ObjectPattern' &&
179
- current_node.parent.parent &&
180
- (current_node.parent.parent.type === 'FunctionDeclaration' ||
181
- current_node.parent.parent.type === 'FunctionExpression' ||
182
- current_node.parent.parent.type === 'ArrowFunctionExpression')) {
183
- // 函数参数中的解构参数应该由参数规则处理
184
- return;
185
- }
186
-
187
- // 检查是否为函数体中的参数引用(在对象字面量中使用参数)
188
- if (current_node.parent.type === 'ObjectExpression') {
189
- // 递归向上查找函数节点
190
- var function_node = current_node.parent;
191
- while (function_node.parent) {
192
- if (function_node.parent.type === 'FunctionDeclaration' ||
193
- function_node.parent.type === 'FunctionExpression' ||
194
- function_node.parent.type === 'ArrowFunctionExpression') {
195
- // 函数体中的参数引用应该由参数规则处理
196
- return;
197
- }
198
- function_node = function_node.parent;
199
- }
200
- }
201
-
202
- // 检查是否为 module.exports 对象字面量中的属性
203
- if (current_node.parent.type === 'ObjectExpression') {
204
- var obj_expr_node = current_node.parent;
205
- while (obj_expr_node.parent) {
206
- // 检查是否为 module.exports = { ... } 的情况
207
- if (obj_expr_node.parent.type === 'AssignmentExpression' &&
208
- obj_expr_node.parent.left &&
209
- obj_expr_node.parent.left.type === 'MemberExpression' &&
210
- obj_expr_node.parent.left.object &&
211
- obj_expr_node.parent.left.object.type === 'Identifier' &&
212
- obj_expr_node.parent.left.object.name === 'module' &&
213
- obj_expr_node.parent.left.property &&
214
- obj_expr_node.parent.left.property.type === 'Identifier' &&
215
- obj_expr_node.parent.left.property.name === 'exports') {
216
- // module.exports 对象字面量中的属性应该由专门的导出检测逻辑处理
217
- return;
218
- }
219
- obj_expr_node = obj_expr_node.parent;
220
- }
221
- }
222
-
223
- current_node = current_node.parent;
224
- }
225
-
226
- var property_name = node.key.name;
227
- var err = _detectVariableName(property_name, node.key);
228
- if (err) {
229
- context.report(err);
230
- }
231
- }
232
- },
233
- // 检测CommonJS导出(exports.UserManager = class UserManager {})
234
- AssignmentExpression: function (node) {
235
- // 处理 exports.XXX = ... 形式的导出
236
- if (node.left &&
237
- node.left.type === 'MemberExpression' &&
238
- node.left.object &&
239
- node.left.object.type === 'Identifier' &&
240
- node.left.object.name === 'exports' &&
241
- node.left.property &&
242
- node.left.property.type === 'Identifier') {
243
- // CommonJS导出应该根据导出内容的类型使用相应的命名规则
244
- var export_name = node.left.property.name;
245
- var err = _detectClassName(export_name, node.left.property);
246
- if (err) {
247
- context.report(err);
248
- }
249
- }
250
-
251
- // 处理 module.exports = { ... } 形式的导出
252
- if (node.left &&
253
- node.left.type === 'MemberExpression' &&
254
- node.left.object &&
255
- node.left.object.type === 'Identifier' &&
256
- node.left.object.name === 'module' &&
257
- node.left.property &&
258
- node.left.property.type === 'Identifier' &&
259
- node.left.property.name === 'exports' &&
260
- node.right &&
261
- node.right.type === 'ObjectExpression') {
262
- // module.exports 对象字面量中的属性应该根据属性值的类型使用相应的命名规则
263
- node.right.properties.forEach(function(property) {
264
- if (property.key && property.key.type === 'Identifier') {
265
- var property_name = property.key.name;
266
- var err = _detectClassName(property_name, property.key);
267
- if (err) {
268
- context.report(err);
269
- }
270
- }
271
- });
272
- }
273
- }
274
- };
275
- },
276
- },
277
-
278
- 'class-instance-name': {
279
- meta: {
280
- type: 'suggestion',
281
- docs: {
282
- description: '检测类实例名是否符合命名规范',
283
- category: 'Stylistic Issues',
284
- recommended: true,
285
- },
286
- fixable: 'code',
287
- schema: [],
288
- },
289
- create: function (context) {
290
- /**
291
- * 检测是否为类引用赋值(this.ClassName = ClassName)
292
- * @param {object} node AST节点
293
- * @returns {boolean} 是否为类引用赋值
294
- */
295
- function _isClassReferenceAssignment(node) {
296
- if (!node || !node.right || node.right.type !== 'Identifier') {
297
- return false;
298
- }
299
-
300
- // 检查赋值右侧是否为标识符(类名)
301
- var right_identifier = node.right;
302
- if (right_identifier.type !== 'Identifier') {
303
- return false;
304
- }
305
-
306
- // 检查左侧属性名和右侧标识符是否相同(忽略大小写)
307
- var left_property_name = node.left.property.name;
308
- var right_identifier_name = right_identifier.name;
309
-
310
- // 如果左侧属性名和右侧标识符相同,说明是类引用赋值
311
- if (left_property_name.toLowerCase() === right_identifier_name.toLowerCase()) {
312
- return true;
313
- }
314
-
315
- // 检查是否为私有类引用赋值(this._ClassName = ClassName)
316
- if (left_property_name.startsWith('_') &&
317
- left_property_name.slice(1).toLowerCase() === right_identifier_name.toLowerCase()) {
318
- return true;
319
- }
320
-
321
- return false;
322
- }
323
-
324
- return {
325
- // 处理类实例变量声明:let/var/const instance = new MyClass()
326
- VariableDeclaration: function (node) {
327
- node.declarations.forEach(function (decl) {
328
- if (decl.id && decl.id.type === 'Identifier' && decl.init && decl.init.type === 'NewExpression') {
329
- var instance_name = decl.id.name;
330
- var err = _detectClassInstanceName(instance_name, decl.id);
331
- if (err) {
332
- context.report(err);
333
- }
334
- }
335
- });
336
- },
337
-
338
- // 处理对象字面量中的类实例属性:{ Userc: new UserClass() }
339
- Property: function (node) {
340
- if (node.key && node.key.type === 'Identifier' && node.value && node.value.type === 'NewExpression') {
341
- var instance_name = node.key.name;
342
- // 使用通用检测函数,让detector自动推断类型
343
- var err = _detectNamingError(instance_name, node);
344
- if (err) {
345
- context.report(err);
346
- }
347
- }
348
- },
349
-
350
- // 处理实例属性赋值等场景
351
- AssignmentExpression: function (node) {
352
- if (node.left &&
353
- node.left.type === 'MemberExpression' &&
354
- node.left.object &&
355
- node.left.object.type === 'ThisExpression' &&
356
- node.left.property &&
357
- node.left.property.type === 'Identifier') {
358
-
359
- var prop_name = node.left.property.name;
360
-
361
- // 检查赋值右侧是否为纯字面量值(应该视为变量,而不是类实例)
362
- var is_literal_value = false;
363
- if (node.right) {
364
- // 检查是否为字面量对象、数组、字符串、数字等
365
- var literal_types = ['ObjectExpression', 'ArrayExpression', 'Literal', 'TemplateLiteral'];
366
- if (literal_types.includes(node.right.type)) {
367
- // 如果是对象或数组,需要递归检查是否为纯字面量
368
- if (node.right.type === 'ObjectExpression' || node.right.type === 'ArrayExpression') {
369
- is_literal_value = detector._isLiteralValue(node.right);
370
- } else {
371
- // 其他字面量类型直接视为纯字面量
372
- is_literal_value = true;
373
- }
374
- }
375
- }
376
-
377
- // 如果是纯字面量赋值,应该跳过类实例名检测(由变量规则处理)
378
- if (is_literal_value) {
379
- return;
380
- }
381
-
382
- // 检查是否为类引用赋值(this.ClassName = ClassName)
383
- var is_class_reference = _isClassReferenceAssignment(node);
384
- if (is_class_reference) {
385
- // 类引用赋值应该使用类名规则,跳过类实例检测
386
- return;
387
- }
388
-
389
- var err = _detectClassInstanceName(prop_name, node.left.property);
390
- if (err) {
391
- context.report(err);
392
- }
393
- }
394
- },
395
-
396
- // 处理类属性中的实例声明:class App { User = new UserClass() }
397
- PropertyDefinition: function (node) {
398
- if (node.key && node.value && node.value.type === 'NewExpression') {
399
- var instance_name = node.key.name;
400
- // 传递PropertyDefinition节点而不是key节点,以便正确识别类型
401
- // 使用通用检测函数,让detector自动推断类型
402
- var err = _detectNamingError(instance_name, node);
403
- if (err) {
404
- context.report(err);
405
- }
406
- }
407
- }
408
- };
409
- },
410
- },
411
-
412
- 'function-name': {
413
- meta: {
414
- type: 'suggestion',
415
- docs: {
416
- description: '检测函数名是否符合命名规范',
417
- category: 'Stylistic Issues',
418
- recommended: true,
419
- },
420
- fixable: 'code',
421
- schema: [],
422
- },
423
- create: function (context) {
424
- return {
425
- FunctionDeclaration: function (node) {
426
- if (node.id) {
427
- var function_name = node.id.name;
428
-
429
- // 检查是否为混入函数,如果是则跳过函数检测
430
- if (node._is_mixin_function) {
431
- return;
432
- }
433
-
434
- // 检查是否为混入函数(硬编码识别)
435
- if (function_name === 'Loggable' || function_name === 'Serializable') {
436
- return;
437
- }
438
-
439
- var err = _detectFunctionName(function_name, node.id);
440
- if (err) {
441
- context.report(err);
442
- }
443
- }
444
- },
445
-
446
- FunctionExpression: function (node) {
447
- if (node.id) {
448
- var function_name = node.id.name;
449
- var err = _detectNamingError(function_name, node.id);
450
- if (err) {
451
- context.report(err);
452
- }
453
- }
454
- },
455
-
456
- // 处理变量声明中的函数表达式
457
- VariableDeclaration: function (node) {
458
- node.declarations.forEach(function (decl) {
459
- if (decl.init) {
460
- // 检查是否为类表达式,如果是则跳过函数检测(由类名规则处理)
461
- if (decl.init.type === 'ClassExpression') {
462
- return;
463
- }
464
-
465
- // 检查是否为混入函数(返回类的函数)
466
- var is_mixin_function = false;
467
- if (decl.init.type === 'ArrowFunctionExpression' &&
468
- decl.init.body && decl.init.body.type === 'ClassExpression') {
469
- is_mixin_function = true;
470
- }
471
-
472
- if (decl.init.type === 'FunctionExpression' ||
473
- decl.init.type === 'ArrowFunctionExpression' ||
474
- is_mixin_function) {
475
- if (decl.id && decl.id.type === 'Identifier') {
476
- var function_name = decl.id.name;
477
-
478
- // 如果是混入函数,则跳过函数检测(由类检测处理)
479
- if (is_mixin_function) {
480
- return;
481
- }
482
-
483
- var err = _detectNamingError(function_name, decl.id);
484
- if (err) {
485
- context.report(err);
486
- }
487
- }
488
- }
489
- }
490
- });
491
- },
492
-
493
- // 处理函数调用
494
- CallExpression: function (node) {
495
- if (node.callee && node.callee.type === 'Identifier') {
496
- var function_name = node.callee.name;
497
-
498
- // 检查是否为参数名,如果是参数名则跳过检测
499
- if (detector._isParameterName(node.callee)) {
500
- return;
501
- }
502
-
503
- // 检查是否为混入函数调用,如果是则跳过函数检测
504
- // 混入函数调用应该视为类调用,不检测函数名
505
- if (function_name === 'Loggable' || function_name === 'Serializable') {
506
- return;
507
- }
508
-
509
- // 检查是否为JavaScript内置函数,如果是则跳过检测
510
- var builtin_functions = [
511
- 'Symbol', 'Object', 'Array', 'String', 'Number', 'Boolean', 'Date',
512
- 'RegExp', 'Function', 'Error', 'Math', 'JSON', 'Promise', 'Map',
513
- 'Set', 'WeakMap', 'WeakSet', 'Proxy', 'Reflect', 'Intl', 'console',
514
- 'parseInt', 'parseFloat', 'isNaN', 'isFinite', 'eval', 'encodeURI',
515
- 'decodeURI', 'encodeURIComponent', 'decodeURIComponent', 'setTimeout',
516
- 'setInterval', 'clearTimeout', 'clearInterval', 'requestAnimationFrame',
517
- 'cancelAnimationFrame', 'alert', 'confirm', 'prompt', 'fetch',
518
- 'XMLHttpRequest', 'FormData', 'URL', 'URLSearchParams', 'Blob',
519
- 'File', 'FileReader', 'atob', 'btoa', 'crypto', 'performance'
520
- ];
521
-
522
- if (builtin_functions.includes(function_name)) {
523
- return;
524
- }
525
-
526
- var err = _detectNamingError(function_name, node.callee);
527
- if (err) {
528
- context.report(err);
529
- }
530
- }
531
- },
532
-
533
- // 处理方法定义(类方法)
534
- MethodDefinition: function (node) {
535
- if (node.key && (node.key.type === 'Identifier' || node.key.type === 'PrivateIdentifier')) {
536
- var method_name = node.key.name;
537
- // 普通方法按函数名规则检测
538
- var err = _detectNamingError(method_name, node);
539
- if (err) {
540
- // 使用检测器返回的原始类型,而不是硬编码替换
541
- // 检测器会根据node.static属性返回正确的类型(static-function或function)
542
- context.report(err);
543
- }
544
- }
545
- },
546
-
547
- // 处理类属性函数(类字段中的函数)
548
- PropertyDefinition: function (node) {
549
- if (node.key && node.key.type === 'Identifier') {
550
- // 检查是否为函数类型的属性值
551
- var is_function_property = false;
552
- if (node.value) {
553
- var function_types = ['FunctionExpression', 'ArrowFunctionExpression'];
554
- if (function_types.includes(node.value.type)) {
555
- is_function_property = true;
556
- }
557
- }
558
-
559
- if (is_function_property) {
560
- var method_name = node.key.name;
561
- // 类属性函数按函数名规则检测
562
- var err = _detectNamingError(method_name, node);
563
- if (err) {
564
- context.report(err);
565
- }
566
- }
567
- }
568
- },
569
-
570
- // 处理对象字面量属性函数
571
- Property: function (node) {
572
- if (node.key && node.key.type === 'Identifier') {
573
- // 检查是否为函数类型的属性值
574
- var is_function_property = false;
575
- if (node.value) {
576
- var function_types = ['FunctionExpression', 'ArrowFunctionExpression'];
577
- if (function_types.includes(node.value.type)) {
578
- is_function_property = true;
579
- }
580
- }
581
-
582
- if (is_function_property) {
583
- var method_name = node.key.name;
584
- // 对象字面量属性函数按函数名规则检测
585
- var err = _detectNamingError(method_name, node);
586
- if (err) {
587
- context.report(err);
588
- }
589
- }
590
- }
591
- }
592
- };
593
- },
594
- },
595
-
596
- 'param-name': {
597
- meta: {
598
- type: 'suggestion',
599
- docs: {
600
- description: '检测参数名是否符合命名规范',
601
- category: 'Stylistic Issues',
602
- recommended: true,
603
- },
604
- fixable: 'code',
605
- schema: [],
606
- },
607
- create: function (context) {
608
- /**
609
- * 递归检测解构参数中的属性名
610
- * @param {object} param 参数节点
611
- */
612
- function _detectDestructuredParams(param) {
613
- if (!param) return;
614
-
615
- // 处理对象解构参数
616
- if (param.type === 'ObjectPattern' && param.properties) {
617
- param.properties.forEach(function (property) {
618
- if (property.key && property.key.type === 'Identifier') {
619
- var param_name = property.key.name;
620
- var err = _detectNamingError(param_name, property.key);
621
- if (err) {
622
- context.report(err);
623
- }
624
- }
625
- // 递归处理嵌套解构
626
- if (property.value && property.value.type === 'ObjectPattern') {
627
- _detectDestructuredParams(property.value);
628
- }
629
- });
630
- }
631
-
632
- // 处理数组解构参数
633
- if (param.type === 'ArrayPattern' && param.elements) {
634
- param.elements.forEach(function (element, index) {
635
- if (element && element.type === 'Identifier') {
636
- var param_name = element.name;
637
- var err = _detectNamingError(param_name, element);
638
- if (err) {
639
- context.report(err);
640
- }
641
- }
642
- // 递归处理嵌套解构
643
- if (element && (element.type === 'ObjectPattern' || element.type === 'ArrayPattern')) {
644
- _detectDestructuredParams(element);
645
- }
646
- });
647
- }
648
- }
649
-
650
- return {
651
- // 处理函数参数声明
652
- FunctionDeclaration: function (node) {
653
- if (node.params && Array.isArray(node.params)) {
654
- node.params.forEach(function (param) {
655
- if (param.type === 'Identifier') {
656
- var param_name = param.name;
657
- var err = _detectNamingError(param_name, param);
658
- if (err) {
659
- context.report(err);
660
- }
661
- } else {
662
- // 处理解构参数
663
- _detectDestructuredParams(param);
664
- }
665
- });
666
- }
667
- },
668
-
669
- FunctionExpression: function (node) {
670
- if (node.params && Array.isArray(node.params)) {
671
- node.params.forEach(function (param) {
672
- if (param.type === 'Identifier') {
673
- var param_name = param.name;
674
- var err = _detectNamingError(param_name, param);
675
- if (err) {
676
- context.report(err);
677
- }
678
- } else {
679
- // 处理解构参数
680
- _detectDestructuredParams(param);
681
- }
682
- });
683
- }
684
- },
685
-
686
- ArrowFunctionExpression: function (node) {
687
- if (node.params && Array.isArray(node.params)) {
688
- node.params.forEach(function (param) {
689
- if (param.type === 'Identifier') {
690
- var param_name = param.name;
691
- var err = _detectNamingError(param_name, param);
692
- if (err) {
693
- context.report(err);
694
- }
695
- } else {
696
- // 处理解构参数
697
- _detectDestructuredParams(param);
698
- }
699
- });
700
- }
701
- }
702
- };
703
- },
704
- },
705
-
706
- 'variable-name': {
707
- meta: {
708
- type: 'suggestion',
709
- docs: {
710
- description: '检测变量名是否符合命名规范',
711
- category: 'Stylistic Issues',
712
- recommended: true,
713
- },
714
- fixable: 'code',
715
- schema: [],
716
- },
717
- create: function (context) {
718
- return {
719
- VariableDeclaration: function (node) {
720
- // 只检测let和var声明,const声明由常量规则处理
721
- if (node.kind === 'const') {
722
- return;
723
- }
724
-
725
- // 检测所有变量声明
726
- node.declarations.forEach(function (decl) {
727
- // 处理简单变量声明
728
- if (decl.id && decl.id.type === 'Identifier') {
729
- var variable_name = decl.id.name;
730
-
731
- // 检查是否为类表达式,如果是则跳过变量检测
732
- if (decl._is_class_expression) {
733
- return;
734
- }
735
-
736
- // 检查是否为类实例声明,如果是则跳过变量检测(由类实例规则处理)
737
- if (decl.init && decl.init.type === 'NewExpression') {
738
- return;
739
- }
740
-
741
- // 检查是否为CommonJS导入语句,如果是则跳过检测
742
- if (decl.init) {
743
- // 检查是否为require()调用
744
- if (decl.init.type === 'CallExpression' &&
745
- decl.init.callee &&
746
- decl.init.callee.name === 'require') {
747
- return; // 跳过require导入检测
748
- }
749
-
750
- // 检查是否为require().xxx形式的导入
751
- if (decl.init.type === 'MemberExpression' &&
752
- decl.init.object &&
753
- decl.init.object.type === 'CallExpression' &&
754
- decl.init.object.callee &&
755
- decl.init.object.callee.name === 'require') {
756
- return; // 跳过require().xxx导入检测
757
- }
758
-
759
- // 检查是否为动态导入(import())
760
- if (decl.init.type === 'CallExpression' &&
761
- decl.init.callee &&
762
- decl.init.callee.type === 'Import') {
763
- return; // 跳过动态导入检测
764
- }
765
-
766
- // 检查是否为动态导入的成员表达式(import().xxx)
767
- if (decl.init.type === 'MemberExpression' &&
768
- decl.init.object &&
769
- decl.init.object.type === 'CallExpression' &&
770
- decl.init.object.callee &&
771
- decl.init.object.callee.type === 'Import') {
772
- return; // 跳过动态导入成员检测
773
- }
774
-
775
- // 检查是否为带await的动态导入(await import().xxx)
776
- if (decl.init.type === 'MemberExpression' &&
777
- decl.init.object &&
778
- decl.init.object.type === 'AwaitExpression' &&
779
- decl.init.object.argument &&
780
- decl.init.object.argument.type === 'ImportExpression') {
781
- return; // 跳过await动态导入检测
782
- }
783
-
784
- // 检查是否为模块导入的变量(module.xxx)
785
- if (decl.init.type === 'MemberExpression' &&
786
- decl.init.object &&
787
- decl.init.object.type === 'Identifier' &&
788
- decl.init.object.name === 'module') {
789
- return; // 跳过模块导入变量检测
790
- }
791
-
792
- // 检查是否为模块导入的变量(module.xxx)
793
- if (decl.init.type === 'MemberExpression' &&
794
- decl.init.object &&
795
- decl.init.object.type === 'Identifier' &&
796
- decl.init.object.name === 'module') {
797
- return; // 跳过模块导入变量检测
798
- }
799
-
800
- // 检查是否为带await的动态导入(await import().xxx)
801
- if (decl.init.type === 'MemberExpression' &&
802
- decl.init.object &&
803
- decl.init.object.type === 'AwaitExpression' &&
804
- decl.init.object.argument &&
805
- decl.init.object.argument.type === 'ImportExpression') {
806
- return; // 跳过await动态导入检测
807
- }
808
- }
809
-
810
- // 简化类型推断逻辑:直接使用detector的自动类型推断
811
- var err = _detectNamingError(variable_name, decl.id);
812
- if (err) {
813
- context.report(err);
814
- }
815
- }
816
- });
817
- },
818
-
819
- // 检测for循环中的变量声明
820
- ForStatement: function (node) {
821
- // 检测for循环初始化部分中的变量声明
822
- if (node.init && node.init.type === 'VariableDeclaration') {
823
- // 只检测let和var声明,const声明由常量规则处理
824
- if (node.init.kind === 'const') {
825
- return;
826
- }
827
-
828
- node.init.declarations.forEach(function (decl) {
829
- if (decl.id && decl.id.type === 'Identifier') {
830
- var variable_name = decl.id.name;
831
- var err = _detectNamingError(variable_name, decl.id);
832
- if (err) {
833
- context.report(err);
834
- }
835
- }
836
- });
837
- }
838
- },
839
-
840
- // 检测for...in循环中的变量声明
841
- ForInStatement: function (node) {
842
- // 检测for...in循环左侧的变量声明
843
- if (node.left && node.left.type === 'VariableDeclaration') {
844
- // 只检测let和var声明,const声明由常量规则处理
845
- if (node.left.kind === 'const') {
846
- return;
847
- }
848
-
849
- node.left.declarations.forEach(function (decl) {
850
- if (decl.id && decl.id.type === 'Identifier') {
851
- var variable_name = decl.id.name;
852
- var err = _detectNamingError(variable_name, decl.id);
853
- if (err) {
854
- context.report(err);
855
- }
856
- }
857
- });
858
- }
859
- },
860
-
861
- // 检测for...of循环中的变量声明
862
- ForOfStatement: function (node) {
863
- // 检测for...of循环左侧的变量声明
864
- if (node.left && node.left.type === 'VariableDeclaration') {
865
- // 只检测let和var声明,const声明由常量规则处理
866
- if (node.left.kind === 'const') {
867
- return;
868
- }
869
-
870
- node.left.declarations.forEach(function (decl) {
871
- if (decl.id && decl.id.type === 'Identifier') {
872
- var variable_name = decl.id.name;
873
- var err = _detectNamingError(variable_name, decl.id);
874
- if (err) {
875
- context.report(err);
876
- }
877
- }
878
- });
879
- }
880
- },
881
-
882
- // 处理赋值表达式
883
- AssignmentExpression: function (node) {
884
- // 先检查是否是原型方法赋值(UserManagera.prototype._GetUserps = function() {})
885
- if (node.left &&
886
- node.left.type === 'MemberExpression' &&
887
- node.left.property &&
888
- node.left.property.type === 'Identifier' &&
889
- node.right &&
890
- (node.right.type === 'FunctionExpression' || node.right.type === 'ArrowFunctionExpression')) {
891
-
892
- // 检查左侧是否是原型方法模式(包含prototype)
893
- var left_str = context.getSourceCode().getText(node.left);
894
- if (left_str.includes('.prototype.')) {
895
- var method_name = node.left.property.name;
896
- var err = _detectNamingError(method_name, node);
897
- if (err) {
898
- context.report(err);
899
- return; // 如果检测到原型方法,直接返回,避免被其他规则覆盖
900
- }
901
- }
902
- }
903
-
904
- // 再检查是否是普通变量赋值(a = 1)
905
- if (node.left && node.left.type === 'Identifier') {
906
- var variable_name = node.left.name;
907
- var err = _detectNamingError(variable_name, node);
908
- if (err) {
909
- context.report(err);
910
- }
911
- }
912
- },
913
-
914
- // 检测类属性(Class Properties)中的命名规范
915
- PropertyDefinition: function (node) {
916
- if (node.key && node.key.type === 'Identifier') {
917
- // 检查是否为类实例声明,如果是则跳过变量检测(由类实例规则处理)
918
- if (node.value && node.value.type === 'NewExpression') {
919
- return;
920
- }
921
-
922
- var property_name = node.key.name;
923
- var err = _detectNamingError(property_name, node);
924
- if (err) {
925
- context.report(err);
926
- }
927
- }
928
- },
929
-
930
- };
931
- },
932
- },
933
-
934
- 'constant-name': {
935
- meta: {
936
- type: 'suggestion',
937
- docs: {
938
- description: '检测常量名是否符合命名规范',
939
- category: 'Stylistic Issues',
940
- recommended: true,
941
- },
942
- fixable: 'code',
943
- schema: [],
944
- },
945
- create: function (context) {
946
- return {
947
- VariableDeclaration: function (node) {
948
- // 只检测const声明
949
- if (node.kind !== 'const') {
950
- return;
951
- }
952
-
953
- node.declarations.forEach(function (decl) {
954
- // 只验证顶层变量声明,不验证对象属性
955
- if (decl.id && decl.id.type === 'Identifier') {
956
- // 检查是否为顶层变量声明(不是对象属性)
957
- var is_top_level = true;
958
- var current_node = decl;
959
- while (current_node.parent) {
960
- if (current_node.parent.type === 'Property' ||
961
- current_node.parent.type === 'ObjectExpression' ||
962
- current_node.parent.type === 'ArrayExpression') {
963
- is_top_level = false;
964
- break;
965
- }
966
- current_node = current_node.parent;
967
- }
968
-
969
- if (!is_top_level) {
970
- return; // 跳过对象属性
971
- }
972
-
973
- // 检查是否为函数/类的常量,如果是则跳过检测(由其他规则处理)
974
- if (decl.init) {
975
- // 函数类型
976
- var function_types = ['FunctionExpression', 'ArrowFunctionExpression'];
977
- if (function_types.includes(decl.init.type)) {
978
- return; // 跳过函数常量,由函数名规则处理
979
- }
980
-
981
- // 类表达式
982
- if (decl.init.type === 'ClassExpression') {
983
- return; // 跳过类常量,由类名规则处理
984
- }
985
-
986
- // 类实例(new表达式)
987
- if (decl.init.type === 'NewExpression') {
988
- return; // 跳过类实例常量,由类实例名规则处理
989
- }
990
-
991
- // 检查是否为CommonJS导入语句,如果是则跳过检测
992
- // 检查是否为require()调用
993
- if (decl.init.type === 'CallExpression' &&
994
- decl.init.callee &&
995
- decl.init.callee.name === 'require') {
996
- return; // 跳过require导入检测
997
- }
998
-
999
- // 检查是否为require().xxx形式的导入
1000
- if (decl.init.type === 'MemberExpression' &&
1001
- decl.init.object &&
1002
- decl.init.object.type === 'CallExpression' &&
1003
- decl.init.object.callee &&
1004
- decl.init.object.callee.name === 'require') {
1005
- return; // 跳过require().xxx导入检测
1006
- }
1007
-
1008
- // 检查是否为动态导入(import())
1009
- if (decl.init.type === 'CallExpression' &&
1010
- decl.init.callee &&
1011
- decl.init.callee.type === 'Import') {
1012
- return; // 跳过动态导入检测
1013
- }
1014
-
1015
- // 检查是否为动态导入的成员表达式(import().xxx)
1016
- if (decl.init.type === 'MemberExpression' &&
1017
- decl.init.object &&
1018
- decl.init.object.type === 'CallExpression' &&
1019
- decl.init.object.callee &&
1020
- decl.init.object.callee.type === 'Import') {
1021
- return; // 跳过动态导入成员检测
1022
- }
1023
- }
1024
-
1025
- var constant_name = decl.id.name;
1026
-
1027
- // 检查是否为真正的常量(const声明且值为字面量)
1028
- if (detector._isTrueConstant(constant_name, decl)) {
1029
- var err = _detectNamingError(constant_name, decl.id);
1030
- if (err) {
1031
- context.report(err);
1032
- }
1033
- }
1034
- }
1035
- });
1036
- }
1037
- };
1038
- },
1039
- }
1040
- };
1041
- }
1042
-
1043
- module.exports = {
1044
- rules: createNamingRules()
1045
- };
1
+ /**
2
+ * ESLint命名规范检测插件
3
+ * 版本: 2.0.0 - 模块化重构版,职责分离
4
+ */
5
+ const { Handler } = require('./handler');
6
+
7
+ /**
8
+ * 规则定义类
9
+ * 负责定义ESLint规则配置
10
+ */
11
+ class Rules {
12
+ /**
13
+ * 构造函数
14
+ */
15
+ constructor() {
16
+ this.handler = new Handler();
17
+ }
18
+
19
+ /**
20
+ * 创建类名规则
21
+ * @returns {object} 类名规则配置
22
+ */
23
+ createClassNameRule() {
24
+ var handler = this.handler;
25
+
26
+ return {
27
+ meta: {
28
+ type: 'suggestion',
29
+ docs: {
30
+ description: '检测类名是否符合命名规范',
31
+ category: 'Stylistic Issues',
32
+ recommended: true,
33
+ },
34
+ fixable: 'code',
35
+ schema: [],
36
+ },
37
+ create: function (context) {
38
+ return {
39
+ ClassDeclaration: function (node) {
40
+ handler.handleClassDeclaration(context, node, node, 'class');
41
+ },
42
+ VariableDeclaration: function (node) {
43
+ handler.handleVariableDeclaration(context, node, node, 'class');
44
+ },
45
+ Property: function (node) {
46
+ handler.handleProperty(context, node, node, 'class');
47
+ },
48
+ AssignmentExpression: function (node) {
49
+ handler.handleAssignmentExpression(context, node, node, 'class');
50
+ },
51
+ ExportDefaultDeclaration: function (node) {
52
+ handler.handleExportDefaultDeclaration(context, node, node, 'class');
53
+ },
54
+ ExportNamedDeclaration: function (node) {
55
+ handler.handleExportNamedDeclaration(context, node, node, 'class');
56
+ },
57
+ ClassExpression: function (node) {
58
+ handler.handleClassExpression(context, node, node, 'class');
59
+ },
60
+ ImportDeclaration: function (node) {
61
+ handler.handleImportDeclaration(context, node, node, 'class');
62
+ },
63
+ Identifier: function (node) {
64
+ handler.handleIdentifier(context, node, node, 'class');
65
+ }
66
+ };
67
+ },
68
+ };
69
+ }
70
+
71
+ /**
72
+ * 创建类实例名规则
73
+ * @returns {object} 类实例名规则配置
74
+ */
75
+ createClassInstanceNameRule() {
76
+ var handler = this.handler;
77
+
78
+ return {
79
+ meta: {
80
+ type: 'suggestion',
81
+ docs: {
82
+ description: '检测类实例名是否符合命名规范',
83
+ category: 'Stylistic Issues',
84
+ recommended: true,
85
+ },
86
+ fixable: 'code',
87
+ schema: [],
88
+ },
89
+ create: function (context) {
90
+ return {
91
+ VariableDeclaration: function (node) {
92
+ handler.handleVariableDeclaration(context, node, node, 'class-instance');
93
+ },
94
+ Property: function (node) {
95
+ handler.handleProperty(context, node, node, 'class-instance');
96
+ },
97
+ AssignmentExpression: function (node) {
98
+ handler.handleAssignmentExpression(context, node, node, 'class-instance');
99
+ },
100
+ PropertyDefinition: function (node) {
101
+ handler.handlePropertyDefinition(context, node, node, 'class-instance');
102
+ }
103
+ };
104
+ },
105
+ };
106
+ }
107
+
108
+ /**
109
+ * 创建函数名规则
110
+ * @returns {object} 函数名规则配置
111
+ */
112
+ createFunctionNameRule() {
113
+ var handler = this.handler;
114
+
115
+ return {
116
+ meta: {
117
+ type: 'suggestion',
118
+ docs: {
119
+ description: '检测函数名是否符合命名规范',
120
+ category: 'Stylistic Issues',
121
+ recommended: true,
122
+ },
123
+ fixable: 'code',
124
+ schema: [],
125
+ },
126
+ create: function (context) {
127
+ return {
128
+ FunctionDeclaration: function (node) {
129
+ handler.handleFunctionDeclaration(context, node, node, 'function');
130
+ },
131
+ FunctionExpression: function (node) {
132
+ handler.handleFunctionExpression(context, node, node, 'function');
133
+ },
134
+ ArrowFunctionExpression: function (node) {
135
+ handler.handleArrowFunctionExpression(context, node, node, 'function');
136
+ },
137
+ CallExpression: function (node) {
138
+ handler.handleCallExpression(context, node, node, 'function');
139
+ },
140
+ MethodDefinition: function (node) {
141
+ handler.handleMethodDefinition(context, node, node, 'function');
142
+ },
143
+ Property: function (node) {
144
+ handler.handleProperty(context, node, node, 'function');
145
+ },
146
+ PropertyDefinition: function (node) {
147
+ handler.handlePropertyDefinition(context, node, node, 'function');
148
+ },
149
+ AssignmentExpression: function (node) {
150
+ handler.handleAssignmentExpression(context, node, node, 'function');
151
+ },
152
+ VariableDeclaration: function (node) {
153
+ handler.handleVariableDeclaration(context, node, node, 'function');
154
+ },
155
+ };
156
+ },
157
+ };
158
+ }
159
+
160
+ /**
161
+ * 创建变量名规则
162
+ * @returns {object} 变量名规则配置
163
+ */
164
+ createVariableNameRule() {
165
+ var handler = this.handler;
166
+
167
+ return {
168
+ meta: {
169
+ type: 'suggestion',
170
+ docs: {
171
+ description: '检测变量名是否符合命名规范',
172
+ category: 'Stylistic Issues',
173
+ recommended: true,
174
+ },
175
+ fixable: 'code',
176
+ schema: [],
177
+ },
178
+ create: function (context) {
179
+ return {
180
+ VariableDeclaration: function (node) {
181
+ handler.handleVariableDeclaration(context, node, node, 'variable');
182
+ },
183
+ ForStatement: function (node) {
184
+ if (node.init && node.init.type === 'VariableDeclaration') {
185
+ handler.handleVariableDeclaration(context, node, node.init, 'variable');
186
+ }
187
+ },
188
+ ForInStatement: function (node) {
189
+ if (node.left && node.left.type === 'VariableDeclaration') {
190
+ handler.handleVariableDeclaration(context, node, node.left, 'variable');
191
+ }
192
+ },
193
+ ForOfStatement: function (node) {
194
+ if (node.left && node.left.type === 'VariableDeclaration') {
195
+ handler.handleVariableDeclaration(context, node, node.left, 'variable');
196
+ }
197
+ },
198
+ Property: function (node) {
199
+ handler.handleProperty(context, node, node, 'variable');
200
+ },
201
+ PropertyDefinition: function (node) {
202
+ handler.handlePropertyDefinition(context, node, node, 'variable');
203
+ },
204
+ AssignmentExpression: function (node) {
205
+ handler.handleAssignmentExpression(context, node, node, 'variable');
206
+ }
207
+ };
208
+ },
209
+ };
210
+ }
211
+
212
+ /**
213
+ * 创建常量名规则
214
+ * @returns {object} 常量名规则配置
215
+ */
216
+ createConstantNameRule() {
217
+ var handler = this.handler;
218
+
219
+ return {
220
+ meta: {
221
+ type: 'suggestion',
222
+ docs: {
223
+ description: '检测常量名是否符合命名规范',
224
+ category: 'Stylistic Issues',
225
+ recommended: true,
226
+ },
227
+ fixable: 'code',
228
+ schema: [],
229
+ },
230
+ create: function (context) {
231
+ return {
232
+ VariableDeclaration: function (node) {
233
+ handler.handleVariableDeclaration(context, node, node, 'constant');
234
+ },
235
+ Property: function (node) {
236
+ handler.handleProperty(context, node, node, 'constant');
237
+ },
238
+ PropertyDefinition: function (node) {
239
+ handler.handlePropertyDefinition(context, node, node, 'constant');
240
+ },
241
+ AssignmentExpression: function (node) {
242
+ handler.handleAssignmentExpression(context, node, node, 'constant');
243
+ }
244
+ };
245
+ },
246
+ };
247
+ }
248
+
249
+ /**
250
+ * 创建参数名规则
251
+ * @returns {object} 参数名规则配置
252
+ */
253
+ createParamNameRule() {
254
+ var handler = this.handler;
255
+
256
+ return {
257
+ meta: {
258
+ type: 'suggestion',
259
+ docs: {
260
+ description: '检测参数名是否符合命名规范',
261
+ category: 'Stylistic Issues',
262
+ recommended: true,
263
+ },
264
+ fixable: 'code',
265
+ schema: [],
266
+ },
267
+ create: function (context) {
268
+ return {
269
+ FunctionDeclaration: function (node) {
270
+ if (node.params && node.params.length > 0) {
271
+ for (var i = 0; i < node.params.length; i++) {
272
+ var param = node.params[i];
273
+ if (param.type === 'Identifier') {
274
+ var result = handler.detector.detect(param, param.name);
275
+ if (result) {
276
+ result.node = param;
277
+ result.fix = handler.fix.createParamFixFunction(context, param, result);
278
+ context.report(result);
279
+ }
280
+ }
281
+ }
282
+ }
283
+ },
284
+ FunctionExpression: function (node) {
285
+ if (node.params && node.params.length > 0) {
286
+ for (var i = 0; i < node.params.length; i++) {
287
+ var param = node.params[i];
288
+ if (param.type === 'Identifier') {
289
+ var result = handler.detector.detect(param, param.name);
290
+ if (result) {
291
+ result.node = param;
292
+ result.fix = handler.fix.createParamFixFunction(context, param, result);
293
+ context.report(result);
294
+ }
295
+ }
296
+ }
297
+ }
298
+ },
299
+ ArrowFunctionExpression: function (node) {
300
+ if (node.params && node.params.length > 0) {
301
+ for (var i = 0; i < node.params.length; i++) {
302
+ var param = node.params[i];
303
+ if (param.type === 'Identifier') {
304
+ var result = handler.detector.detect(param, param.name);
305
+ if (result) {
306
+ result.node = param;
307
+ result.fix = handler.fix.createParamFixFunction(context, param, result);
308
+ context.report(result);
309
+ }
310
+ }
311
+ }
312
+ }
313
+ }
314
+ };
315
+ },
316
+ };
317
+ }
318
+
319
+ /**
320
+ * 获取所有规则
321
+ * @returns {object} 所有规则配置
322
+ */
323
+ getAllRules() {
324
+ return {
325
+ 'class-name': this.createClassNameRule(),
326
+ 'class-instance-name': this.createClassInstanceNameRule(),
327
+ 'function-name': this.createFunctionNameRule(),
328
+ 'variable-name': this.createVariableNameRule(),
329
+ 'constant-name': this.createConstantNameRule(),
330
+ 'param-name': this.createParamNameRule()
331
+ };
332
+ }
333
+ }
334
+
335
+ /**
336
+ * 创建ESLint规则配置
337
+ * @returns {object} ESLint规则配置对象
338
+ */
339
+ function createNamingRules() {
340
+ var rules = new Rules();
341
+ return rules.getAllRules();
342
+ }
343
+
344
+ module.exports = createNamingRules();