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