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/detector.js CHANGED
@@ -1,1239 +1,1291 @@
1
-
2
- const { Config } = require('./config');
3
- const { Validator } = require('./validator');
4
- const { Corrector } = require('./corrector');
5
- const { Tip } = require('./tip');
6
-
7
- /**
8
- * 命名规范检测器类
9
- * 负责检测命名类型
10
- */
11
- class Detector {
12
- /**
13
- * 构造函数
14
- * @param {object} config 配置对象
15
- */
16
- constructor(config) {
17
- this.config = config || new Config();
18
- this.validator = new Validator(config);
19
- this.corrector = new Corrector(config);
20
- this.tip = new Tip(config);
21
- }
22
- }
23
-
24
- /**
25
- * 获取原始类型
26
- * @param {object} node AST节点
27
- * @returns {string} 原始类型
28
- */
29
- Detector.prototype._getOriginalType = function (node) {
30
- if (!node) {
31
- return 'variable';
32
- }
33
-
34
- // 检查是否为属性节点
35
- var is_property = false;
36
- var current_node = node;
37
-
38
- // 特殊处理:类中的实例方法应该视为属性函数
39
- var is_class_method = false;
40
- var is_static_method = false;
41
-
42
- if (node.type === 'MethodDefinition') {
43
- is_class_method = true;
44
- is_static_method = node.static || false;
45
- }
46
-
47
- while (current_node.parent) {
48
- // 如果是属性节点或成员表达式,且不是顶层声明
49
- if (current_node.parent.type === 'Property' ||
50
- current_node.parent.type === 'MemberExpression') {
51
- is_property = true;
52
- break;
53
- }
54
- // 如果是对象表达式,但父级不是变量声明,则视为属性
55
- if (current_node.parent.type === 'ObjectExpression' &&
56
- current_node.parent.parent &&
57
- current_node.parent.parent.type !== 'VariableDeclarator') {
58
- is_property = true;
59
- break;
60
- }
61
- // 类中的实例方法应该视为属性函数,但静态方法保持静态函数类型
62
- if (current_node.parent.type === 'ClassBody' ||
63
- current_node.parent.type === 'ClassDeclaration' ||
64
- current_node.parent.type === 'ClassExpression') {
65
- // 如果是类中的方法,但不是静态方法,则视为属性
66
- if (is_class_method && !is_static_method) {
67
- is_property = true;
68
- }
69
- break;
70
- }
71
- current_node = current_node.parent;
72
- }
73
-
74
- // 根据AST节点类型映射到配置文件中定义的命名类型
75
- switch (node.type) {
76
- case 'ClassDeclaration':
77
- case 'ClassExpression':
78
- return is_property ? 'property-class' : 'class';
79
-
80
- case 'MethodDefinition':
81
- // 检查是否是静态方法
82
- if (node.static) {
83
- return is_property ? 'property-static-function' : 'static-function';
84
- }
85
- // 私有方法使用与普通方法相同的命名规则
86
- return is_property ? 'property-function' : 'function';
87
-
88
- case 'FunctionDeclaration':
89
- case 'FunctionExpression':
90
- case 'ArrowFunctionExpression':
91
- return is_property ? 'property-function' : 'function';
92
-
93
- case 'VariableDeclarator':
94
- return this._getVariableDeclaratorType(node);
95
-
96
- case 'Property':
97
- // 属性节点需要根据属性值类型进一步判断
98
- return this._getPropertyType(node);
99
-
100
- case 'NewExpression':
101
- return is_property ? 'property-class-instance' : 'class-instance';
102
-
103
- case 'AssignmentExpression':
104
- // 赋值表达式:根据赋值右侧的类型判断
105
- return this._getAssignmentPropertyType(node);
106
-
107
- case 'PropertyDefinition':
108
- // 类属性:根据属性值的类型判断
109
- if (node.value && node.value.type === 'NewExpression') {
110
- // 如果是new表达式,则根据是否为静态属性判断类型
111
- if (node.static) {
112
- return 'static-class-instance'; // 静态类字段实例
113
- }
114
- return 'property-class-instance'; // 普通类字段实例
115
- }
116
-
117
- // 检查是否为函数类型的属性值
118
- if (node.value) {
119
- var function_types = ['FunctionExpression', 'ArrowFunctionExpression'];
120
- if (function_types.includes(node.value.type)) {
121
- // 类属性函数:根据是否为静态属性判断类型
122
- if (node.static) {
123
- return 'static-function'; // 静态类字段函数
124
- }
125
- return 'property-function'; // 普通类字段函数
126
- }
127
- }
128
-
129
- // 类属性:根据是否为静态属性判断类型
130
- if (node.static) {
131
- return 'static-variable';
132
- }
133
- return 'property-variable';
134
-
135
- case 'Identifier':
136
- // 如果是属性名标识符
137
- if (node.parent && node.parent.type === 'Property' && node.parent.key === node) {
138
- // 根据属性值的类型判断属性类型
139
- return this._getPropertyType(node.parent);
140
- }
141
-
142
- // 如果是赋值表达式中的属性名标识符
143
- if (node.parent && node.parent.type === 'MemberExpression' &&
144
- node.parent.property === node && node.parent.parent &&
145
- node.parent.parent.type === 'AssignmentExpression') {
146
- // 根据赋值右侧的类型判断属性类型
147
- return this._getAssignmentPropertyType(node.parent.parent);
148
- }
149
-
150
- // 如果是类名标识符
151
- if (node.parent && (node.parent.type === 'ClassDeclaration' ||
152
- node.parent.type === 'ClassExpression')) {
153
- return is_property ? 'property-class' : 'class';
154
- }
155
-
156
- // 如果是变量声明标识符
157
- if (node.parent && node.parent.type === 'VariableDeclarator' &&
158
- node.parent.id === node) {
159
- return this._getVariableDeclaratorType(node.parent, is_property);
160
- }
161
-
162
- // 如果是参数节点(函数声明、函数表达式中的参数)
163
- if (node.parent && (node.parent.type === 'FunctionDeclaration' ||
164
- node.parent.type === 'FunctionExpression' ||
165
- node.parent.type === 'ArrowFunctionExpression')) {
166
- // 检查是否是函数参数(不是函数名)
167
- if (node.parent.params && node.parent.params.includes(node)) {
168
- return 'param';
169
- }
170
- // 如果不是参数,则是函数名
171
- return is_property ? 'property-function' : 'function';
172
- }
173
-
174
- // 如果是函数调用中的函数名标识符
175
- if (node.parent && node.parent.type === 'CallExpression' &&
176
- node.parent.callee === node) {
177
- return is_property ? 'property-function' : 'function';
178
- }
179
-
180
- // 如果是方法参数节点
181
- if (node.parent && node.parent.type === 'MethodDefinition') {
182
- // 检查是否是方法参数(不是方法名)
183
- if (node.parent.value && node.parent.value.params && node.parent.value.params.includes(node)) {
184
- return 'param';
185
- }
186
- }
187
-
188
- // 其他标识符根据上下文判断
189
- return is_property ? 'property-variable' : 'variable';
190
-
191
- default:
192
- return is_property ? 'property-variable' : 'variable';
193
- }
194
- };
195
-
196
- /**
197
- * 检测命名规范
198
- * @param {string} name 名称
199
- * @param {object} node AST节点
200
- * @param {string} expected_type 期望的命名类型
201
- * @returns {object} 检测结果
202
- */
203
- Detector.prototype.detect = function (name, node, expected_type = null) {
204
- // 根据AST节点类型自动推断命名类型
205
- var original_type = this._getOriginalType(node);
206
-
207
- // 如果指定了期望类型,但推断类型不匹配,则返回null
208
- if (expected_type && original_type !== expected_type) {
209
- return null;
210
- }
211
-
212
- var error = this.validator.validate(name, original_type);
213
- if (!error) {
214
- return null;
215
- }
216
- var fix_suggestion = this.corrector.getSuggestion(error);
217
- var message = this.tip.getFullMessage(error, fix_suggestion);
218
- return {
219
- node,
220
- message,
221
- error_type: error.type,
222
- severity: error.severity,
223
- fix_suggestion: fix_suggestion,
224
- original_type: original_type
225
- }
226
- }
227
-
228
- /**
229
- * 获取变量声明类型
230
- * @param {object} node 变量声明节点
231
- * @param {boolean} is_property 是否为属性节点
232
- * @returns {string} 原始类型
233
- */
234
- Detector.prototype._getVariableDeclaratorType = function (node, is_property = false) {
235
- // 检查是否为类表达式赋值
236
- if (node.init && node.init.type === 'ClassExpression') {
237
- return is_property ? 'property-class' : 'class'; // 类表达式赋值 -> 类类型
238
- }
239
-
240
- // 检查是否为函数赋值
241
- if (node.init && (node.init.type === 'FunctionExpression' ||
242
- node.init.type === 'ArrowFunctionExpression')) {
243
- // 特殊处理:检查是否为混入类(返回类表达式的箭头函数)
244
- if (node.init.type === 'ArrowFunctionExpression' &&
245
- node.init.body && node.init.body.type === 'ClassExpression') {
246
- return is_property ? 'property-class' : 'class'; // 混入类 -> 类类型
247
- }
248
- return is_property ? 'property-function' : 'function'; // 函数赋值 -> 函数类型
249
- }
250
-
251
- // 检查是否为类实例赋值
252
- if (node.init && node.init.type === 'NewExpression') {
253
- return is_property ? 'property-class-instance' : 'class-instance'; // 类实例赋值 -> 类实例类型
254
- }
255
-
256
- // 检查是否为正则表达式字面量(RegExp实例)
257
- if (node.init && node.init.type === 'Literal' && node.init.regex) {
258
- return is_property ? 'property-class-instance' : 'class-instance'; // 正则表达式字面量 -> 类实例类型
259
- }
260
-
261
- // 检查是否为包含函数的对象(类实例)
262
- if (node.init && node.init.type === 'ObjectExpression' &&
263
- node.init.properties && node.init.properties.length > 0) {
264
- for (var i = 0; i < node.init.properties.length; i++) {
265
- var property = node.init.properties[i];
266
- if (property.value && (property.value.type === 'FunctionExpression' ||
267
- property.value.type === 'ArrowFunctionExpression' ||
268
- property.value.type === 'ClassExpression')) {
269
- return is_property ? 'property-class-instance' : 'class-instance'; // 包含函数的对象 -> 类实例
270
- }
271
- }
272
- }
273
-
274
- // 检查是否为字面量赋值
275
- if (node.init && this._isLiteralValue(node.init)) {
276
- // 只有纯字面量才能被识别为变量或常量
277
- if (node.parent && node.parent.kind === 'const') {
278
- return is_property ? 'property-constant' : 'constant'; // const 声明的字面量 -> 常量
279
- }
280
- return is_property ? 'property-variable' : 'variable'; // let/var 声明的字面量 -> 变量
281
- }
282
-
283
- // 检查是否为函数调用赋值
284
- if (node.init && node.init.type === 'CallExpression') {
285
- // 特殊处理:检查是否为Object.freeze/Object.seal调用
286
- var callee = node.init.callee;
287
- if (callee.type === 'MemberExpression') {
288
- var object_name = callee.object.name;
289
- var property_name = callee.property.name;
290
- if (object_name === 'Object' &&
291
- (property_name === 'freeze' || property_name === 'seal')) {
292
- // Object.freeze/Object.seal包装的字面量应该视为常量
293
- if (node.parent && node.parent.kind === 'const') {
294
- return is_property ? 'property-constant' : 'constant';
295
- }
296
- }
297
- }
298
- // 其他函数调用赋值应该视为变量
299
- return is_property ? 'property-variable' : 'variable';
300
- }
301
-
302
- // 检查是否为标识符赋值(如 undefined、null 等)
303
- if (node.init && node.init.type === 'Identifier') {
304
- // 特殊标识符赋值应该视为变量
305
- var identifier_name = node.init.name;
306
- if (identifier_name === 'undefined' || identifier_name === 'null' || identifier_name === 'NaN' || identifier_name === 'Infinity') {
307
- return is_property ? 'property-variable' : 'variable';
308
- }
309
- // 其他标识符赋值视为类实例
310
- return is_property ? 'property-class-instance' : 'class-instance';
311
- }
312
-
313
- // 其他非字面量赋值视为类实例
314
- return is_property ? 'property-class-instance' : 'class-instance';
315
- };
316
-
317
- /**
318
- * 获取赋值表达式中的属性类型
319
- * @param {object} node 赋值表达式节点
320
- * @returns {string} 原始类型
321
- */
322
- Detector.prototype._getAssignmentPropertyType = function (node) {
323
- if (!node.right) {
324
- return 'property-variable';
325
- }
326
-
327
- // 根据赋值右侧的类型判断属性类型
328
- switch (node.right.type) {
329
- case 'FunctionExpression':
330
- case 'ArrowFunctionExpression':
331
- // 检查是否为原型方法赋值
332
- if (node.left &&
333
- node.left.type === 'MemberExpression' &&
334
- node.left.object &&
335
- node.left.object.type === 'MemberExpression' &&
336
- node.left.object.property &&
337
- node.left.object.property.type === 'Identifier' &&
338
- node.left.object.property.name === 'prototype') {
339
- return 'prototype-function';
340
- }
341
- return 'property-function';
342
-
343
- case 'ClassExpression':
344
- return 'property-class';
345
-
346
- case 'NewExpression':
347
- return 'property-class-instance';
348
-
349
- case 'CallExpression':
350
- // 函数调用:根据函数名推断返回值类型
351
- // 如果函数名以'create'、'get'、'make'等开头,可能返回实例
352
- if (node.right.callee && node.right.callee.type === 'Identifier') {
353
- var func_name = node.right.callee.name.toLowerCase();
354
- if (func_name.startsWith('create') || func_name.startsWith('get') ||
355
- func_name.startsWith('make') || func_name.startsWith('build')) {
356
- return 'property-class-instance';
357
- }
358
- }
359
- return 'property-variable';
360
-
361
- case 'Literal':
362
- case 'TemplateLiteral':
363
- case 'ArrayExpression':
364
- case 'ObjectExpression':
365
- // 字面量值:根据属性名判断类型
366
- if (node.left && node.left.type === 'MemberExpression' &&
367
- node.left.property && node.left.property.type === 'Identifier') {
368
- var property_name = node.left.property.name;
369
-
370
- // 检查属性名是否为常量名规范(UPPER_SNAKE_CASE)
371
- var constant_name_regex = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/;
372
- if (constant_name_regex.test(property_name)) {
373
- return 'property-constant';
374
- }
375
-
376
- // 检查属性名是否为类名规范(PascalCase)
377
- var class_name_regex = /^[A-Z][a-z]*([A-Z][a-z]*)*$/;
378
- if (class_name_regex.test(property_name)) {
379
- return 'property-class';
380
- }
381
- }
382
- return 'property-variable';
383
-
384
- case 'Identifier':
385
- // 检查标识符是否为类引用
386
- // 如果标识符名称符合类名规范(PascalCase),则视为类引用
387
- var class_name_regex = /^[A-Z][a-z]*([A-Z][a-z]*)*$/;
388
-
389
- // 检查标识符是否为常量引用
390
- // 如果标识符名称符合常量名规范(UPPER_SNAKE_CASE),则视为常量引用
391
- var constant_name_regex = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/;
392
-
393
- // 检查是否为解构赋值的情况(node.right可能不存在)
394
- if (node.right && node.right.name) {
395
- if (class_name_regex.test(node.right.name)) {
396
- return 'property-class';
397
- }
398
- if (constant_name_regex.test(node.right.name)) {
399
- return 'property-constant';
400
- }
401
- }
402
-
403
- // 对于解构赋值中的标识符,直接根据标识符名称判断
404
- if (node.value && node.value.name) {
405
- if (class_name_regex.test(node.value.name)) {
406
- return 'property-class';
407
- }
408
- if (constant_name_regex.test(node.value.name)) {
409
- return 'property-constant';
410
- }
411
- }
412
-
413
- return 'property-variable';
414
-
415
- case 'Literal':
416
- case 'TemplateLiteral':
417
- case 'ArrayExpression':
418
- case 'ObjectExpression':
419
- // 检查是否为字面量值,并根据父级对象类型判断属性类型
420
- if (this._isLiteralValue(node.value)) {
421
- // 首先获取属性所在对象的类型
422
- var parent_object_type = this._getParentObjectType(node);
423
-
424
- // 如果父级对象是类实例,字面量属性值应该识别为变量属性
425
- if (parent_object_type === 'class-instance' || parent_object_type === 'property-class-instance') {
426
- return 'property-variable';
427
- }
428
-
429
- // 如果父级对象是常量,字面量属性值应该识别为常量属性
430
- if (parent_object_type === 'constant' || parent_object_type === 'property-constant') {
431
- return 'property-constant';
432
- }
433
-
434
- // 其他情况都视为变量属性
435
- return 'property-variable';
436
- }
437
- return 'property-variable';
438
-
439
- default:
440
- return 'property-variable';
441
- }
442
- };
443
-
444
- /**
445
- * 获取属性所在对象的类型
446
- * @param {object} node 属性节点
447
- * @returns {string} 对象类型
448
- */
449
- Detector.prototype._getParentObjectType = function (node) {
450
- var current_node = node;
451
-
452
- // 向上遍历父节点,找到对象表达式或变量声明
453
- while (current_node.parent) {
454
- current_node = current_node.parent;
455
-
456
- // 如果是对象表达式,继续向上找变量声明
457
- if (current_node.type === 'ObjectExpression') {
458
- continue;
459
- }
460
-
461
- // 如果是变量声明,获取其类型
462
- if (current_node.type === 'VariableDeclarator') {
463
- return this._getVariableDeclaratorType(current_node, true); // true 表示是属性
464
- }
465
-
466
- // 如果是赋值表达式,获取其类型
467
- if (current_node.type === 'AssignmentExpression') {
468
- return this._getAssignmentPropertyType(current_node);
469
- }
470
- }
471
-
472
- return 'unknown';
473
- };
474
-
475
- /**
476
- * 获取属性所在对象的声明类型
477
- * @param {object} node 属性节点
478
- * @returns {string} 声明类型('const'、'let'、'var' 或 'unknown')
479
- */
480
- Detector.prototype._getParentDeclarationType = function (node) {
481
- var current_node = node;
482
-
483
- // 向上遍历父节点,找到变量声明或赋值表达式
484
- while (current_node.parent) {
485
- current_node = current_node.parent;
486
-
487
- // 如果是变量声明
488
- if (current_node.type === 'VariableDeclarator') {
489
- if (current_node.parent && current_node.parent.kind) {
490
- return current_node.parent.kind; // 'const', 'let', 'var'
491
- }
492
- }
493
-
494
- // 如果是赋值表达式
495
- if (current_node.type === 'AssignmentExpression') {
496
- return 'variable'; // 赋值表达式视为变量
497
- }
498
-
499
- // 如果是函数参数
500
- if (current_node.type === 'FunctionDeclaration' ||
501
- current_node.type === 'FunctionExpression' ||
502
- current_node.type === 'ArrowFunctionExpression') {
503
- return 'param'; // 函数参数
504
- }
505
- }
506
-
507
- return 'unknown';
508
- };
509
-
510
- /**
511
- * 获取属性类型
512
- * @param {object} node 属性节点
513
- * @returns {string} 原始类型
514
- */
515
- Detector.prototype._getPropertyType = function (node) {
516
- if (!node.value) {
517
- return 'property-variable';
518
- }
519
-
520
- // 根据属性值的类型判断属性类型
521
- switch (node.value.type) {
522
- case 'FunctionExpression':
523
- case 'ArrowFunctionExpression':
524
- return 'property-function';
525
-
526
- case 'ClassExpression':
527
- return 'property-class';
528
-
529
- case 'NewExpression':
530
- return 'property-class-instance';
531
-
532
- case 'Identifier':
533
- // 检查标识符是否为类引用
534
- // 如果标识符名称符合类名规范(PascalCase),则视为类引用
535
- var class_name_regex = /^[A-Z][a-z]*([A-Z][a-z]*)*$/;
536
-
537
- // 检查是否为解构赋值的情况(node.right可能不存在)
538
- if (node.right && node.right.name && class_name_regex.test(node.right.name)) {
539
- return 'property-class';
540
- }
541
-
542
- // 对于解构赋值中的标识符,直接根据标识符名称判断
543
- if (node.value.name && class_name_regex.test(node.value.name)) {
544
- return 'property-class';
545
- }
546
-
547
- // 检查标识符是否为函数参数引用
548
- if (this._isParameterName(node.value)) {
549
- return 'property-variable'; // 函数参数引用应该视为变量属性
550
- }
551
-
552
- return 'property-variable';
553
-
554
- case 'Literal':
555
- case 'TemplateLiteral':
556
- case 'ArrayExpression':
557
- case 'ObjectExpression':
558
- // 检查是否为字面量值,并根据属性名判断类型
559
- if (this._isLiteralValue(node.value)) {
560
- // 首先根据属性名判断类型
561
- if (node.key && node.key.type === 'Identifier') {
562
- var property_name = node.key.name;
563
-
564
- // 检查属性名是否为常量名规范(UPPER_SNAKE_CASE)
565
- var constant_name_regex = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/;
566
- if (constant_name_regex.test(property_name)) {
567
- return 'property-constant';
568
- }
569
-
570
- // 检查属性名是否为类名规范(PascalCase)
571
- var class_name_regex = /^[A-Z][a-z]*([A-Z][a-z]*)*$/;
572
- if (class_name_regex.test(property_name)) {
573
- return 'property-class';
574
- }
575
- }
576
-
577
- // 如果属性名不符合特定规范,再根据父级对象类型判断
578
- var parent_object_type = this._getParentObjectType(node);
579
-
580
- // 如果父级对象是类实例,字面量属性值应该识别为变量属性
581
- if (parent_object_type === 'class-instance' || parent_object_type === 'property-class-instance') {
582
- return 'property-variable';
583
- }
584
-
585
- // 如果父级对象是常量,字面量属性值应该识别为常量属性
586
- if (parent_object_type === 'constant' || parent_object_type === 'property-constant') {
587
- return 'property-constant';
588
- }
589
-
590
- // 其他情况都视为变量属性
591
- return 'property-variable';
592
- }
593
- return 'property-variable';
594
-
595
- default:
596
- return 'property-variable';
597
- }
598
- };
599
-
600
- /**
601
- * 判断是否为字面量值
602
- * @param {object} node AST节点
603
- * @returns {boolean} 是否为字面量
604
- */
605
- Detector.prototype._isLiteralValue = function (node) {
606
- if (!node) {
607
- return false;
608
- }
609
-
610
- switch (node.type) {
611
- case 'Literal':
612
- // 布尔型、字符串型、数字型字面量
613
- // 排除正则表达式字面量(应该视为类实例)
614
- if (node.regex) {
615
- // 正则表达式字面量有regex属性,应该视为类实例,不是普通字面量
616
- return false;
617
- }
618
- return true;
619
-
620
- case 'TemplateLiteral':
621
- // 模板字符串字面量
622
- return true;
623
-
624
- case 'Identifier':
625
- // 特殊字面量标识符:undefined、null、Infinity、NaN等
626
- var literal_identifiers = ['undefined', 'null', 'Infinity', 'NaN', 'true', 'false'];
627
- if (literal_identifiers.includes(node.name)) {
628
- return true;
629
- }
630
- return false;
631
-
632
- case 'ArrayExpression':
633
- // 数组型字面量:检查所有元素是否都是字面量
634
- if (node.elements && node.elements.length > 0) {
635
- for (var i = 0; i < node.elements.length; i++) {
636
- if (!this._isLiteralValue(node.elements[i])) {
637
- return false;
638
- }
639
- }
640
- return true;
641
- }
642
- return true; // 空数组也是字面量
643
-
644
- case 'ObjectExpression':
645
- // 对象型字面量:检查所有属性值是否都是字面量
646
- if (node.properties && node.properties.length > 0) {
647
- for (var i = 0; i < node.properties.length; i++) {
648
- var property = node.properties[i];
649
- if (property.value && !this._isLiteralValue(property.value)) {
650
- return false;
651
- }
652
- }
653
- return true;
654
- }
655
- return true; // 空对象也是字面量
656
-
657
- default:
658
- return false;
659
- }
660
- };
661
-
662
- /**
663
- * 检查节点是否为参数名或参数引用
664
- * @param {object} node AST节点
665
- * @returns {boolean} 是否为参数名或参数引用
666
- */
667
- Detector.prototype._isParameterName = function (node) {
668
- if (!node || !node.parent) {
669
- return false;
670
- }
671
-
672
- // 检查是否为函数参数声明
673
- var parent = node.parent;
674
- if (parent.type === 'FunctionDeclaration' ||
675
- parent.type === 'FunctionExpression' ||
676
- parent.type === 'ArrowFunctionExpression') {
677
- if (parent.params && Array.isArray(parent.params)) {
678
- for (var i = 0; i < parent.params.length; i++) {
679
- if (parent.params[i] === node) {
680
- return true;
681
- }
682
- }
683
- }
684
- }
685
-
686
- // 检查是否为函数参数引用(在函数体中使用参数)
687
- var current_node = node;
688
- while (current_node.parent) {
689
- // 检查是否在函数体内
690
- if (current_node.parent.type === 'FunctionDeclaration' ||
691
- current_node.parent.type === 'FunctionExpression' ||
692
- current_node.parent.type === 'ArrowFunctionExpression') {
693
-
694
- // 检查标识符名称是否与函数参数匹配
695
- var function_node = current_node.parent;
696
- if (function_node.params && Array.isArray(function_node.params)) {
697
- for (var i = 0; i < function_node.params.length; i++) {
698
- var param = function_node.params[i];
699
- // 对于普通参数
700
- if (param.type === 'Identifier' && param.name === node.name) {
701
- return true;
702
- }
703
- // 对于解构参数,需要递归检查
704
- if ((param.type === 'ObjectPattern' || param.type === 'ArrayPattern') &&
705
- this._isParameterInDestructuredPattern(param, node.name)) {
706
- return true;
707
- }
708
- }
709
- }
710
- break;
711
- }
712
- current_node = current_node.parent;
713
- }
714
-
715
- return false;
716
- }
717
-
718
- /**
719
- * 检查是否为真正的常量(const标签且值为字面量)
720
- * @param {string} constant_name 常量名
721
- * @param {object} decl 声明节点
722
- * @returns {boolean} 是否为真正的常量
723
- */
724
- Detector.prototype._isTrueConstant = function (constant_name, decl) {
725
- // 检查是否为字面量值
726
- var is_literal = false;
727
- if (decl.init) {
728
- // 基本字面量类型
729
- var literal_types = ['Literal', 'RegExpLiteral', 'TemplateLiteral'];
730
- if (literal_types.includes(decl.init.type)) {
731
- is_literal = true;
732
- }
733
-
734
- // 函数类型不是字面量,应该被识别为函数而不是常量
735
- var function_types = ['FunctionExpression', 'ArrowFunctionExpression'];
736
- if (function_types.includes(decl.init.type)) {
737
- return false; // 函数赋值不是字面量,不是真正的常量
738
- }
739
-
740
- // 对象字面量 - 只有当所有属性值都是字面量时才视为常量
741
- if (decl.init.type === 'ObjectExpression') {
742
- var all_properties_literal = true;
743
- if (decl.init.properties && decl.init.properties.length > 0) {
744
- decl.init.properties.forEach(function (prop) {
745
- if (prop.value) {
746
- // 检查属性值是否为非字面量类型
747
- var non_literal_types = ['NewExpression', 'CallExpression', 'FunctionExpression', 'ArrowFunctionExpression', 'ClassExpression'];
748
- if (non_literal_types.includes(prop.value.type)) {
749
- all_properties_literal = false;
750
- }
751
- // 如果属性值是对象或数组,递归检查
752
- else if (prop.value.type === 'ObjectExpression' || prop.value.type === 'ArrayExpression') {
753
- // 创建一个假的声明节点来递归检查
754
- var fake_decl = { init: prop.value };
755
- if (!_isTrueConstant('', fake_decl)) {
756
- all_properties_literal = false;
757
- }
758
- }
759
- }
760
- });
761
- }
762
- is_literal = all_properties_literal;
763
- }
764
-
765
- // 数组字面量 - 只有当所有元素都是字面量时才视为常量
766
- if (decl.init.type === 'ArrayExpression') {
767
- var all_elements_literal = true;
768
- if (decl.init.elements && decl.init.elements.length > 0) {
769
- decl.init.elements.forEach(function (element) {
770
- if (element) {
771
- // 检查元素是否为非字面量类型
772
- var non_literal_types = ['NewExpression', 'CallExpression', 'FunctionExpression', 'ArrowFunctionExpression', 'ClassExpression', 'AssignmentExpression'];
773
- if (non_literal_types.includes(element.type)) {
774
- all_elements_literal = false;
775
- }
776
- // 如果元素是对象或数组,递归检查
777
- else if (element.type === 'ObjectExpression' || element.type === 'ArrayExpression') {
778
- // 创建一个假的声明节点来递归检查
779
- var fake_decl = { init: element };
780
- if (!_isTrueConstant('', fake_decl)) {
781
- all_elements_literal = false;
782
- }
783
- }
784
- }
785
- });
786
- }
787
- is_literal = all_elements_literal;
788
- }
789
-
790
- // Object.freeze/Object.seal包装的字面量
791
- if (decl.init.type === 'CallExpression') {
792
- var callee = decl.init.callee;
793
- if (callee.type === 'MemberExpression') {
794
- var object_name = callee.object.name;
795
- var property_name = callee.property.name;
796
- if (object_name === 'Object' &&
797
- (property_name === 'freeze' || property_name === 'seal')) {
798
- // 检查第一个参数是否为字面量
799
- var args = decl.init.arguments;
800
- if (args && args.length > 0) {
801
- var first_arg = args[0];
802
- if (first_arg.type === 'ObjectExpression' ||
803
- first_arg.type === 'ArrayExpression') {
804
- // 创建一个假的声明节点来检查参数是否为字面量
805
- var fake_decl = { init: first_arg };
806
- is_literal = _isTrueConstant('', fake_decl);
807
- }
808
- }
809
- }
810
- }
811
- }
812
- }
813
-
814
- // 真正的常量是const声明且值为字面量
815
- return is_literal;
816
- }
817
-
818
- /**
819
- * 获取变量验证类型
820
- * @param {object} node 变量声明节点
821
- * @returns {string} 验证类型
822
- */
823
- Detector.prototype._getVariableValidationType = function (node) {
824
- // 检查是否为常量声明
825
- if (node.parent && node.parent.kind === 'const') {
826
- // 检查是否为字面量赋值
827
- if (node.init && this._isLiteralValue(node.init)) {
828
- return 'constant';
829
- }
830
- return 'variable'; // const 声明的非字面量视为变量
831
- }
832
-
833
- // 检查是否为参数
834
- if (node.parent && (node.parent.type === 'FunctionDeclaration' ||
835
- node.parent.type === 'FunctionExpression' ||
836
- node.parent.type === 'ArrowFunctionExpression')) {
837
- return 'param';
838
- }
839
-
840
- return 'variable';
841
- };
842
-
843
- /**
844
- * 获取赋值验证类型
845
- * @param {object} node 赋值表达式节点
846
- * @returns {string} 验证类型
847
- */
848
- Detector.prototype._getAssignmentValidationType = function (node) {
849
- // 检查是否为类实例赋值
850
- if (node.right && node.right.type === 'NewExpression') {
851
- return 'class-instance'; // 类实例使用类实例命名规则
852
- }
853
-
854
- // 检查是否为函数赋值
855
- if (node.right && (node.right.type === 'FunctionExpression' ||
856
- node.right.type === 'ArrowFunctionExpression')) {
857
- return 'function';
858
- }
859
-
860
- return 'variable';
861
- };
862
-
863
- /**
864
- * 获取导出验证类型
865
- * @param {object} node 导出声明节点
866
- * @returns {string} 验证类型
867
- */
868
- Detector.prototype._getExportValidationType = function (node) {
869
- // 根据导出内容的类型决定验证类型
870
- if (node.declaration) {
871
- switch (node.declaration.type) {
872
- case 'ClassDeclaration':
873
- case 'ClassExpression':
874
- return 'class';
875
-
876
- case 'FunctionDeclaration':
877
- case 'FunctionExpression':
878
- return 'function';
879
-
880
- case 'VariableDeclaration':
881
- // 检查是否为常量导出
882
- if (node.declaration.kind === 'const') {
883
- return 'constant';
884
- }
885
- return 'variable';
886
-
887
- default:
888
- return 'variable';
889
- }
890
- }
891
-
892
- return 'variable';
893
- };
894
-
895
- /**
896
- * 获取默认导出验证类型
897
- * @param {object} node 默认导出节点
898
- * @returns {string} 验证类型
899
- */
900
- Detector.prototype._getExportDefaultValidationType = function (node) {
901
- // 根据默认导出内容的类型决定验证类型
902
- if (node.declaration) {
903
- switch (node.declaration.type) {
904
- case 'ClassDeclaration':
905
- case 'ClassExpression':
906
- return 'class';
907
-
908
- case 'FunctionDeclaration':
909
- case 'FunctionExpression':
910
- return 'function';
911
-
912
- default:
913
- return 'class'; // 默认导出通常使用类名规则
914
- }
915
- }
916
-
917
- return 'class'; // 默认使用类名规则
918
- };
919
-
920
- /**
921
- * 获取导入验证类型
922
- * @param {object} node 导入节点
923
- * @returns {string} 验证类型
924
- */
925
- Detector.prototype._getImportValidationType = function (node) {
926
- // 根据导入内容的类型决定验证类型
927
-
928
- // 默认导入通常导入类或默认导出
929
- if (node.type === 'ImportDefaultSpecifier') {
930
- return 'class';
931
- }
932
-
933
- // 命名空间导入使用变量名规则
934
- if (node.type === 'ImportNamespaceSpecifier') {
935
- return 'variable';
936
- }
937
-
938
- // 命名导入根据导入名称推断类型
939
- if (node.type === 'ImportSpecifier') {
940
- var imported_name = node.imported ? node.imported.name : '';
941
-
942
- // 如果导入的名称以大写字母开头,可能是类
943
- if (/^[A-Z]/.test(imported_name)) {
944
- return 'class';
945
- }
946
-
947
- // 如果导入的名称包含特定关键词,可能是函数
948
- var function_keywords = ['get', 'set', 'is', 'has', 'on', 'handle', 'callback'];
949
- var lower_name = imported_name.toLowerCase();
950
- for (var i = 0; i < function_keywords.length; i++) {
951
- if (lower_name.includes(function_keywords[i])) {
952
- return 'function';
953
- }
954
- }
955
-
956
- // 如果导入的名称全大写,可能是常量
957
- if (imported_name === imported_name.toUpperCase()) {
958
- return 'constant';
959
- }
960
- }
961
-
962
- // 默认使用变量名规则
963
- return 'variable';
964
- };
965
-
966
- /**
967
- * 检测参数类型并返回正确的验证类型
968
- * @param {string} name 参数名
969
- * @param {object} node 参数节点
970
- * @returns {string} 验证类型
971
- */
972
- Detector.prototype._getParamValidationType = function (name, node) {
973
- // 根据参数名推断参数类型
974
- // 1. 如果参数名以大写字母开头,可能是类类型参数
975
- if (/^[A-Z]/.test(name)) {
976
- return 'class';
977
- }
978
-
979
- // 2. 如果参数名包含'on'、'handle'、'callback'等,可能是函数类型参数
980
- var function_keywords = ['on', 'handle', 'callback', 'func', 'fn', 'cb'];
981
- var lower_name = name.toLowerCase();
982
- for (var i = 0; i < function_keywords.length; i++) {
983
- if (lower_name.includes(function_keywords[i])) {
984
- return 'function';
985
- }
986
- }
987
-
988
- // 3. 默认使用变量类型参数规则
989
- return 'variable';
990
- };
991
-
992
- /**
993
- * 检查是否为真正的常量(const标签且值为字面量)
994
- * @param {string} constant_name 常量名
995
- * @param {object} decl 声明节点
996
- * @returns {boolean} 是否为真正的常量
997
- */
998
- Detector.prototype._isTrueConstant = function (constant_name, decl) {
999
- // 检查是否为字面量值
1000
- var is_literal = false;
1001
- if (decl.init) {
1002
- // 基本字面量类型
1003
- var literal_types = ['Literal', 'RegExpLiteral', 'TemplateLiteral'];
1004
- if (literal_types.includes(decl.init.type)) {
1005
- is_literal = true;
1006
- }
1007
-
1008
- // 函数类型不是字面量,应该被识别为函数而不是常量
1009
- var function_types = ['FunctionExpression', 'ArrowFunctionExpression'];
1010
- if (function_types.includes(decl.init.type)) {
1011
- return false; // 函数赋值不是字面量,不是真正的常量
1012
- }
1013
-
1014
- // 对象字面量 - 只有当所有属性值都是字面量时才视为常量
1015
- if (decl.init.type === 'ObjectExpression') {
1016
- var all_properties_literal = true;
1017
- if (decl.init.properties && decl.init.properties.length > 0) {
1018
- decl.init.properties.forEach(function (prop) {
1019
- if (prop.value) {
1020
- // 检查属性值是否为非字面量类型
1021
- var non_literal_types = ['NewExpression', 'CallExpression', 'FunctionExpression', 'ArrowFunctionExpression', 'ClassExpression'];
1022
- if (non_literal_types.includes(prop.value.type)) {
1023
- all_properties_literal = false;
1024
- }
1025
- // 如果属性值是对象或数组,递归检查
1026
- else if (prop.value.type === 'ObjectExpression' || prop.value.type === 'ArrayExpression') {
1027
- // 创建一个假的声明节点来递归检查
1028
- var fake_decl = { init: prop.value };
1029
- if (!this._isLiteralValue(prop.value)) {
1030
- all_properties_literal = false;
1031
- }
1032
- }
1033
- }
1034
- }.bind(this));
1035
- }
1036
- is_literal = all_properties_literal;
1037
- }
1038
-
1039
- // 数组字面量 - 只有当所有元素都是字面量时才视为常量
1040
- if (decl.init.type === 'ArrayExpression') {
1041
- var all_elements_literal = true;
1042
- if (decl.init.elements && decl.init.elements.length > 0) {
1043
- decl.init.elements.forEach(function (element) {
1044
- if (element) {
1045
- // 检查元素是否为非字面量类型
1046
- var non_literal_types = ['NewExpression', 'CallExpression', 'FunctionExpression', 'ArrowFunctionExpression', 'ClassExpression', 'AssignmentExpression'];
1047
- if (non_literal_types.includes(element.type)) {
1048
- all_elements_literal = false;
1049
- }
1050
- // 如果元素是对象或数组,递归检查
1051
- else if (element.type === 'ObjectExpression' || element.type === 'ArrayExpression') {
1052
- // 检查元素是否为字面量
1053
- if (!this._isLiteralValue(element)) {
1054
- all_elements_literal = false;
1055
- }
1056
- }
1057
- }
1058
- }.bind(this));
1059
- }
1060
- is_literal = all_elements_literal;
1061
- }
1062
-
1063
- // Object.freeze/Object.seal包装的字面量
1064
- if (decl.init.type === 'CallExpression') {
1065
- var callee = decl.init.callee;
1066
- if (callee.type === 'MemberExpression') {
1067
- var object_name = callee.object.name;
1068
- var property_name = callee.property.name;
1069
- if (object_name === 'Object' &&
1070
- (property_name === 'freeze' || property_name === 'seal')) {
1071
- // 检查第一个参数是否为字面量
1072
- var args = decl.init.arguments;
1073
- if (args && args.length > 0) {
1074
- var first_arg = args[0];
1075
- if (first_arg.type === 'ObjectExpression' ||
1076
- first_arg.type === 'ArrayExpression') {
1077
- // 检查参数是否为字面量
1078
- is_literal = this._isLiteralValue(first_arg);
1079
- }
1080
- }
1081
- }
1082
- }
1083
- }
1084
- }
1085
-
1086
- // 真正的常量是const声明且值为字面量
1087
- return is_literal;
1088
- };
1089
-
1090
-
1091
-
1092
-
1093
-
1094
- /**
1095
- * 检查变量是否为类实例
1096
- * @param {object} decl 变量声明节点
1097
- * @returns {boolean} 是否为类实例
1098
- */
1099
- Detector.prototype._isClassInstance = function (decl) {
1100
- if (!decl.id || decl.id.type !== 'Identifier') {
1101
- return false;
1102
- }
1103
-
1104
- // 检查变量是否被赋值为类实例(new ClassName())
1105
- if (decl.init && decl.init.type === 'NewExpression') {
1106
- return true;
1107
- }
1108
-
1109
- // 检查变量是否被赋值为函数返回的类实例
1110
- if (decl.init && decl.init.type === 'CallExpression') {
1111
- var callee = decl.init.callee;
1112
-
1113
- // 检查是否为成员表达式调用(如 Math.random())
1114
- if (callee.type === 'MemberExpression') {
1115
- var object_name = callee.object.name;
1116
- var property_name = callee.property.name;
1117
-
1118
- // 排除常见的内置对象方法调用
1119
- if (object_name === 'Math' || object_name === 'Date' ||
1120
- object_name === 'String' || object_name === 'Number' ||
1121
- object_name === 'Array' || object_name === 'Object') {
1122
- return false;
1123
- }
1124
- }
1125
-
1126
- // 检查是否为标识符调用
1127
- if (callee.type === 'Identifier') {
1128
- // 排除内置的数学函数
1129
- if (callee.name === 'random' || callee.name === 'now' ||
1130
- callee.name === 'floor' || callee.name === 'ceil' ||
1131
- callee.name === 'round' || callee.name === 'abs') {
1132
- return false;
1133
- }
1134
-
1135
- // 排除常见的内置函数
1136
- var non_instance_functions = ['parseInt', 'parseFloat', 'encodeURI', 'decodeURI',
1137
- 'encodeURIComponent', 'decodeURIComponent', 'isNaN',
1138
- 'isFinite', 'eval', 'setTimeout', 'setInterval'];
1139
- if (non_instance_functions.includes(callee.name)) {
1140
- return false;
1141
- }
1142
-
1143
- // 如果函数名包含create、get、build等关键词,可能是返回类实例的函数
1144
- if (callee.name.match(/^(create|get|build|make|new|init)/i)) {
1145
- return true;
1146
- }
1147
- }
1148
-
1149
- // 默认情况下,函数调用不视为类实例
1150
- return false;
1151
- }
1152
-
1153
- // 检查是否为内置类的实例(RegExp字面量、Array字面量等)
1154
- if (decl.init) {
1155
- // RegExp字面量 - 视为类实例
1156
- if (decl.init.type === 'Literal' && decl.init.regex) {
1157
- return true;
1158
- }
1159
- // Array字面量 [] - 只有当所有元素都是字面量时才视为变量
1160
- if (decl.init.type === 'ArrayExpression') {
1161
- return !this._isLiteralValue(decl.init);
1162
- }
1163
- // Object字面量 {} - 检查是否包含函数(类实例)
1164
- if (decl.init.type === 'ObjectExpression') {
1165
- // 如果对象包含函数,则视为类实例
1166
- if (decl.init.properties && decl.init.properties.length > 0) {
1167
- for (var i = 0; i < decl.init.properties.length; i++) {
1168
- var property = decl.init.properties[i];
1169
- if (property.value && (property.value.type === 'FunctionExpression' ||
1170
- property.value.type === 'ArrowFunctionExpression' ||
1171
- property.value.type === 'ClassExpression')) {
1172
- return true; // 包含函数的对象 -> 类实例
1173
- }
1174
- }
1175
- }
1176
- return false; // 纯字面量对象不是类实例
1177
- }
1178
- // 模板字面量 - 视为变量(基础值字符串类型)
1179
- if (decl.init.type === 'TemplateLiteral') {
1180
- return false;
1181
- }
1182
- }
1183
-
1184
- return false;
1185
- };
1186
-
1187
- /**
1188
- * 检查标识符是否在解构参数模式中
1189
- * @param {object} pattern 解构模式节点
1190
- * @param {string} identifier_name 标识符名称
1191
- * @returns {boolean} 是否在解构参数中
1192
- */
1193
- Detector.prototype._isParameterInDestructuredPattern = function (pattern, identifier_name) {
1194
- if (!pattern) {
1195
- return false;
1196
- }
1197
-
1198
- // 处理对象解构模式
1199
- if (pattern.type === 'ObjectPattern' && pattern.properties) {
1200
- for (var i = 0; i < pattern.properties.length; i++) {
1201
- var property = pattern.properties[i];
1202
- // 检查属性键名是否匹配
1203
- if (property.key && property.key.type === 'Identifier' && property.key.name === identifier_name) {
1204
- return true;
1205
- }
1206
- // 检查属性值是否匹配(对于别名解构)
1207
- if (property.value && property.value.type === 'Identifier' && property.value.name === identifier_name) {
1208
- return true;
1209
- }
1210
- // 递归检查嵌套解构
1211
- if (property.value && (property.value.type === 'ObjectPattern' || property.value.type === 'ArrayPattern')) {
1212
- if (this._isParameterInDestructuredPattern(property.value, identifier_name)) {
1213
- return true;
1214
- }
1215
- }
1216
- }
1217
- }
1218
-
1219
- // 处理数组解构模式
1220
- if (pattern.type === 'ArrayPattern' && pattern.elements) {
1221
- for (var i = 0; i < pattern.elements.length; i++) {
1222
- var element = pattern.elements[i];
1223
- // 检查数组元素是否匹配
1224
- if (element && element.type === 'Identifier' && element.name === identifier_name) {
1225
- return true;
1226
- }
1227
- // 递归检查嵌套解构
1228
- if (element && (element.type === 'ObjectPattern' || element.type === 'ArrayPattern')) {
1229
- if (this._isParameterInDestructuredPattern(element, identifier_name)) {
1230
- return true;
1231
- }
1232
- }
1233
- }
1234
- }
1235
-
1236
- return false;
1237
- };
1238
-
1
+ const { Validator } = require('./validator');
2
+ const { Corrector } = require('./corrector');
3
+ const { Tip } = require('./tip');
4
+
5
+ /**
6
+ * 类型检测器类
7
+ * 负责根据AST节点推断命名类型
8
+ */
9
+ class Detector {
10
+ /**
11
+ * 构造函数
12
+ * @param {object} config 配置对象
13
+ */
14
+ constructor(config) {
15
+ this.config = config;
16
+ this.validator = new Validator(config);
17
+ this.corrector = new Corrector(config);
18
+ this.tip = new Tip(config);
19
+ }
20
+
21
+ /**
22
+ * 检测类声明类型
23
+ * @param {object} node AST节点
24
+ * @returns {string} 类型名称
25
+ */
26
+ detectClassType(node) {
27
+ if (node.type === 'ClassDeclaration') {
28
+ return 'class';
29
+ }
30
+
31
+ if (node.type === 'ClassExpression') {
32
+ return 'class';
33
+ }
34
+
35
+ if (node.type === 'VariableDeclaration' &&
36
+ node.declarations &&
37
+ node.declarations.length > 0 &&
38
+ node.declarations[0].init &&
39
+ node.declarations[0].init.type === 'ClassExpression') {
40
+ return 'class';
41
+ }
42
+
43
+ if (node.type === 'AssignmentExpression' && node.right && node.right.type === 'ClassExpression') {
44
+ return 'class';
45
+ }
46
+
47
+ if (node.type === 'Property' && node.value && node.value.type === 'ClassExpression') {
48
+ return 'property-class';
49
+ }
50
+
51
+ // 处理 module.exports = class user_manager {} 这种形式
52
+ if (node.type === 'AssignmentExpression' &&
53
+ node.left &&
54
+ node.left.type === 'MemberExpression' &&
55
+ node.left.object &&
56
+ node.left.object.type === 'Identifier' &&
57
+ node.left.object.name === 'module' &&
58
+ node.left.property &&
59
+ node.left.property.type === 'Identifier' &&
60
+ node.left.property.name === 'exports' &&
61
+ node.right &&
62
+ node.right.type === 'ClassExpression') {
63
+ return 'class';
64
+ }
65
+
66
+ // 处理 module.exports = { Admin: Admin, AdminManager } 这种形式的引用
67
+ if ((node.type === 'Property' || node.type === 'ObjectProperty') && node.key && node.key.type === 'Identifier') {
68
+ // 检查是否在导出语句的上下文中
69
+ var parent = node.parent;
70
+ if (parent && parent.type === 'ObjectExpression') {
71
+ var grand_parent = parent.parent;
72
+ if (grand_parent && grand_parent.type === 'AssignmentExpression' &&
73
+ grand_parent.left && grand_parent.left.type === 'MemberExpression' &&
74
+ grand_parent.left.object && grand_parent.left.object.type === 'Identifier' &&
75
+ grand_parent.left.object.name === 'module' &&
76
+ grand_parent.left.property && grand_parent.left.property.type === 'Identifier' &&
77
+ grand_parent.left.property.name === 'exports') {
78
+
79
+ // 通用类型溯源:对于导出语句中的属性,溯源其引用的类型
80
+ var traced_type = this._traceReferenceType(node);
81
+ if (traced_type) {
82
+ return traced_type;
83
+ }
84
+
85
+ // 如果无法溯源到具体类型,返回null让其他检测器处理
86
+ return null;
87
+ }
88
+ }
89
+ }
90
+
91
+ return null;
92
+ }
93
+
94
+ /**
95
+ * 检测类实例类型
96
+ * @param {object} node AST节点
97
+ * @returns {string} 类型名称
98
+ */
99
+ detectClassInstanceType(node) {
100
+ // VariableDeclaration 中的 new 表达式
101
+ if (node.type === 'VariableDeclaration') {
102
+ if (node.declarations && node.declarations.length > 0) {
103
+ var decl = node.declarations[0];
104
+ if (decl.init && decl.init.type === 'NewExpression') {
105
+ return 'class-instance';
106
+ }
107
+ }
108
+ }
109
+
110
+ if (node.type === 'Property' && node.value && node.value.type === 'NewExpression') {
111
+ return 'property-class-instance';
112
+ }
113
+
114
+ if (node.type === 'AssignmentExpression' && node.right && node.right.type === 'NewExpression') {
115
+ return 'property-class-instance';
116
+ }
117
+
118
+ if (node.type === 'PropertyDefinition' && node.key && node.value && node.value.type === 'NewExpression') {
119
+ // 判断是否是私有字段
120
+ if (node.key.type === 'PrivateIdentifier') {
121
+ return 'private-class-instance';
122
+ }
123
+ return node.static ? 'static-class-instance' : 'property-class-instance';
124
+ }
125
+
126
+ // 正则表达式字面量视为类实例
127
+ if (node.type === 'VariableDeclaration') {
128
+ if (node.declarations && node.declarations.length > 0) {
129
+ var decl = node.declarations[0];
130
+ if (decl.init && decl.init.type === 'Literal' && decl.init.regex) {
131
+ return 'class-instance';
132
+ }
133
+ }
134
+ }
135
+
136
+ if (node.type === 'Property' && node.value && node.value.type === 'Literal' && node.value.regex) {
137
+ return 'property-class-instance';
138
+ }
139
+
140
+ return null;
141
+ }
142
+
143
+ /**
144
+ * 检测函数类型
145
+ * @param {object} node AST节点
146
+ * @returns {string} 类型名称
147
+ */
148
+ detectFunctionType(node) {
149
+ if (node.type === 'FunctionDeclaration') {
150
+ return 'function';
151
+ }
152
+
153
+ // 检测函数表达式内部的函数名
154
+ if (node.type === 'FunctionExpression' && node.id && node.id.type === 'Identifier') {
155
+ return 'function';
156
+ }
157
+
158
+ if (node.type === 'VariableDeclaration' && node.declarations && node.declarations.length > 0) {
159
+ var decl = node.declarations[0];
160
+ if (decl.init && (decl.init.type === 'FunctionExpression' || decl.init.type === 'ArrowFunctionExpression')) {
161
+ return 'function';
162
+ }
163
+ }
164
+
165
+ // 检测VariableDeclarator节点中的箭头函数
166
+ if (node.type === 'VariableDeclarator' && node.init &&
167
+ (node.init.type === 'FunctionExpression' || node.init.type === 'ArrowFunctionExpression')) {
168
+ return 'function';
169
+ }
170
+
171
+ if (node.type === 'Property' && node.value &&
172
+ (node.value.type === 'FunctionExpression' || node.value.type === 'ArrowFunctionExpression')) {
173
+ return 'property-function';
174
+ }
175
+
176
+ if (node.type === 'MethodDefinition') {
177
+ // 检测私有方法(ES6私有方法语法 # 前缀)
178
+ if (node.key && node.key.type === 'PrivateIdentifier') {
179
+ return 'private-function';
180
+ }
181
+
182
+ // 检测传统私有方法约定(_ 前缀)
183
+ if (node.key && node.key.type === 'Identifier' && node.key.name.startsWith('_')) {
184
+ return node.static ? 'static-function' : 'internal-function';
185
+ }
186
+
187
+ return node.static ? 'static-function' : 'function';
188
+ }
189
+
190
+ if (node.type === 'PropertyDefinition' && node.value &&
191
+ (node.value.type === 'FunctionExpression' || node.value.type === 'ArrowFunctionExpression')) {
192
+ return node.static ? 'static-function' : 'property-function';
193
+ }
194
+
195
+ if (node.type === 'AssignmentExpression' && node.right &&
196
+ (node.right.type === 'FunctionExpression' || node.right.type === 'ArrowFunctionExpression')) {
197
+ return 'property-function';
198
+ }
199
+
200
+ if (node.type === 'CallExpression' && node.callee && node.callee.type === 'Identifier') {
201
+ // 函数调用应该被识别为函数使用,而不是函数定义
202
+ return 'use-function';
203
+ }
204
+
205
+ return null;
206
+ }
207
+
208
+ /**
209
+ * 检测变量类型
210
+ * @param {object} node AST节点
211
+ * @returns {string} 类型名称
212
+ */
213
+ detectVariableType(node) {
214
+ // let/var 声明
215
+ if (node.type === 'VariableDeclaration' && (node.kind === 'let' || node.kind === 'var')) {
216
+ return 'variable';
217
+ }
218
+
219
+ // for 循环中的变量
220
+ if (node.type === 'ForStatement' && node.init && node.init.type === 'VariableDeclaration' &&
221
+ (node.init.kind === 'let' || node.init.kind === 'var')) {
222
+ return 'variable';
223
+ }
224
+
225
+ // 对象属性变量 - 先排除函数类型和常量属性
226
+ if ((node.type === 'Property' || node.type === 'ObjectProperty')) {
227
+ // 如果是函数类型,不应该识别为变量
228
+ if (node.value && (node.value.type === 'FunctionExpression' || node.value.type === 'ArrowFunctionExpression')) {
229
+ return null;
230
+ }
231
+ // 属性简写(如 { user_name })应该识别为变量
232
+ if (node.shorthand && node.value && node.value.type === 'Identifier') {
233
+ return 'property-variable';
234
+ }
235
+ // 只有字面量值且不是常量属性才识别为变量
236
+ if (this._isLiteralValue(node.value)) {
237
+ // 检查是否为常量属性(父级是const声明)
238
+ var parent_type = this._getParentDeclarationType(node);
239
+ if (parent_type !== 'const') {
240
+ return 'property-variable';
241
+ }
242
+ }
243
+ }
244
+
245
+ // 类属性变量
246
+ if (node.type === 'PropertyDefinition' && this._isLiteralValue(node.value)) {
247
+ return node.static ? 'static-variable' : 'property-variable';
248
+ }
249
+
250
+ // 赋值表达式
251
+ if (node.type === 'AssignmentExpression' && this._isLiteralValue(node.right)) {
252
+ return 'property-variable';
253
+ }
254
+
255
+ return null;
256
+ }
257
+
258
+ /**
259
+ * 检测声明方式问题
260
+ * @param {object} node AST节点
261
+ * @returns {string} 问题类型
262
+ */
263
+ detectDeclarationIssue(node) {
264
+ // const 声明但包含非基础字面量 - 应该用let而不是const
265
+ if (node.type === 'VariableDeclaration' && node.kind === 'const') {
266
+ if (node.declarations && node.declarations.length > 0) {
267
+ var decl = node.declarations[0];
268
+ if (decl.init && !this._isBasicLiteralValue(decl.init)) {
269
+ // 排除函数表达式和箭头函数表达式,它们应该使用const声明
270
+ if (decl.init.type === 'FunctionExpression' || decl.init.type === 'ArrowFunctionExpression') {
271
+ return null;
272
+ }
273
+ return 'const-should-be-let';
274
+ }
275
+ }
276
+ }
277
+
278
+ return null;
279
+ }
280
+
281
+ /**
282
+ * 检测常量类型
283
+ * @param {object} node AST节点
284
+ * @returns {string} 类型名称
285
+ */
286
+ detectConstantType(node) {
287
+ // const 声明 - 当右侧是字面量值(包括对象和数组)时视为常量
288
+ if (node.type === 'VariableDeclaration' && node.kind === 'const') {
289
+ // 检查右侧是否是字面量值
290
+ if (node.declarations && node.declarations.length > 0) {
291
+ var decl = node.declarations[0];
292
+ if (decl.init && this._isLiteralValue(decl.init)) {
293
+ return 'constant';
294
+ }
295
+ }
296
+ }
297
+
298
+ // var 和 let 声明应该被识别为变量,而不是常量
299
+ if (node.type === 'VariableDeclaration' && (node.kind === 'var' || node.kind === 'let')) {
300
+ return null; // 返回null,让其他检测器处理
301
+ }
302
+
303
+ // 对象属性常量 - 只有当父级是const声明且属性值是字面量时才视为常量
304
+ if ((node.type === 'Property' || node.type === 'ObjectProperty')) {
305
+ // 只有当值是字面量时才视为常量
306
+ if (this._isLiteralValue(node.value)) {
307
+ var parent_type = this._getParentDeclarationType(node);
308
+ if (parent_type === 'const') {
309
+ return 'property-constant';
310
+ }
311
+ }
312
+ }
313
+
314
+ // 类属性常量 - 只有当属性名符合常量命名规范时才识别为常量
315
+ if (node.type === 'PropertyDefinition' && this._isLiteralValue(node.value)) {
316
+ if (node.static) {
317
+ return 'static-variable';
318
+ }
319
+ // 类中的静态属性应该被识别为静态属性-变量,而不是静态属性-常量
320
+ return 'variable';
321
+ }
322
+
323
+ return null;
324
+ }
325
+
326
+ /**
327
+ * 检测参数类型
328
+ * @param {object} node AST节点
329
+ * @returns {string} 类型名称
330
+ */
331
+ detectParamType(node) {
332
+ // 只在真正的函数参数节点上返回参数类型
333
+ if (node.type === 'Identifier' && node.parent &&
334
+ (node.parent.type === 'FunctionDeclaration' ||
335
+ node.parent.type === 'FunctionExpression' ||
336
+ node.parent.type === 'ArrowFunctionExpression') &&
337
+ node.parent.params && node.parent.params.includes(node)) {
338
+
339
+ // 增强版参数类型检测:根据使用上下文推断参数类型
340
+ var param_type = this._inferParamTypeFromContext(node);
341
+
342
+ // 如果使用上下文无法推断,尝试其他方法
343
+ if (!param_type) {
344
+ // 基于命名约定推断(优先级高于命名风格)
345
+ param_type = this._inferParamTypeByNamingConvention(node.name);
346
+
347
+ // 如果命名约定也无法推断,基于命名风格推断
348
+ if (!param_type) {
349
+ param_type = this._inferParamTypeByStyle(node.name);
350
+ }
351
+ }
352
+
353
+ // 对于箭头函数参数,优先推断为变量类型
354
+ if (node.parent && node.parent.type === 'ArrowFunctionExpression') {
355
+ param_type = 'variable';
356
+ }
357
+ return param_type ? 'param-' + param_type : 'param';
358
+ }
359
+
360
+ // 不是参数节点,返回null让其他检测器处理
361
+ return null;
362
+ }
363
+
364
+ /**
365
+ * 根据上下文推断参数类型
366
+ * @param {object} param_node 参数节点
367
+ * @returns {string} 参数类型(function/class/variable)
368
+ */
369
+ _inferParamTypeFromContext(param_node) {
370
+ var function_node = param_node.parent;
371
+ var param_name = param_node.name;
372
+
373
+ // 如果没有函数体,无法进行使用上下文推断
374
+ if (!function_node.body) {
375
+ return null; // 无法推断,返回null让上层逻辑处理
376
+ }
377
+
378
+ // 收集参数在函数体中的所有使用方式
379
+ var usage_types = [];
380
+
381
+ this._traverseFunctionBody(function_node.body, function (node) {
382
+ // 检查调用表达式:param_name() → 函数类型
383
+ if (node.type === 'CallExpression' &&
384
+ node.callee.type === 'Identifier' &&
385
+ node.callee.name === param_name) {
386
+ usage_types.push('function_call');
387
+ }
388
+
389
+ // 检查new表达式:new param_name() → 类类型
390
+ else if (node.type === 'NewExpression' &&
391
+ node.callee.type === 'Identifier' &&
392
+ node.callee.name === param_name) {
393
+ usage_types.push('class_instantiation');
394
+ }
395
+
396
+ // 检查成员表达式:param_name.property → 对象类型
397
+ else if (node.type === 'MemberExpression' &&
398
+ node.object.type === 'Identifier' &&
399
+ node.object.name === param_name) {
400
+ usage_types.push('property_access');
401
+ }
402
+
403
+ // 检查方法调用:param_name.method() → 对象类型(类实例)
404
+ else if (node.type === 'CallExpression' &&
405
+ node.callee.type === 'MemberExpression' &&
406
+ node.callee.object.type === 'Identifier' &&
407
+ node.callee.object.name === param_name) {
408
+ usage_types.push('method_call');
409
+ }
410
+
411
+ // 检查赋值表达式:var x = param_name → 变量类型
412
+ else if (node.type === 'VariableDeclarator' &&
413
+ node.init && node.init.type === 'Identifier' &&
414
+ node.init.name === param_name) {
415
+ usage_types.push('variable_assignment');
416
+ }
417
+
418
+ // 检查作为参数传递:func(param_name) → 根据接收函数的上下文推断
419
+ else if (node.type === 'CallExpression') {
420
+ for (var i = 0; i < node.arguments.length; i++) {
421
+ var arg = node.arguments[i];
422
+ if (arg.type === 'Identifier' && arg.name === param_name) {
423
+ usage_types.push('function_argument');
424
+ }
425
+ }
426
+ }
427
+
428
+ // 检查直接使用:return name, var x = name → 变量类型
429
+ else if (node.type === 'Identifier' && node.name === param_name) {
430
+ // 排除已经在其他检测中处理的情况
431
+ var parent = node.parent;
432
+ if (!parent ||
433
+ (parent.type !== 'CallExpression' &&
434
+ parent.type !== 'NewExpression' &&
435
+ parent.type !== 'MemberExpression' &&
436
+ !(parent.type === 'VariableDeclarator' && parent.init === node))) {
437
+ usage_types.push('direct_usage');
438
+ }
439
+ }
440
+
441
+ return false; // 继续遍历,收集所有使用方式
442
+ });
443
+
444
+ // 根据使用方式推断参数类型
445
+ return this._inferTypeFromUsage(usage_types, param_name);
446
+ }
447
+
448
+ /**
449
+ * 根据使用方式推断参数类型
450
+ * @param {Array} usage_types 使用方式数组
451
+ * @param {string} param_name 参数名
452
+ * @returns {string} 推断的参数类型
453
+ */
454
+ _inferTypeFromUsage(usage_types, param_name) {
455
+ // 如果没有使用方式,无法推断
456
+ if (usage_types.length === 0) {
457
+ return null;
458
+ }
459
+
460
+ // 优先级:函数调用 > 类实例化 > 方法调用 > 属性访问 > 函数参数 > 变量赋值 > 直接使用
461
+ var priority_map = {
462
+ 'function_call': 7, // 最高优先级:明确是函数
463
+ 'class_instantiation': 6, // 高优先级:明确是类
464
+ 'method_call': 5, // 中高优先级:方法调用(类实例)
465
+ 'property_access': 4, // 中优先级:对象属性访问
466
+ 'function_argument': 3, // 低优先级:作为函数参数传递(根据接收函数推断)
467
+ 'variable_assignment': 2, // 较低优先级:变量赋值
468
+ 'direct_usage': 1 // 最低优先级:直接使用
469
+ };
470
+
471
+ // 找到最高优先级的用法
472
+ var highest_priority = 0;
473
+ var inferred_type = null;
474
+
475
+ for (var i = 0; i < usage_types.length; i++) {
476
+ var usage = usage_types[i];
477
+ var priority = priority_map[usage] || 0;
478
+
479
+ if (priority > highest_priority) {
480
+ highest_priority = priority;
481
+
482
+ // 根据使用方式映射到参数类型
483
+ switch (usage) {
484
+ case 'function_call':
485
+ inferred_type = 'function';
486
+ break;
487
+ case 'class_instantiation':
488
+ inferred_type = 'class';
489
+ break;
490
+ case 'method_call':
491
+ inferred_type = 'class-instance';
492
+ break;
493
+ case 'property_access':
494
+ inferred_type = 'object';
495
+ break;
496
+ case 'function_argument':
497
+ // 作为函数参数传递,需要根据接收函数的上下文推断
498
+ inferred_type = 'variable'; // 默认变量类型,让其他使用方式覆盖
499
+ break;
500
+ case 'variable_assignment':
501
+ case 'direct_usage':
502
+ inferred_type = 'variable';
503
+ break;
504
+ }
505
+ }
506
+ }
507
+
508
+ return inferred_type;
509
+ }
510
+
511
+ /**
512
+ * 基于命名约定推断参数类型
513
+ * @param {string} param_name 参数名
514
+ * @returns {string} 推断的参数类型
515
+ */
516
+ _inferParamTypeByNamingConvention(param_name) {
517
+ var lower_name = param_name.toLowerCase();
518
+
519
+ // 函数类型命名约定
520
+ if (lower_name.startsWith('on') ||
521
+ lower_name.startsWith('handle') ||
522
+ lower_name.endsWith('func') ||
523
+ lower_name.endsWith('callback') ||
524
+ lower_name.endsWith('handler')) {
525
+ return 'function';
526
+ }
527
+
528
+ // 类类型命名约定
529
+ if (lower_name.endsWith('manager') ||
530
+ lower_name.endsWith('service') ||
531
+ lower_name.endsWith('controller') ||
532
+ lower_name.endsWith('provider') ||
533
+ lower_name.endsWith('factory') ||
534
+ lower_name.endsWith('class') ||
535
+ lower_name.endsWith('model') ||
536
+ lower_name.endsWith('view') ||
537
+ lower_name.endsWith('component')) {
538
+ return 'class';
539
+ }
540
+
541
+ // 对象类型命名约定
542
+ if (lower_name.endsWith('obj') ||
543
+ lower_name.endsWith('object') ||
544
+ lower_name.endsWith('data') ||
545
+ lower_name.endsWith('info') ||
546
+ lower_name.endsWith('config') ||
547
+ lower_name.endsWith('options')) {
548
+ return 'variable';
549
+ }
550
+
551
+ return null;
552
+ }
553
+
554
+ /**
555
+ * 基于命名风格推断参数类型
556
+ * @param {string} param_name 参数名
557
+ * @returns {string} 推断的参数类型
558
+ */
559
+ _inferParamTypeByStyle(param_name) {
560
+ var config = this.config || new (require('./config').Config)();
561
+
562
+ // 检查是否符合PascalCase(类类型)
563
+ if (config.getRegex('PascalCase').test(param_name)) {
564
+ return 'class';
565
+ }
566
+
567
+ // 检查是否符合snake_case(变量/对象类型)
568
+ if (config.getRegex('snake_case').test(param_name)) {
569
+ return 'variable';
570
+ }
571
+
572
+ // 检查是否符合camelCase(函数类型)
573
+ if (config.getRegex('camelCase').test(param_name)) {
574
+ return 'function';
575
+ }
576
+
577
+ // 默认变量类型
578
+ return 'variable';
579
+ }
580
+
581
+ /**
582
+ * 语义推断参数类型
583
+ * @param {object} param_node 参数节点
584
+ * @returns {string} 推断的参数类型
585
+ */
586
+ _inferParamTypeSemantically(param_node) {
587
+ var function_node = param_node.parent;
588
+ var param_name = param_node.name;
589
+
590
+ // 收集函数体中所有标识符
591
+ var identifiers = [];
592
+ this._traverseFunctionBody(function_node.body, function (node) {
593
+ if (node.type === 'Identifier') {
594
+ identifiers.push({
595
+ name: node.name,
596
+ type: this._getIdentifierUsageType(node),
597
+ node: node
598
+ });
599
+ }
600
+ return false;
601
+ }.bind(this));
602
+
603
+ // 分析标识符与参数的语义关联
604
+ for (var i = 0; i < identifiers.length; i++) {
605
+ var identifier = identifiers[i];
606
+
607
+ // 检查标识符是否与参数名称有语义关联
608
+ if (this._hasSemanticRelation(param_name, identifier.name)) {
609
+ // 根据标识符的使用类型推断参数类型
610
+ switch (identifier.type) {
611
+ case 'function_call':
612
+ return 'function';
613
+ case 'class_instantiation':
614
+ return 'class';
615
+ case 'property_access':
616
+ return 'class-instance';
617
+ case 'variable_declaration':
618
+ return 'variable';
619
+ }
620
+ }
621
+ }
622
+
623
+ return null;
624
+ }
625
+
626
+ /**
627
+ * 检查两个标识符是否有语义关联
628
+ * @param {string} param_name 参数名
629
+ * @param {string} identifier_name 标识符名
630
+ * @returns {boolean} 是否有语义关联
631
+ */
632
+ _hasSemanticRelation(param_name, identifier_name) {
633
+ // 简单的语义关联规则
634
+
635
+ // 1. 名称相似性检查(忽略大小写和下划线)
636
+ var normalized_param = param_name.toLowerCase().replace(/[_-]/g, '');
637
+ var normalized_ident = identifier_name.toLowerCase().replace(/[_-]/g, '');
638
+
639
+ if (normalized_param === normalized_ident) {
640
+ return true;
641
+ }
642
+
643
+ // 2. 包含关系检查
644
+ if (normalized_ident.includes(normalized_param) ||
645
+ normalized_param.includes(normalized_ident)) {
646
+ return true;
647
+ }
648
+
649
+ // 3. 词根相似性检查
650
+ var param_root = this._getWordRoot(normalized_param);
651
+ var ident_root = this._getWordRoot(normalized_ident);
652
+
653
+ if (param_root && ident_root && param_root === ident_root) {
654
+ return true;
655
+ }
656
+
657
+ return false;
658
+ }
659
+
660
+ /**
661
+ * 获取标识符的使用类型
662
+ * @param {object} identifier_node 标识符节点
663
+ * @returns {string} 使用类型
664
+ */
665
+ _getIdentifierUsageType(identifier_node) {
666
+ var parent = identifier_node.parent;
667
+
668
+ if (parent.type === 'CallExpression' && parent.callee === identifier_node) {
669
+ return 'function_call';
670
+ }
671
+
672
+ if (parent.type === 'NewExpression' && parent.callee === identifier_node) {
673
+ return 'class_instantiation';
674
+ }
675
+
676
+ if (parent.type === 'MemberExpression' && parent.object === identifier_node) {
677
+ return 'property_access';
678
+ }
679
+
680
+ if (parent.type === 'VariableDeclarator' && parent.id === identifier_node) {
681
+ return 'variable_declaration';
682
+ }
683
+
684
+ return 'other';
685
+ }
686
+
687
+ /**
688
+ * 获取单词的词根(简化实现)
689
+ * @param {string} word 单词
690
+ * @returns {string} 词根
691
+ */
692
+ _getWordRoot(word) {
693
+ // 简单的词根提取规则
694
+ var common_suffixes = ['s', 'es', 'ed', 'ing', 'er', 'or', 'ment', 'tion', 'ity'];
695
+
696
+ for (var i = 0; i < common_suffixes.length; i++) {
697
+ var suffix = common_suffixes[i];
698
+ if (word.endsWith(suffix) && word.length > suffix.length) {
699
+ return word.slice(0, -suffix.length);
700
+ }
701
+ }
702
+
703
+ return word;
704
+ }
705
+
706
+ /**
707
+ * 遍历函数体
708
+ * @param {object} body_node 函数体节点
709
+ * @param {function} visitor 访问器函数
710
+ */
711
+ _traverseFunctionBody(body_node, visitor) {
712
+ if (!body_node || !visitor) return;
713
+
714
+ // 简单的AST遍历实现
715
+ var nodes_to_visit = [body_node];
716
+
717
+ while (nodes_to_visit.length > 0) {
718
+ var current_node = nodes_to_visit.pop();
719
+
720
+ // 调用访问器,如果返回true则停止遍历
721
+ if (visitor(current_node)) {
722
+ return;
723
+ }
724
+
725
+ // 添加子节点到遍历队列
726
+ if (current_node.body) {
727
+ if (Array.isArray(current_node.body)) {
728
+ nodes_to_visit.push(...current_node.body.reverse());
729
+ } else {
730
+ nodes_to_visit.push(current_node.body);
731
+ }
732
+ }
733
+
734
+ if (current_node.expression) {
735
+ nodes_to_visit.push(current_node.expression);
736
+ }
737
+
738
+ if (current_node.consequent) {
739
+ nodes_to_visit.push(current_node.consequent);
740
+ }
741
+
742
+ if (current_node.alternate) {
743
+ nodes_to_visit.push(current_node.alternate);
744
+ }
745
+
746
+ if (current_node.argument) {
747
+ nodes_to_visit.push(current_node.argument);
748
+ }
749
+
750
+ if (current_node.arguments && Array.isArray(current_node.arguments)) {
751
+ nodes_to_visit.push(...current_node.arguments.reverse());
752
+ }
753
+
754
+ if (current_node.elements && Array.isArray(current_node.elements)) {
755
+ nodes_to_visit.push(...current_node.elements.reverse());
756
+ }
757
+
758
+ if (current_node.properties && Array.isArray(current_node.properties)) {
759
+ nodes_to_visit.push(...current_node.properties.reverse());
760
+ }
761
+ }
762
+ }
763
+
764
+ /**
765
+ * 检测命名类型
766
+ * @param {object} node AST节点
767
+ * @param {string} name 名称
768
+ * @returns {object} 检测结果
769
+ */
770
+ detect(node, name) {
771
+ var type = null;
772
+
773
+ // 按优先级检测类型 - 变量检测应该在常量检测之前
774
+ var detectors = [
775
+ this.detectClassType.bind(this),
776
+ this.detectClassInstanceType.bind(this),
777
+ this.detectFunctionType.bind(this), // 函数检测应该在变量检测之前
778
+ this.detectConstantType.bind(this), // 常量检测优先级提高
779
+ this.detectVariableType.bind(this), // 变量检测优先级降低
780
+ this.detectParamType.bind(this)
781
+ ];
782
+
783
+ for (var i = 0; i < detectors.length; i++) {
784
+ type = detectors[i](node);
785
+ if (type) {
786
+ break;
787
+ }
788
+ }
789
+
790
+ // 如果检测到类实例、函数等特殊类型,跳过声明问题检测
791
+ if (type && (type.includes('class-instance') || type.includes('function'))) {
792
+ // 跳过声明问题检测,直接进行命名规范验证
793
+ } else {
794
+ // 检测声明方式问题(优先级较低)
795
+ var original_type = this.detectDeclarationIssue(node);
796
+ if (original_type) {
797
+ // 如果是声明方式问题,直接返回相应的错误,不进行命名规范验证
798
+ var message = this.tip.getDeclarationIssueMessage(original_type, name);
799
+ return {
800
+ name,
801
+ node,
802
+ message,
803
+ error_type: 'declaration',
804
+ severity: 'error',
805
+ fix_suggestion: null,
806
+ original_type
807
+ };
808
+ }
809
+ }
810
+
811
+ if (!type) {
812
+ type = 'variable'; // 默认类型
813
+ }
814
+
815
+ var error = this.validator.validate(name, type);
816
+ if (!error) {
817
+ return null;
818
+ }
819
+
820
+ var fix_suggestion = this.corrector.getSuggestion(error);
821
+ var message = this.tip.getFullMessage(error, fix_suggestion);
822
+
823
+ return {
824
+ name,
825
+ node,
826
+ message,
827
+ error_type: error.type,
828
+ severity: error.severity,
829
+ fix_suggestion: fix_suggestion,
830
+ original_type: type
831
+ };
832
+ }
833
+
834
+ /**
835
+ * 检测命名类型(仅返回类型,不验证)
836
+ * @param {object} node AST节点
837
+ * @returns {string} 检测到的类型
838
+ */
839
+ detectTypeOnly(node) {
840
+ var type = null;
841
+
842
+ // 按优先级检测类型 - 变量检测应该在常量检测之前
843
+ var detectors = [
844
+ this.detectClassType.bind(this),
845
+ this.detectClassInstanceType.bind(this),
846
+ this.detectFunctionType.bind(this), // 函数检测应该在变量检测之前
847
+ this.detectConstantType.bind(this), // 常量检测优先级提高
848
+ this.detectVariableType.bind(this), // 变量检测优先级降低
849
+ this.detectParamType.bind(this)
850
+ ];
851
+
852
+ for (var i = 0; i < detectors.length; i++) {
853
+ type = detectors[i](node);
854
+ if (type) {
855
+ break;
856
+ }
857
+ }
858
+
859
+ // 特殊处理:属性简写应该识别为变量,而不是常量
860
+ if (node.type === 'Property' && node.shorthand && node.value && node.value.type === 'Identifier') {
861
+ // 如果是属性简写,强制识别为变量
862
+ type = 'property-variable';
863
+ }
864
+
865
+ if (!type) {
866
+ type = 'variable'; // 默认类型
867
+ }
868
+
869
+ return type;
870
+ }
871
+
872
+ /**
873
+ * 判断是否为字面量值
874
+ * @param {object} node AST节点
875
+ * @returns {boolean} 是否为字面量
876
+ */
877
+ _isLiteralValue(node) {
878
+ if (!node) {
879
+ return false;
880
+ }
881
+
882
+ switch (node.type) {
883
+ case 'Literal':
884
+ return !node.regex; // 排除正则表达式
885
+ case 'TemplateLiteral':
886
+ return true;
887
+ case 'Identifier':
888
+ var literal_identifiers = ['undefined', 'null', 'Infinity', 'NaN', 'true', 'false'];
889
+ return literal_identifiers.includes(node.name);
890
+ case 'ArrayExpression':
891
+ if (node.elements && node.elements.length > 0) {
892
+ for (var i = 0; i < node.elements.length; i++) {
893
+ if (!this._isLiteralValue(node.elements[i])) {
894
+ return false;
895
+ }
896
+ }
897
+ }
898
+ return true;
899
+ case 'ObjectExpression':
900
+ if (node.properties && node.properties.length > 0) {
901
+ for (var i = 0; i < node.properties.length; i++) {
902
+ var property = node.properties[i];
903
+ if (property.value && !this._isLiteralValue(property.value)) {
904
+ return false;
905
+ }
906
+ }
907
+ }
908
+ return true;
909
+ default:
910
+ return false;
911
+ }
912
+ }
913
+
914
+ /**
915
+ * 判断字符串是否符合PascalCase命名规范
916
+ * @param {string} name 名称
917
+ * @returns {boolean} 是否符合PascalCase
918
+ */
919
+ _isPascalCase(name) {
920
+ if (!name || name.length === 0) {
921
+ return false;
922
+ }
923
+
924
+ // PascalCase要求首字母大写,后续字母可以大小写混合
925
+ // 但不能包含下划线或连字符
926
+ if (name.includes('_') || name.includes('-')) {
927
+ return false;
928
+ }
929
+
930
+ // 首字母必须是大写字母
931
+ if (!/^[A-Z]/.test(name)) {
932
+ return false;
933
+ }
934
+
935
+ // 整体必须符合标识符规范
936
+ if (!/^[A-Za-z][A-Za-z0-9]*$/.test(name)) {
937
+ return false;
938
+ }
939
+
940
+ return true;
941
+ }
942
+
943
+ /**
944
+ * 检查属性名是否在作用域内有对应的类实例变量声明
945
+ * @param {string} name 属性名
946
+ * @param {object} node AST节点
947
+ * @returns {boolean} 是否是类实例引用
948
+ */
949
+ _isClassInstanceReference(name, node) {
950
+ if (!name || !node) {
951
+ return false;
952
+ }
953
+
954
+ // 遍历AST查找变量声明
955
+ var current_node = node;
956
+ while (current_node.parent) {
957
+ current_node = current_node.parent;
958
+
959
+ // 查找变量声明
960
+ if (current_node.type === 'VariableDeclaration') {
961
+ for (var i = 0; i < current_node.declarations.length; i++) {
962
+ var decl = current_node.declarations[i];
963
+ if (decl.id && decl.id.type === 'Identifier' && decl.id.name === name) {
964
+ // 检查是否为类实例声明(new表达式)
965
+ if (decl.init && decl.init.type === 'NewExpression') {
966
+ return true;
967
+ }
968
+ }
969
+ }
970
+ }
971
+
972
+ // 查找赋值表达式
973
+ if (current_node.type === 'AssignmentExpression' &&
974
+ current_node.left && current_node.left.type === 'Identifier' &&
975
+ current_node.left.name === name) {
976
+ // 检查是否为类实例赋值(new表达式)
977
+ if (current_node.right && current_node.right.type === 'NewExpression') {
978
+ return true;
979
+ }
980
+ }
981
+
982
+ // 如果到达程序根节点,停止搜索
983
+ if (current_node.type === 'Program') {
984
+ break;
985
+ }
986
+ }
987
+
988
+ return false;
989
+ }
990
+
991
+ /**
992
+ * 通用类型溯源:对于导出语句中的属性,溯源其引用的类型
993
+ * @param {object} node 属性节点
994
+ * @returns {string} 溯源到的类型,无法溯源则返回null
995
+ */
996
+ _traceReferenceType(node) {
997
+ if (!node || !node.key || node.key.type !== 'Identifier') {
998
+ return null;
999
+ }
1000
+
1001
+ // 对于简写属性 { AdminManager },溯源属性名对应的类型
1002
+ if (node.shorthand) {
1003
+ return this._traceIdentifierType(node.key.name, node);
1004
+ }
1005
+
1006
+ // 对于完整属性 { Admin_DD: Admin },溯源属性值对应的类型
1007
+ if (!node.shorthand && node.value && node.value.type === 'Identifier') {
1008
+ return this._traceIdentifierType(node.value.name, node);
1009
+ }
1010
+
1011
+ // 其他情况无法溯源
1012
+ return null;
1013
+ }
1014
+
1015
+ /**
1016
+ * 溯源标识符的类型
1017
+ * @param {string} name 标识符名
1018
+ * @param {object} node AST节点
1019
+ * @returns {string} 溯源到的类型,无法溯源则返回null
1020
+ */
1021
+ _traceIdentifierType(name, node) {
1022
+ if (!name || !node) {
1023
+ return null;
1024
+ }
1025
+
1026
+ // 获取Program节点(AST根节点)
1027
+ var program_node = this._getProgramNode(node);
1028
+ if (!program_node || !program_node.body) {
1029
+ return null;
1030
+ }
1031
+
1032
+ // 遍历同级节点查找声明
1033
+ for (var i = 0; i < program_node.body.length; i++) {
1034
+ var sibling_node = program_node.body[i];
1035
+
1036
+ // 查找类声明
1037
+ if (sibling_node.type === 'ClassDeclaration') {
1038
+ if (sibling_node.id && sibling_node.id.type === 'Identifier' && sibling_node.id.name === name) {
1039
+ return 'class';
1040
+ }
1041
+ }
1042
+
1043
+ // 查找函数声明
1044
+ if (sibling_node.type === 'FunctionDeclaration') {
1045
+ if (sibling_node.id && sibling_node.id.type === 'Identifier' && sibling_node.id.name === name) {
1046
+ return 'function';
1047
+ }
1048
+ }
1049
+
1050
+ // 查找变量声明
1051
+ if (sibling_node.type === 'VariableDeclaration') {
1052
+ for (var j = 0; j < sibling_node.declarations.length; j++) {
1053
+ var decl = sibling_node.declarations[j];
1054
+ if (decl.id && decl.id.type === 'Identifier' && decl.id.name === name) {
1055
+ // 检查变量声明的类型
1056
+ if (decl.init) {
1057
+ // 类表达式
1058
+ if (decl.init.type === 'ClassExpression') {
1059
+ return 'class';
1060
+ }
1061
+
1062
+ // 函数表达式
1063
+ if (decl.init.type === 'FunctionExpression' || decl.init.type === 'ArrowFunctionExpression') {
1064
+ return 'function';
1065
+ }
1066
+
1067
+ // new 表达式(类实例)
1068
+ if (decl.init.type === 'NewExpression') {
1069
+ return 'class-instance';
1070
+ }
1071
+
1072
+ // 常量(只有const声明且为基础字面量)
1073
+ if (sibling_node.kind === 'const' && this._isBasicLiteralValue(decl.init)) {
1074
+ return 'constant';
1075
+ }
1076
+
1077
+ // 普通变量
1078
+ return 'variable';
1079
+ }
1080
+
1081
+ // 没有初始值的变量声明,默认为变量
1082
+ return 'variable';
1083
+ }
1084
+ }
1085
+ }
1086
+ }
1087
+
1088
+ // 无法溯源到具体类型
1089
+ return null;
1090
+ }
1091
+
1092
+ /**
1093
+ * 检查属性名是否在作用域内有对应的类声明
1094
+ * @param {string} name 属性名
1095
+ * @param {object} node AST节点
1096
+ * @returns {boolean} 是否是类引用
1097
+ */
1098
+ _isClassReference(name, node) {
1099
+ if (!name || !node) {
1100
+ return false;
1101
+ }
1102
+
1103
+ console.log(' [DEBUG] _isClassReference called:', name);
1104
+
1105
+ // 在ESLint环境中,AST节点有parent属性,可以向上遍历
1106
+ // 获取Program节点(AST根节点)
1107
+ var program_node = this._getProgramNode(node);
1108
+ console.log(' [DEBUG] Program node:', program_node ? program_node.type : 'null');
1109
+
1110
+ if (!program_node || !program_node.body) {
1111
+ console.log(' [DEBUG] No program node or body');
1112
+ return false;
1113
+ }
1114
+
1115
+ console.log(' [DEBUG] Program body length:', program_node.body.length);
1116
+
1117
+ // 遍历同级节点查找类声明
1118
+ for (var i = 0; i < program_node.body.length; i++) {
1119
+ var sibling_node = program_node.body[i];
1120
+ console.log(' [DEBUG] Sibling node', i, ':', sibling_node.type);
1121
+
1122
+ // 查找类声明
1123
+ if (sibling_node.type === 'ClassDeclaration') {
1124
+ console.log(' [DEBUG] Found ClassDeclaration:', sibling_node.id ? sibling_node.id.name : 'null');
1125
+ if (sibling_node.id && sibling_node.id.type === 'Identifier' && sibling_node.id.name === name) {
1126
+ console.log(' [DEBUG] Class reference found!');
1127
+ return true;
1128
+ }
1129
+ }
1130
+
1131
+ // 查找变量声明中的类表达式
1132
+ if (sibling_node.type === 'VariableDeclaration') {
1133
+ for (var j = 0; j < sibling_node.declarations.length; j++) {
1134
+ var decl = sibling_node.declarations[j];
1135
+ if (decl.id && decl.id.type === 'Identifier' && decl.id.name === name) {
1136
+ // 检查是否为类表达式
1137
+ if (decl.init && decl.init.type === 'ClassExpression') {
1138
+ return true;
1139
+ }
1140
+ }
1141
+ }
1142
+ }
1143
+ }
1144
+
1145
+ console.log(' [DEBUG] No class reference found');
1146
+ return false;
1147
+ }
1148
+
1149
+ /**
1150
+ * 获取Program节点(AST根节点)
1151
+ * @param {object} node AST节点
1152
+ * @returns {object} Program节点
1153
+ */
1154
+ _getProgramNode(node) {
1155
+ var current_node = node;
1156
+
1157
+ // 在ESLint环境中,AST节点有parent属性,可以向上遍历
1158
+ // 向上遍历直到找到Program节点
1159
+ while (current_node && current_node.parent) {
1160
+ current_node = current_node.parent;
1161
+
1162
+ // 如果找到Program节点,返回它
1163
+ if (current_node.type === 'Program') {
1164
+ return current_node;
1165
+ }
1166
+ }
1167
+
1168
+ // 如果没有找到Program节点,返回null
1169
+ return null;
1170
+ }
1171
+
1172
+ /**
1173
+ * 获取父级声明类型
1174
+ * @param {object} node AST节点
1175
+ * @returns {string} 声明类型
1176
+ */
1177
+ _getParentDeclarationType(node) {
1178
+ var current_node = node;
1179
+
1180
+ while (current_node.parent) {
1181
+ current_node = current_node.parent;
1182
+
1183
+ if (current_node.type === 'VariableDeclarator' && current_node.parent && current_node.parent.kind) {
1184
+ return current_node.parent.kind;
1185
+ }
1186
+
1187
+ if (current_node.type === 'AssignmentExpression') {
1188
+ return 'variable';
1189
+ }
1190
+ }
1191
+
1192
+ return 'unknown';
1193
+ }
1194
+
1195
+ /**
1196
+ * 获取父级对象节点
1197
+ * @param {object} node AST节点
1198
+ * @returns {object|null} 父级对象节点
1199
+ */
1200
+ _getParentObject(node) {
1201
+ var current_node = node;
1202
+
1203
+ while (current_node.parent) {
1204
+ current_node = current_node.parent;
1205
+
1206
+ if (current_node.type === 'ObjectExpression') {
1207
+ return current_node;
1208
+ }
1209
+
1210
+ if (current_node.type === 'VariableDeclarator' || current_node.type === 'AssignmentExpression') {
1211
+ break;
1212
+ }
1213
+ }
1214
+
1215
+ return null;
1216
+ }
1217
+
1218
+ /**
1219
+ * 判断是否为基础字面量值(排除正则表达式)
1220
+ * @param {object} node AST节点
1221
+ * @returns {boolean} 是否为基础字面量
1222
+ */
1223
+ _isBasicLiteralValue(node) {
1224
+ if (!node) {
1225
+ return false;
1226
+ }
1227
+
1228
+ switch (node.type) {
1229
+ case 'Literal':
1230
+ // 排除正则表达式
1231
+ return !node.regex;
1232
+ case 'TemplateLiteral':
1233
+ return true;
1234
+ case 'ArrayExpression':
1235
+ // 数组必须所有元素都是基础字面量
1236
+ if (node.elements && node.elements.length > 0) {
1237
+ for (var i = 0; i < node.elements.length; i++) {
1238
+ if (!this._isBasicLiteralValue(node.elements[i])) {
1239
+ return false;
1240
+ }
1241
+ }
1242
+ }
1243
+ return true;
1244
+ case 'ObjectExpression':
1245
+ // 对象必须所有属性值都是基础字面量
1246
+ if (node.properties && node.properties.length > 0) {
1247
+ for (var i = 0; i < node.properties.length; i++) {
1248
+ var property = node.properties[i];
1249
+ if (property.value && !this._isBasicLiteralValue(property.value)) {
1250
+ return false;
1251
+ }
1252
+ }
1253
+ }
1254
+ return true;
1255
+ case 'Identifier':
1256
+ var basic_literal_identifiers = ['undefined', 'null', 'Infinity', 'NaN', 'true', 'false'];
1257
+ return basic_literal_identifiers.includes(node.name);
1258
+ default:
1259
+ return false;
1260
+ }
1261
+ }
1262
+
1263
+ /**
1264
+ * 检查对象的所有属性是否都是字面量
1265
+ * @param {object} object_node 对象节点
1266
+ * @returns {boolean} 是否所有属性都是字面量
1267
+ */
1268
+ _isObjectAllLiteral(object_node) {
1269
+ if (object_node.type !== 'ObjectExpression' || !object_node.properties) {
1270
+ return false;
1271
+ }
1272
+
1273
+ for (var i = 0; i < object_node.properties.length; i++) {
1274
+ var property = object_node.properties[i];
1275
+
1276
+ // 跳过解构赋值
1277
+ if (property.type !== 'Property') {
1278
+ continue;
1279
+ }
1280
+
1281
+ // 检查属性值是否为字面量
1282
+ if (!this._isLiteralValue(property.value)) {
1283
+ return false;
1284
+ }
1285
+ }
1286
+
1287
+ return true;
1288
+ }
1289
+ }
1290
+
1239
1291
  module.exports = { Detector };