mm_eslint 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config.js +78 -44
- package/detector.js +2602 -367
- package/index.js +984 -78
- package/package.json +1 -1
- package/README_EN.md +0 -410
package/detector.js
CHANGED
|
@@ -9,19 +9,19 @@ class Detector {
|
|
|
9
9
|
constructor(config) {
|
|
10
10
|
// 直接将传入的配置对象赋值,确保原型方法不被丢失
|
|
11
11
|
this.config = config;
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
// 添加命名类型的中文描述
|
|
14
14
|
this.config.name_type_map = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
"class-name": "类名",
|
|
16
|
+
"function-name": "函数名",
|
|
17
|
+
"method-name": "方法名",
|
|
18
|
+
"variable-name": "变量名",
|
|
19
|
+
"param-name": "参数名",
|
|
20
|
+
"constant-name": "常量名",
|
|
21
|
+
"property-class-name": "属性类名",
|
|
22
|
+
"property-instance-class-name": "属性实例类名",
|
|
23
|
+
"property-method-name": "属性方法名",
|
|
24
|
+
"property-value-name": "属性值名",
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -34,64 +34,119 @@ class Detector {
|
|
|
34
34
|
*/
|
|
35
35
|
Detector.prototype._checkClassName = function (class_name, node) {
|
|
36
36
|
try {
|
|
37
|
-
var rule = this.config.getRule(
|
|
37
|
+
var rule = this.config.getRule("class-name");
|
|
38
38
|
if (!rule) {
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// 检查是否为忽略词
|
|
43
|
-
if (this._isIgnoredWord(class_name,
|
|
43
|
+
if (this._isIgnoredWord(class_name, "class-name")) {
|
|
44
44
|
return null;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// 检查命名风格
|
|
48
|
-
var style_err = this._validate_naming_style(
|
|
48
|
+
var style_err = this._validate_naming_style(
|
|
49
|
+
class_name,
|
|
50
|
+
rule.styles,
|
|
51
|
+
"class-name",
|
|
52
|
+
);
|
|
49
53
|
if (style_err) {
|
|
54
|
+
// 如果有推荐建议,在风格错误消息后附加推荐
|
|
55
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
56
|
+
class_name,
|
|
57
|
+
"class-name",
|
|
58
|
+
);
|
|
59
|
+
var error_message = style_err;
|
|
60
|
+
if (smart_abbreviation && smart_abbreviation !== class_name) {
|
|
61
|
+
error_message = style_err + ",建议使用: " + smart_abbreviation;
|
|
62
|
+
}
|
|
50
63
|
return {
|
|
51
64
|
node: node,
|
|
52
|
-
message:
|
|
65
|
+
message: error_message,
|
|
66
|
+
rule_type: "class-name",
|
|
53
67
|
};
|
|
54
68
|
}
|
|
55
69
|
|
|
56
70
|
// 检查并推荐更合适的词汇
|
|
57
|
-
var rec_err = this._checkAndRecommend(class_name,
|
|
71
|
+
var rec_err = this._checkAndRecommend(class_name, "class-name");
|
|
58
72
|
if (rec_err) {
|
|
73
|
+
// 生成完整的建议名称
|
|
74
|
+
var recommended_full_name = class_name.replace(
|
|
75
|
+
new RegExp(rec_err.original_word, "i"),
|
|
76
|
+
rec_err.recommended_word,
|
|
77
|
+
);
|
|
78
|
+
|
|
59
79
|
return {
|
|
60
80
|
node: node,
|
|
61
|
-
message:
|
|
81
|
+
message: "类名'" + class_name + "',建议使用: " + recommended_full_name,
|
|
82
|
+
rule_type: "class-name",
|
|
62
83
|
};
|
|
63
84
|
}
|
|
64
85
|
|
|
65
86
|
// 检查长度
|
|
66
|
-
var len_err = this._checkNameLength(
|
|
87
|
+
var len_err = this._checkNameLength(
|
|
88
|
+
class_name,
|
|
89
|
+
rule.min,
|
|
90
|
+
rule.max,
|
|
91
|
+
"class-name",
|
|
92
|
+
);
|
|
67
93
|
if (len_err) {
|
|
94
|
+
// 使用智能缩写生成推荐名称
|
|
95
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
96
|
+
class_name,
|
|
97
|
+
"class-name",
|
|
98
|
+
);
|
|
99
|
+
var error_message = len_err;
|
|
100
|
+
if (smart_abbreviation && smart_abbreviation !== class_name) {
|
|
101
|
+
error_message = len_err + ",建议使用: " + smart_abbreviation;
|
|
102
|
+
}
|
|
68
103
|
return {
|
|
69
104
|
node: node,
|
|
70
|
-
message:
|
|
105
|
+
message: error_message,
|
|
106
|
+
rule_type: "class-name",
|
|
71
107
|
};
|
|
72
108
|
}
|
|
73
109
|
|
|
74
110
|
// 检查单词长度
|
|
75
|
-
var word_err = this._checkWordLength(
|
|
111
|
+
var word_err = this._checkWordLength(
|
|
112
|
+
class_name,
|
|
113
|
+
rule.single_word_len,
|
|
114
|
+
"class-name",
|
|
115
|
+
);
|
|
76
116
|
if (word_err) {
|
|
117
|
+
// 检查错误消息是否已经包含建议
|
|
118
|
+
var error_message = word_err;
|
|
119
|
+
if (!word_err.includes("建议使用")) {
|
|
120
|
+
// 如果错误消息中不包含建议,则添加建议
|
|
121
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
122
|
+
class_name,
|
|
123
|
+
"class-name",
|
|
124
|
+
);
|
|
125
|
+
if (smart_abbreviation && smart_abbreviation !== class_name) {
|
|
126
|
+
error_message = word_err + ",建议使用: " + smart_abbreviation;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
77
130
|
return {
|
|
78
131
|
node: node,
|
|
79
|
-
message:
|
|
132
|
+
message: error_message,
|
|
133
|
+
rule_type: "class-name",
|
|
80
134
|
};
|
|
81
135
|
}
|
|
82
136
|
|
|
83
137
|
// 检查禁止词汇
|
|
84
|
-
var forbid_err = this._checkForbiddenWords(class_name,
|
|
138
|
+
var forbid_err = this._checkForbiddenWords(class_name, "class-name");
|
|
85
139
|
if (forbid_err) {
|
|
86
140
|
return {
|
|
87
141
|
node: node,
|
|
88
142
|
message: forbid_err,
|
|
143
|
+
rule_type: "class-name",
|
|
89
144
|
};
|
|
90
145
|
}
|
|
91
146
|
|
|
92
147
|
return null;
|
|
93
148
|
} catch (error) {
|
|
94
|
-
console.error(
|
|
149
|
+
console.error("检测类名时出错:", error);
|
|
95
150
|
return null;
|
|
96
151
|
}
|
|
97
152
|
};
|
|
@@ -104,72 +159,138 @@ Detector.prototype._checkClassName = function (class_name, node) {
|
|
|
104
159
|
*/
|
|
105
160
|
Detector.prototype._checkMethodName = function (method_name, node) {
|
|
106
161
|
try {
|
|
107
|
-
var rule = this.config.getRule(
|
|
162
|
+
var rule = this.config.getRule("method-name");
|
|
108
163
|
if (!rule) {
|
|
109
164
|
return null;
|
|
110
165
|
}
|
|
111
166
|
|
|
112
167
|
// 检查是否为忽略词(在所有检测之前)
|
|
113
|
-
if (this._isIgnoredWord(method_name,
|
|
168
|
+
if (this._isIgnoredWord(method_name, "method-name")) {
|
|
114
169
|
return null;
|
|
115
170
|
}
|
|
116
171
|
|
|
117
172
|
// 检查命名风格(支持公开方法和私有方法)
|
|
118
173
|
var style_err = null;
|
|
119
|
-
if (method_name.startsWith(
|
|
174
|
+
if (method_name.startsWith("_")) {
|
|
120
175
|
// 私有方法:检查是否符合私有方法命名规范
|
|
121
|
-
style_err = this._validate_naming_style(
|
|
176
|
+
style_err = this._validate_naming_style(
|
|
177
|
+
method_name,
|
|
178
|
+
["_camelCase"],
|
|
179
|
+
"method-name",
|
|
180
|
+
);
|
|
122
181
|
} else {
|
|
123
182
|
// 公开方法:检查是否符合公开方法命名规范
|
|
124
|
-
style_err = this._validate_naming_style(
|
|
183
|
+
style_err = this._validate_naming_style(
|
|
184
|
+
method_name,
|
|
185
|
+
rule.styles,
|
|
186
|
+
"method-name",
|
|
187
|
+
);
|
|
125
188
|
}
|
|
126
189
|
|
|
127
190
|
if (style_err) {
|
|
191
|
+
// 使用智能缩写生成推荐名称
|
|
192
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
193
|
+
method_name,
|
|
194
|
+
"method-name",
|
|
195
|
+
);
|
|
196
|
+
var error_message = style_err;
|
|
197
|
+
if (smart_abbreviation && smart_abbreviation !== method_name) {
|
|
198
|
+
error_message = style_err + ",建议使用: " + smart_abbreviation;
|
|
199
|
+
}
|
|
128
200
|
return {
|
|
129
201
|
node: node,
|
|
130
|
-
message:
|
|
202
|
+
message: error_message,
|
|
131
203
|
};
|
|
132
204
|
}
|
|
133
205
|
|
|
134
206
|
// 检查长度
|
|
135
|
-
var len_err = this._checkNameLength(
|
|
207
|
+
var len_err = this._checkNameLength(
|
|
208
|
+
method_name,
|
|
209
|
+
rule.min,
|
|
210
|
+
rule.max,
|
|
211
|
+
"method-name",
|
|
212
|
+
);
|
|
136
213
|
if (len_err) {
|
|
214
|
+
// 使用智能缩写生成推荐名称
|
|
215
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
216
|
+
method_name,
|
|
217
|
+
"method-name",
|
|
218
|
+
);
|
|
219
|
+
var error_message = len_err;
|
|
220
|
+
if (smart_abbreviation && smart_abbreviation !== method_name) {
|
|
221
|
+
error_message = len_err + ",建议使用: " + smart_abbreviation;
|
|
222
|
+
}
|
|
137
223
|
return {
|
|
138
224
|
node: node,
|
|
139
|
-
message:
|
|
225
|
+
message: error_message,
|
|
140
226
|
};
|
|
141
227
|
}
|
|
142
228
|
|
|
143
229
|
// 检查单词长度
|
|
144
|
-
var word_err = this._checkWordLength(
|
|
230
|
+
var word_err = this._checkWordLength(
|
|
231
|
+
method_name,
|
|
232
|
+
rule.single_word_len,
|
|
233
|
+
"method-name",
|
|
234
|
+
);
|
|
145
235
|
if (word_err) {
|
|
236
|
+
// 检查错误消息是否已经包含建议
|
|
237
|
+
var error_message = word_err;
|
|
238
|
+
if (!word_err.includes("建议使用")) {
|
|
239
|
+
// 如果错误消息中不包含建议,则添加建议
|
|
240
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
241
|
+
method_name,
|
|
242
|
+
"method-name",
|
|
243
|
+
);
|
|
244
|
+
if (smart_abbreviation && smart_abbreviation !== method_name) {
|
|
245
|
+
error_message = word_err + ",建议使用: " + smart_abbreviation;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
146
248
|
return {
|
|
147
249
|
node: node,
|
|
148
|
-
message:
|
|
250
|
+
message: error_message,
|
|
149
251
|
};
|
|
150
252
|
}
|
|
151
253
|
|
|
152
254
|
// 检查禁止词汇
|
|
153
|
-
var forbid_err = this._checkForbiddenWords(method_name,
|
|
255
|
+
var forbid_err = this._checkForbiddenWords(method_name, "method-name");
|
|
154
256
|
if (forbid_err) {
|
|
257
|
+
// 使用智能缩写生成推荐名称
|
|
258
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
259
|
+
method_name,
|
|
260
|
+
"method-name",
|
|
261
|
+
);
|
|
262
|
+
var error_message = forbid_err;
|
|
263
|
+
if (smart_abbreviation && smart_abbreviation !== method_name) {
|
|
264
|
+
error_message = forbid_err + ",建议使用: " + smart_abbreviation;
|
|
265
|
+
}
|
|
155
266
|
return {
|
|
156
267
|
node: node,
|
|
157
|
-
message:
|
|
268
|
+
message: error_message,
|
|
158
269
|
};
|
|
159
270
|
}
|
|
160
271
|
|
|
161
|
-
//
|
|
162
|
-
var
|
|
163
|
-
|
|
272
|
+
// 如果没有错误但有推荐建议,返回优化建议
|
|
273
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
274
|
+
method_name,
|
|
275
|
+
"method-name",
|
|
276
|
+
);
|
|
277
|
+
if (smart_abbreviation && smart_abbreviation !== method_name) {
|
|
164
278
|
return {
|
|
165
279
|
node: node,
|
|
166
|
-
message:
|
|
280
|
+
message:
|
|
281
|
+
"方法名'" +
|
|
282
|
+
method_name +
|
|
283
|
+
"'不是行业通用名,建议使用: " +
|
|
284
|
+
smart_abbreviation,
|
|
285
|
+
fix: function (fixer) {
|
|
286
|
+
return fixer.replaceText(node, smart_abbreviation);
|
|
287
|
+
},
|
|
167
288
|
};
|
|
168
289
|
}
|
|
169
290
|
|
|
170
291
|
return null;
|
|
171
292
|
} catch (error) {
|
|
172
|
-
console.error(
|
|
293
|
+
console.error("检测方法名时出错:", error);
|
|
173
294
|
return null;
|
|
174
295
|
}
|
|
175
296
|
};
|
|
@@ -182,67 +303,148 @@ Detector.prototype._checkMethodName = function (method_name, node) {
|
|
|
182
303
|
*/
|
|
183
304
|
Detector.prototype._checkFunctionName = function (function_name, node) {
|
|
184
305
|
try {
|
|
185
|
-
var rule = this.config.getRule(
|
|
306
|
+
var rule = this.config.getRule("function-name");
|
|
186
307
|
if (!rule) {
|
|
187
308
|
return null;
|
|
188
309
|
}
|
|
189
310
|
|
|
190
311
|
// 检查是否为忽略词
|
|
191
|
-
if (this._isIgnoredWord(function_name,
|
|
312
|
+
if (this._isIgnoredWord(function_name, "function-name")) {
|
|
192
313
|
return null;
|
|
193
314
|
}
|
|
194
315
|
|
|
316
|
+
// 检查是否为私有函数(不允许私有函数)
|
|
317
|
+
if (function_name.startsWith("_")) {
|
|
318
|
+
// 生成建议:去掉下划线前缀,转换为公有函数
|
|
319
|
+
var public_function_name = function_name.substring(1);
|
|
320
|
+
// 使用智能缩写生成推荐名称
|
|
321
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
322
|
+
public_function_name,
|
|
323
|
+
"function-name",
|
|
324
|
+
);
|
|
325
|
+
var recommended_name =
|
|
326
|
+
smart_abbreviation && smart_abbreviation !== public_function_name
|
|
327
|
+
? smart_abbreviation
|
|
328
|
+
: public_function_name;
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
node: node,
|
|
332
|
+
message:
|
|
333
|
+
"函数名'" +
|
|
334
|
+
function_name +
|
|
335
|
+
"'不允许声明私有函数,建议使用: " +
|
|
336
|
+
recommended_name,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
195
340
|
// 检查命名风格
|
|
196
|
-
var style_err = this._validate_naming_style(
|
|
341
|
+
var style_err = this._validate_naming_style(
|
|
342
|
+
function_name,
|
|
343
|
+
rule.styles,
|
|
344
|
+
"function-name",
|
|
345
|
+
);
|
|
197
346
|
if (style_err) {
|
|
347
|
+
// 使用智能缩写生成推荐名称
|
|
348
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
349
|
+
function_name,
|
|
350
|
+
"function-name",
|
|
351
|
+
);
|
|
352
|
+
var error_message = style_err;
|
|
353
|
+
if (smart_abbreviation && smart_abbreviation !== function_name) {
|
|
354
|
+
error_message = style_err + ",建议使用: " + smart_abbreviation;
|
|
355
|
+
}
|
|
198
356
|
return {
|
|
199
357
|
node: node,
|
|
200
|
-
message:
|
|
358
|
+
message: error_message,
|
|
201
359
|
};
|
|
202
360
|
}
|
|
203
361
|
|
|
204
362
|
// 检查长度
|
|
205
|
-
var len_err = this._checkNameLength(
|
|
363
|
+
var len_err = this._checkNameLength(
|
|
364
|
+
function_name,
|
|
365
|
+
rule.min,
|
|
366
|
+
rule.max,
|
|
367
|
+
"function-name",
|
|
368
|
+
);
|
|
206
369
|
if (len_err) {
|
|
370
|
+
// 使用智能缩写生成推荐名称
|
|
371
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
372
|
+
function_name,
|
|
373
|
+
"function-name",
|
|
374
|
+
);
|
|
375
|
+
var error_message = len_err;
|
|
376
|
+
if (smart_abbreviation && smart_abbreviation !== function_name) {
|
|
377
|
+
error_message = len_err + ",建议使用: " + smart_abbreviation;
|
|
378
|
+
}
|
|
207
379
|
return {
|
|
208
380
|
node: node,
|
|
209
|
-
message:
|
|
381
|
+
message: error_message,
|
|
210
382
|
};
|
|
211
383
|
}
|
|
212
384
|
|
|
213
385
|
// 检查单词长度
|
|
214
|
-
var word_err = this._checkWordLength(
|
|
386
|
+
var word_err = this._checkWordLength(
|
|
387
|
+
function_name,
|
|
388
|
+
rule.single_word_len,
|
|
389
|
+
"function-name",
|
|
390
|
+
);
|
|
215
391
|
if (word_err) {
|
|
392
|
+
// 检查错误消息是否已经包含建议
|
|
393
|
+
var error_message = word_err;
|
|
394
|
+
if (!word_err.includes("建议使用")) {
|
|
395
|
+
// 如果错误消息中不包含建议,则添加建议
|
|
396
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
397
|
+
function_name,
|
|
398
|
+
"function-name",
|
|
399
|
+
);
|
|
400
|
+
if (smart_abbreviation && smart_abbreviation !== function_name) {
|
|
401
|
+
error_message = word_err + ",建议使用: " + smart_abbreviation;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
216
404
|
return {
|
|
217
405
|
node: node,
|
|
218
|
-
message:
|
|
406
|
+
message: error_message,
|
|
219
407
|
};
|
|
220
408
|
}
|
|
221
409
|
|
|
222
410
|
// 检查禁止词汇
|
|
223
|
-
var forbid_err = this._checkForbiddenWords(
|
|
224
|
-
function_name,
|
|
225
|
-
'function-name',
|
|
226
|
-
);
|
|
411
|
+
var forbid_err = this._checkForbiddenWords(function_name, "function-name");
|
|
227
412
|
if (forbid_err) {
|
|
413
|
+
// 使用智能缩写生成推荐名称
|
|
414
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
415
|
+
function_name,
|
|
416
|
+
"function-name",
|
|
417
|
+
);
|
|
418
|
+
var error_message = forbid_err;
|
|
419
|
+
if (smart_abbreviation && smart_abbreviation !== function_name) {
|
|
420
|
+
error_message = forbid_err + ",建议使用: " + smart_abbreviation;
|
|
421
|
+
}
|
|
228
422
|
return {
|
|
229
423
|
node: node,
|
|
230
|
-
message:
|
|
424
|
+
message: error_message,
|
|
231
425
|
};
|
|
232
426
|
}
|
|
233
427
|
|
|
234
|
-
//
|
|
235
|
-
var
|
|
236
|
-
|
|
428
|
+
// 检查并推荐更合适的词汇(作为命名风格检查的补充)
|
|
429
|
+
var recommend_info = this._checkAndRecommend(
|
|
430
|
+
function_name,
|
|
431
|
+
"function-name",
|
|
432
|
+
);
|
|
433
|
+
if (recommend_info) {
|
|
434
|
+
// 如果有推荐建议,提示可以使用更简洁的词汇
|
|
237
435
|
return {
|
|
238
436
|
node: node,
|
|
239
|
-
message:
|
|
437
|
+
message:
|
|
438
|
+
"函数名'" +
|
|
439
|
+
function_name +
|
|
440
|
+
"'建议使用: " +
|
|
441
|
+
recommend_info.recommended_name,
|
|
240
442
|
};
|
|
241
443
|
}
|
|
242
444
|
|
|
243
445
|
return null;
|
|
244
446
|
} catch (error) {
|
|
245
|
-
console.error(
|
|
447
|
+
console.error("检测函数名时出错:", error);
|
|
246
448
|
return null;
|
|
247
449
|
}
|
|
248
450
|
};
|
|
@@ -255,18 +457,22 @@ Detector.prototype._checkFunctionName = function (function_name, node) {
|
|
|
255
457
|
*/
|
|
256
458
|
Detector.prototype._checkVariableName = function (variable_name, node) {
|
|
257
459
|
try {
|
|
258
|
-
var rule = this.config.getRule(
|
|
460
|
+
var rule = this.config.getRule("variable-name");
|
|
259
461
|
if (!rule) {
|
|
260
462
|
return null;
|
|
261
463
|
}
|
|
262
464
|
|
|
263
465
|
// 检查是否为忽略词
|
|
264
|
-
if (this._isIgnoredWord(variable_name,
|
|
466
|
+
if (this._isIgnoredWord(variable_name, "variable-name")) {
|
|
265
467
|
return null;
|
|
266
468
|
}
|
|
267
469
|
|
|
268
470
|
// 检查命名风格
|
|
269
|
-
var style_err = this._validate_naming_style(
|
|
471
|
+
var style_err = this._validate_naming_style(
|
|
472
|
+
variable_name,
|
|
473
|
+
rule.styles,
|
|
474
|
+
"variable-name",
|
|
475
|
+
);
|
|
270
476
|
if (style_err) {
|
|
271
477
|
return {
|
|
272
478
|
node: node,
|
|
@@ -275,28 +481,59 @@ Detector.prototype._checkVariableName = function (variable_name, node) {
|
|
|
275
481
|
}
|
|
276
482
|
|
|
277
483
|
// 检查长度
|
|
278
|
-
var len_err = this._checkNameLength(
|
|
484
|
+
var len_err = this._checkNameLength(
|
|
485
|
+
variable_name,
|
|
486
|
+
rule.min,
|
|
487
|
+
rule.max,
|
|
488
|
+
"variable-name",
|
|
489
|
+
);
|
|
279
490
|
if (len_err) {
|
|
491
|
+
// 检查错误消息是否已经包含建议
|
|
492
|
+
var error_message = len_err;
|
|
493
|
+
if (!len_err.includes("建议使用")) {
|
|
494
|
+
// 如果错误消息中不包含建议,则添加建议
|
|
495
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
496
|
+
variable_name,
|
|
497
|
+
"variable-name",
|
|
498
|
+
);
|
|
499
|
+
if (smart_abbreviation && smart_abbreviation !== variable_name) {
|
|
500
|
+
error_message = len_err + ",建议使用: " + smart_abbreviation;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
280
504
|
return {
|
|
281
505
|
node: node,
|
|
282
|
-
message:
|
|
506
|
+
message: error_message,
|
|
283
507
|
};
|
|
284
508
|
}
|
|
285
509
|
|
|
286
510
|
// 检查单词长度
|
|
287
|
-
var word_err = this._checkWordLength(
|
|
511
|
+
var word_err = this._checkWordLength(
|
|
512
|
+
variable_name,
|
|
513
|
+
rule.single_word_len,
|
|
514
|
+
"variable-name",
|
|
515
|
+
);
|
|
288
516
|
if (word_err) {
|
|
517
|
+
// 检查错误消息是否已经包含建议
|
|
518
|
+
var error_message = word_err;
|
|
519
|
+
if (!word_err.includes("建议使用")) {
|
|
520
|
+
// 如果错误消息中不包含建议,则添加建议
|
|
521
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
522
|
+
variable_name,
|
|
523
|
+
"variable-name",
|
|
524
|
+
);
|
|
525
|
+
if (smart_abbreviation && smart_abbreviation !== variable_name) {
|
|
526
|
+
error_message = word_err + ",建议使用: " + smart_abbreviation;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
289
529
|
return {
|
|
290
530
|
node: node,
|
|
291
|
-
message:
|
|
531
|
+
message: error_message,
|
|
292
532
|
};
|
|
293
533
|
}
|
|
294
534
|
|
|
295
535
|
// 检查禁止词汇
|
|
296
|
-
var forbid_err = this._checkForbiddenWords(
|
|
297
|
-
variable_name,
|
|
298
|
-
'variable-name',
|
|
299
|
-
);
|
|
536
|
+
var forbid_err = this._checkForbiddenWords(variable_name, "variable-name");
|
|
300
537
|
if (forbid_err) {
|
|
301
538
|
return {
|
|
302
539
|
node: node,
|
|
@@ -306,7 +543,7 @@ Detector.prototype._checkVariableName = function (variable_name, node) {
|
|
|
306
543
|
|
|
307
544
|
return null;
|
|
308
545
|
} catch (error) {
|
|
309
|
-
console.error(
|
|
546
|
+
console.error("检测变量名时出错:", error);
|
|
310
547
|
return null;
|
|
311
548
|
}
|
|
312
549
|
};
|
|
@@ -319,55 +556,111 @@ Detector.prototype._checkVariableName = function (variable_name, node) {
|
|
|
319
556
|
*/
|
|
320
557
|
Detector.prototype._checkParamName = function (param_name, node) {
|
|
321
558
|
try {
|
|
322
|
-
var rule = this.config.getRule(
|
|
559
|
+
var rule = this.config.getRule("param-name");
|
|
323
560
|
if (!rule) {
|
|
324
561
|
return null;
|
|
325
562
|
}
|
|
326
563
|
|
|
327
564
|
// 检查是否为忽略词
|
|
328
|
-
if (this._isIgnoredWord(param_name,
|
|
565
|
+
if (this._isIgnoredWord(param_name, "param-name")) {
|
|
329
566
|
return null;
|
|
330
567
|
}
|
|
331
568
|
|
|
332
569
|
// 检查命名风格
|
|
333
|
-
var style_err = this._validate_naming_style(
|
|
570
|
+
var style_err = this._validate_naming_style(
|
|
571
|
+
param_name,
|
|
572
|
+
rule.styles,
|
|
573
|
+
"param-name",
|
|
574
|
+
);
|
|
334
575
|
if (style_err) {
|
|
576
|
+
// 使用智能缩写生成推荐名称
|
|
577
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
578
|
+
param_name,
|
|
579
|
+
"param-name",
|
|
580
|
+
);
|
|
581
|
+
var error_message = style_err;
|
|
582
|
+
if (smart_abbreviation && smart_abbreviation !== param_name) {
|
|
583
|
+
error_message = style_err + ",建议使用: " + smart_abbreviation;
|
|
584
|
+
}
|
|
335
585
|
return {
|
|
336
586
|
node: node,
|
|
337
|
-
message:
|
|
587
|
+
message: error_message,
|
|
338
588
|
};
|
|
339
589
|
}
|
|
340
590
|
|
|
341
591
|
// 检查长度
|
|
342
|
-
var len_err = this._checkNameLength(
|
|
592
|
+
var len_err = this._checkNameLength(
|
|
593
|
+
param_name,
|
|
594
|
+
rule.min,
|
|
595
|
+
rule.max,
|
|
596
|
+
"param-name",
|
|
597
|
+
);
|
|
343
598
|
if (len_err) {
|
|
599
|
+
// 检查错误消息是否已经包含建议
|
|
600
|
+
var error_message = len_err;
|
|
601
|
+
if (!len_err.includes("建议使用")) {
|
|
602
|
+
// 如果错误消息中不包含建议,则添加建议
|
|
603
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
604
|
+
param_name,
|
|
605
|
+
"param-name",
|
|
606
|
+
);
|
|
607
|
+
if (smart_abbreviation && smart_abbreviation !== param_name) {
|
|
608
|
+
error_message = len_err + ",建议使用: " + smart_abbreviation;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
344
612
|
return {
|
|
345
613
|
node: node,
|
|
346
|
-
message:
|
|
614
|
+
message: error_message,
|
|
347
615
|
};
|
|
348
616
|
}
|
|
349
617
|
|
|
350
618
|
// 检查单词长度
|
|
351
|
-
var word_err = this._checkWordLength(
|
|
619
|
+
var word_err = this._checkWordLength(
|
|
620
|
+
param_name,
|
|
621
|
+
rule.single_word_len,
|
|
622
|
+
"param-name",
|
|
623
|
+
);
|
|
352
624
|
if (word_err) {
|
|
625
|
+
// 检查错误消息是否已经包含建议
|
|
626
|
+
var error_message = word_err;
|
|
627
|
+
if (!word_err.includes("建议使用")) {
|
|
628
|
+
// 如果错误消息中不包含建议,则添加建议
|
|
629
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
630
|
+
param_name,
|
|
631
|
+
"param-name",
|
|
632
|
+
);
|
|
633
|
+
if (smart_abbreviation && smart_abbreviation !== param_name) {
|
|
634
|
+
error_message = word_err + ",建议使用: " + smart_abbreviation;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
353
637
|
return {
|
|
354
638
|
node: node,
|
|
355
|
-
message:
|
|
639
|
+
message: error_message,
|
|
356
640
|
};
|
|
357
641
|
}
|
|
358
642
|
|
|
359
643
|
// 检查禁止词汇
|
|
360
|
-
var forbid_err = this._checkForbiddenWords(param_name,
|
|
644
|
+
var forbid_err = this._checkForbiddenWords(param_name, "param-name");
|
|
361
645
|
if (forbid_err) {
|
|
646
|
+
// 使用智能缩写生成推荐名称
|
|
647
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
648
|
+
param_name,
|
|
649
|
+
"param-name",
|
|
650
|
+
);
|
|
651
|
+
var error_message = forbid_err;
|
|
652
|
+
if (smart_abbreviation && smart_abbreviation !== param_name) {
|
|
653
|
+
error_message = forbid_err + ",建议使用: " + smart_abbreviation;
|
|
654
|
+
}
|
|
362
655
|
return {
|
|
363
656
|
node: node,
|
|
364
|
-
message:
|
|
657
|
+
message: error_message,
|
|
365
658
|
};
|
|
366
659
|
}
|
|
367
660
|
|
|
368
661
|
return null;
|
|
369
662
|
} catch (error) {
|
|
370
|
-
console.error(
|
|
663
|
+
console.error("检测参数名时出错:", error);
|
|
371
664
|
return null;
|
|
372
665
|
}
|
|
373
666
|
};
|
|
@@ -379,101 +672,207 @@ Detector.prototype._checkParamName = function (param_name, node) {
|
|
|
379
672
|
* @param {object} val_node 值节点(用于识别基础值)
|
|
380
673
|
* @returns {object|null} 错误信息或null
|
|
381
674
|
*/
|
|
382
|
-
Detector.prototype._checkConstantName = function (
|
|
675
|
+
Detector.prototype._checkConstantName = function (
|
|
676
|
+
constant_name,
|
|
677
|
+
node,
|
|
678
|
+
val_node,
|
|
679
|
+
) {
|
|
383
680
|
try {
|
|
384
|
-
var rule = this.config.getRule('constant-name');
|
|
385
|
-
if (!rule) {
|
|
386
|
-
return null;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// 检查是否为忽略词
|
|
390
|
-
if (this._isIgnoredWord(constant_name, 'constant-name')) {
|
|
391
|
-
return null;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
681
|
// 检查是否为解构导入(从模块导入的变量)
|
|
395
682
|
var is_destructured_import = this._isDestructuredImport(node);
|
|
396
|
-
|
|
397
|
-
//
|
|
683
|
+
|
|
684
|
+
// 如果是解构导入,则不进行命名检测
|
|
398
685
|
if (is_destructured_import) {
|
|
399
686
|
return null;
|
|
400
687
|
}
|
|
401
688
|
|
|
402
689
|
// 检查是否应该使用let而不是const
|
|
403
690
|
var should_use_let = this._shouldUseLetInsteadOfConst(node, val_node);
|
|
404
|
-
|
|
691
|
+
|
|
405
692
|
// 如果应该使用let,则提示开发者
|
|
406
693
|
if (should_use_let) {
|
|
407
694
|
return {
|
|
408
695
|
node: node,
|
|
409
|
-
message: `变量'${constant_name}'应该使用let而不是const
|
|
696
|
+
message: `变量'${constant_name}'应该使用let而不是const声明,因为它不是真正的常量`,
|
|
410
697
|
};
|
|
411
698
|
}
|
|
412
699
|
|
|
413
|
-
//
|
|
414
|
-
var
|
|
700
|
+
// 根据值类型确定应该应用的命名规则
|
|
701
|
+
var rule_type = "constant-name"; // 默认使用常量命名规则
|
|
702
|
+
var allowed_styles = [];
|
|
415
703
|
|
|
416
|
-
//
|
|
417
|
-
if (
|
|
704
|
+
// 检查是否为函数表达式或箭头函数
|
|
705
|
+
if (
|
|
706
|
+
val_node &&
|
|
707
|
+
(val_node.type === "FunctionExpression" ||
|
|
708
|
+
val_node.type === "ArrowFunctionExpression")
|
|
709
|
+
) {
|
|
710
|
+
rule_type = "function-name";
|
|
711
|
+
}
|
|
712
|
+
// 检查是否为类表达式
|
|
713
|
+
else if (val_node && val_node.type === "ClassExpression") {
|
|
714
|
+
rule_type = "class-name";
|
|
715
|
+
}
|
|
716
|
+
// 检查是否为类实例(new表达式)
|
|
717
|
+
else if (val_node && val_node.type === "NewExpression") {
|
|
718
|
+
rule_type = "function-name"; // 类实例使用函数命名规则(camelCase)
|
|
719
|
+
}
|
|
720
|
+
// 检查是否为基础值类型
|
|
721
|
+
else if (val_node && this._isBaseValue(val_node)) {
|
|
722
|
+
rule_type = "constant-name";
|
|
723
|
+
}
|
|
724
|
+
// 检查是否为其他复杂类型(函数调用、变量引用等)
|
|
725
|
+
else if (val_node && this._isComplexType(val_node)) {
|
|
726
|
+
// 其他复杂类型不进行命名检测
|
|
727
|
+
return null;
|
|
728
|
+
}
|
|
729
|
+
// 其他情况不进行命名检测
|
|
730
|
+
else {
|
|
418
731
|
return null;
|
|
419
732
|
}
|
|
420
733
|
|
|
421
|
-
//
|
|
422
|
-
|
|
734
|
+
// 获取对应的命名规则
|
|
735
|
+
// 将属性规则类型映射到对应的基础规则类型(用于获取规则配置)
|
|
736
|
+
var rule_config_type = rule_type;
|
|
737
|
+
if (rule_type.startsWith('property-')) {
|
|
738
|
+
// 属性类名 -> 类名
|
|
739
|
+
if (rule_type === 'property-class-name') {
|
|
740
|
+
rule_config_type = 'class-name';
|
|
741
|
+
}
|
|
742
|
+
// 属性实例类名 -> 变量名
|
|
743
|
+
else if (rule_type === 'property-instance-class-name') {
|
|
744
|
+
rule_config_type = 'variable-name';
|
|
745
|
+
}
|
|
746
|
+
// 属性方法名 -> 方法名
|
|
747
|
+
else if (rule_type === 'property-method-name') {
|
|
748
|
+
rule_config_type = 'method-name';
|
|
749
|
+
}
|
|
750
|
+
// 属性值名 -> 变量名
|
|
751
|
+
else if (rule_type === 'property-value-name') {
|
|
752
|
+
rule_config_type = 'variable-name';
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
var rule = this.config.getRule(rule_config_type);
|
|
757
|
+
if (!rule) {
|
|
758
|
+
return null;
|
|
759
|
+
}
|
|
423
760
|
|
|
424
|
-
//
|
|
425
|
-
if (
|
|
761
|
+
// 检查是否为忽略词
|
|
762
|
+
if (this._isIgnoredWord(constant_name, rule_type)) {
|
|
426
763
|
return null;
|
|
427
764
|
}
|
|
428
765
|
|
|
429
766
|
// 检查命名风格
|
|
430
|
-
var style_err = this._validate_naming_style(
|
|
767
|
+
var style_err = this._validate_naming_style(
|
|
768
|
+
constant_name,
|
|
769
|
+
rule.styles,
|
|
770
|
+
rule_type,
|
|
771
|
+
);
|
|
431
772
|
if (style_err) {
|
|
773
|
+
// 使用智能缩写生成推荐名称
|
|
774
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
775
|
+
constant_name,
|
|
776
|
+
rule_type,
|
|
777
|
+
);
|
|
778
|
+
var error_message = style_err;
|
|
779
|
+
if (smart_abbreviation && smart_abbreviation !== constant_name) {
|
|
780
|
+
error_message = style_err + ",建议使用: " + smart_abbreviation;
|
|
781
|
+
}
|
|
782
|
+
|
|
432
783
|
return {
|
|
433
784
|
node: node,
|
|
434
|
-
message:
|
|
785
|
+
message: error_message,
|
|
786
|
+
rule_type: rule_type, // 返回正确的规则类型
|
|
435
787
|
};
|
|
436
788
|
}
|
|
437
789
|
|
|
438
790
|
// 检查长度
|
|
439
|
-
var len_err = this._checkNameLength(
|
|
791
|
+
var len_err = this._checkNameLength(
|
|
792
|
+
constant_name,
|
|
793
|
+
rule.min,
|
|
794
|
+
rule.max,
|
|
795
|
+
rule_type,
|
|
796
|
+
);
|
|
440
797
|
if (len_err) {
|
|
798
|
+
// 使用智能缩写生成推荐名称
|
|
799
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
800
|
+
constant_name,
|
|
801
|
+
rule_type,
|
|
802
|
+
);
|
|
803
|
+
var error_message = len_err;
|
|
804
|
+
if (smart_abbreviation && smart_abbreviation !== constant_name) {
|
|
805
|
+
error_message = len_err + ",建议使用: " + smart_abbreviation;
|
|
806
|
+
}
|
|
807
|
+
|
|
441
808
|
return {
|
|
442
809
|
node: node,
|
|
443
|
-
message:
|
|
810
|
+
message: error_message,
|
|
811
|
+
rule_type: rule_type, // 返回正确的规则类型
|
|
444
812
|
};
|
|
445
813
|
}
|
|
446
814
|
|
|
447
815
|
// 检查单词长度
|
|
448
|
-
var word_err = this._checkWordLength(
|
|
816
|
+
var word_err = this._checkWordLength(
|
|
817
|
+
constant_name,
|
|
818
|
+
rule.single_word_len,
|
|
819
|
+
rule_type,
|
|
820
|
+
);
|
|
449
821
|
if (word_err) {
|
|
450
822
|
return {
|
|
451
823
|
node: node,
|
|
452
824
|
message: word_err,
|
|
825
|
+
rule_type: rule_type, // 返回正确的规则类型
|
|
453
826
|
};
|
|
454
827
|
}
|
|
455
828
|
|
|
456
829
|
// 检查禁止词汇
|
|
457
|
-
var forbid_err = this._checkForbiddenWords(constant_name,
|
|
830
|
+
var forbid_err = this._checkForbiddenWords(constant_name, rule_type);
|
|
458
831
|
if (forbid_err) {
|
|
459
832
|
return {
|
|
460
833
|
node: node,
|
|
461
834
|
message: forbid_err,
|
|
835
|
+
rule_type: rule_type, // 返回正确的规则类型
|
|
462
836
|
};
|
|
463
837
|
}
|
|
464
838
|
|
|
465
|
-
//
|
|
466
|
-
var
|
|
467
|
-
if (
|
|
839
|
+
// 检查并推荐更合适的词汇(作为命名风格检查的补充)
|
|
840
|
+
var recommend_info = this._checkAndRecommend(constant_name, rule_type);
|
|
841
|
+
if (recommend_info) {
|
|
842
|
+
// 根据规则类型生成正确的错误消息
|
|
843
|
+
var name_type_text = "";
|
|
844
|
+
switch (rule_type) {
|
|
845
|
+
case "function-name":
|
|
846
|
+
name_type_text = "函数名";
|
|
847
|
+
break;
|
|
848
|
+
case "class-name":
|
|
849
|
+
name_type_text = "类名";
|
|
850
|
+
break;
|
|
851
|
+
case "constant-name":
|
|
852
|
+
name_type_text = "常量名";
|
|
853
|
+
break;
|
|
854
|
+
case "variable-name":
|
|
855
|
+
name_type_text = "变量名";
|
|
856
|
+
break;
|
|
857
|
+
default:
|
|
858
|
+
name_type_text = "名称";
|
|
859
|
+
}
|
|
860
|
+
|
|
468
861
|
return {
|
|
469
862
|
node: node,
|
|
470
|
-
message:
|
|
863
|
+
message:
|
|
864
|
+
name_type_text +
|
|
865
|
+
"'" +
|
|
866
|
+
constant_name +
|
|
867
|
+
"'长度过长,最大长度为20字符,建议使用: " +
|
|
868
|
+
recommend_info.recommended_name,
|
|
869
|
+
rule_type: rule_type, // 返回正确的规则类型
|
|
471
870
|
};
|
|
472
871
|
}
|
|
473
872
|
|
|
474
873
|
return null;
|
|
475
874
|
} catch (error) {
|
|
476
|
-
console.error(
|
|
875
|
+
console.error("检测常量名时出错:", error);
|
|
477
876
|
return null;
|
|
478
877
|
}
|
|
479
878
|
};
|
|
@@ -498,11 +897,11 @@ Detector.prototype._validate_naming_style = function (name, styles, name_type) {
|
|
|
498
897
|
}
|
|
499
898
|
}
|
|
500
899
|
|
|
501
|
-
var style_names = styles.join(
|
|
900
|
+
var style_names = styles.join("或");
|
|
502
901
|
|
|
503
|
-
var name_type_desc = this.config.name_type_map[name_type] ||
|
|
902
|
+
var name_type_desc = this.config.name_type_map[name_type] || "名称";
|
|
504
903
|
|
|
505
|
-
return name_type_desc + '
|
|
904
|
+
return name_type_desc + "'" + name + "'不符合" + style_names + "命名风格";
|
|
506
905
|
};
|
|
507
906
|
|
|
508
907
|
/**
|
|
@@ -514,17 +913,17 @@ Detector.prototype._validate_naming_style = function (name, styles, name_type) {
|
|
|
514
913
|
*/
|
|
515
914
|
Detector.prototype._checkNameLength = function (name, min, max, name_type) {
|
|
516
915
|
if (!name) {
|
|
517
|
-
return
|
|
916
|
+
return "名称不能为空";
|
|
518
917
|
}
|
|
519
918
|
|
|
520
|
-
var name_type_desc = this.config.name_type_map[name_type] ||
|
|
919
|
+
var name_type_desc = this.config.name_type_map[name_type] || "名称";
|
|
521
920
|
var len = name.length;
|
|
522
921
|
if (len < min) {
|
|
523
|
-
return name_type_desc + '
|
|
922
|
+
return name_type_desc + "'" + name + "'长度过短,最小长度为" + min + "字符";
|
|
524
923
|
}
|
|
525
924
|
|
|
526
925
|
if (len > max) {
|
|
527
|
-
return name_type_desc + '
|
|
926
|
+
return name_type_desc + "'" + name + "'长度过长,最大长度为" + max + "字符";
|
|
528
927
|
}
|
|
529
928
|
|
|
530
929
|
return null;
|
|
@@ -541,13 +940,13 @@ Detector.prototype._checkWordLength = function (name, max_word_len, name_type) {
|
|
|
541
940
|
return null;
|
|
542
941
|
}
|
|
543
942
|
|
|
544
|
-
var name_type_desc = this.config.name_type_map[name_type] ||
|
|
545
|
-
|
|
943
|
+
var name_type_desc = this.config.name_type_map[name_type] || "名称";
|
|
944
|
+
|
|
546
945
|
// 处理私有标识符(开头的下划线)
|
|
547
946
|
var processed_name = name;
|
|
548
947
|
var has_private_prefix = false;
|
|
549
948
|
|
|
550
|
-
if (name.startsWith(
|
|
949
|
+
if (name.startsWith("_")) {
|
|
551
950
|
has_private_prefix = true;
|
|
552
951
|
processed_name = name.substring(1); // 去掉开头的下划线
|
|
553
952
|
}
|
|
@@ -555,10 +954,10 @@ Detector.prototype._checkWordLength = function (name, max_word_len, name_type) {
|
|
|
555
954
|
// 分割单词(根据命名风格)
|
|
556
955
|
var words = [];
|
|
557
956
|
|
|
558
|
-
if (processed_name.includes(
|
|
559
|
-
words = processed_name.split(
|
|
560
|
-
} else if (processed_name.includes(
|
|
561
|
-
words = processed_name.split(
|
|
957
|
+
if (processed_name.includes("_")) {
|
|
958
|
+
words = processed_name.split("_");
|
|
959
|
+
} else if (processed_name.includes("-")) {
|
|
960
|
+
words = processed_name.split("-");
|
|
562
961
|
} else {
|
|
563
962
|
// 驼峰命名法分割(保持原词大小写)
|
|
564
963
|
words = processed_name.split(/(?=[A-Z])/);
|
|
@@ -566,11 +965,11 @@ Detector.prototype._checkWordLength = function (name, max_word_len, name_type) {
|
|
|
566
965
|
|
|
567
966
|
// 如果存在私有标识符,添加空字符串表示私有标识符(不检查长度)
|
|
568
967
|
if (has_private_prefix) {
|
|
569
|
-
words.unshift(
|
|
968
|
+
words.unshift("_");
|
|
570
969
|
}
|
|
571
970
|
|
|
572
971
|
// 过滤空字符串
|
|
573
|
-
words = words.filter(function(word) {
|
|
972
|
+
words = words.filter(function (word) {
|
|
574
973
|
return word && word.length > 0;
|
|
575
974
|
});
|
|
576
975
|
|
|
@@ -582,27 +981,27 @@ Detector.prototype._checkWordLength = function (name, max_word_len, name_type) {
|
|
|
582
981
|
for (var i = 0; i < words.length; i++) {
|
|
583
982
|
var word = words[i];
|
|
584
983
|
// 跳过空字符串和私有标识符(单个下划线)
|
|
585
|
-
if (!word || word ===
|
|
984
|
+
if (!word || word === "_") {
|
|
586
985
|
continue;
|
|
587
986
|
}
|
|
588
987
|
|
|
589
988
|
if (word.length > max_word_len) {
|
|
590
|
-
//
|
|
591
|
-
var
|
|
592
|
-
var recommendation_text =
|
|
593
|
-
if (
|
|
594
|
-
recommendation_text =
|
|
989
|
+
// 使用智能缩写生成推荐名称
|
|
990
|
+
var smart_abbreviation = this._getSmartAbbreviation(name, name_type);
|
|
991
|
+
var recommendation_text = "";
|
|
992
|
+
if (smart_abbreviation && smart_abbreviation !== name) {
|
|
993
|
+
recommendation_text = ",建议使用: " + smart_abbreviation;
|
|
595
994
|
}
|
|
596
|
-
|
|
995
|
+
|
|
597
996
|
return (
|
|
598
997
|
name_type_desc +
|
|
599
|
-
'
|
|
998
|
+
"'" +
|
|
600
999
|
name +
|
|
601
|
-
'
|
|
1000
|
+
"'中的单词'" +
|
|
602
1001
|
word +
|
|
603
|
-
'
|
|
1002
|
+
"'过长,最大长度为" +
|
|
604
1003
|
max_word_len +
|
|
605
|
-
|
|
1004
|
+
"字符" +
|
|
606
1005
|
recommendation_text
|
|
607
1006
|
);
|
|
608
1007
|
}
|
|
@@ -627,7 +1026,7 @@ Detector.prototype._checkForbiddenWords = function (name, name_type) {
|
|
|
627
1026
|
return null;
|
|
628
1027
|
}
|
|
629
1028
|
|
|
630
|
-
var name_type_desc = this.config.name_type_map[name_type] ||
|
|
1029
|
+
var name_type_desc = this.config.name_type_map[name_type] || "名称";
|
|
631
1030
|
var name_lower = name.toLowerCase();
|
|
632
1031
|
|
|
633
1032
|
// 如果名称本身就是禁止词汇(即单个单词),则允许使用
|
|
@@ -640,23 +1039,45 @@ Detector.prototype._checkForbiddenWords = function (name, name_type) {
|
|
|
640
1039
|
|
|
641
1040
|
// 按单词边界分割名称
|
|
642
1041
|
var words = this._splitNameIntoWords(name_lower);
|
|
643
|
-
|
|
1042
|
+
|
|
644
1043
|
// 检查每个单词是否在禁止词汇列表中
|
|
1044
|
+
var found_forbidden_words = [];
|
|
1045
|
+
|
|
645
1046
|
for (var i = 0; i < words.length; i++) {
|
|
646
1047
|
var word = words[i];
|
|
647
1048
|
// 跳过空字符串和单个字符
|
|
648
1049
|
if (!word || word.length <= 1) {
|
|
649
1050
|
continue;
|
|
650
1051
|
}
|
|
651
|
-
|
|
1052
|
+
|
|
652
1053
|
for (var j = 0; j < forbidden_words.length; j++) {
|
|
653
1054
|
var forbidden_word = forbidden_words[j].toLowerCase();
|
|
654
1055
|
if (word === forbidden_word) {
|
|
655
|
-
|
|
1056
|
+
// 记录找到的禁用词,但不立即返回
|
|
1057
|
+
if (found_forbidden_words.indexOf(forbidden_word) === -1) {
|
|
1058
|
+
found_forbidden_words.push(forbidden_word);
|
|
1059
|
+
}
|
|
656
1060
|
}
|
|
657
1061
|
}
|
|
658
1062
|
}
|
|
659
1063
|
|
|
1064
|
+
// 如果有找到禁用词,返回错误信息
|
|
1065
|
+
if (found_forbidden_words.length > 0) {
|
|
1066
|
+
var error_message = name_type_desc + "'" + name + "'包含禁止拼接词";
|
|
1067
|
+
|
|
1068
|
+
if (found_forbidden_words.length === 1) {
|
|
1069
|
+
error_message += "'" + found_forbidden_words[0] + "'";
|
|
1070
|
+
} else {
|
|
1071
|
+
// 多个禁用词,按优先级排序(长的优先)
|
|
1072
|
+
found_forbidden_words.sort(function(a, b) {
|
|
1073
|
+
return b.length - a.length; // 长的优先
|
|
1074
|
+
});
|
|
1075
|
+
error_message += ":" + found_forbidden_words.join(", ");
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
return error_message;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
660
1081
|
return null;
|
|
661
1082
|
};
|
|
662
1083
|
|
|
@@ -669,22 +1090,22 @@ Detector.prototype._splitNameIntoWords = function (name) {
|
|
|
669
1090
|
if (!name) {
|
|
670
1091
|
return [];
|
|
671
1092
|
}
|
|
672
|
-
|
|
1093
|
+
|
|
673
1094
|
var words = [];
|
|
674
1095
|
var processed_name = name;
|
|
675
1096
|
var has_private_prefix = false;
|
|
676
1097
|
|
|
677
1098
|
// 处理私有标识符(开头的下划线)
|
|
678
|
-
if (name.startsWith(
|
|
1099
|
+
if (name.startsWith("_")) {
|
|
679
1100
|
has_private_prefix = true;
|
|
680
1101
|
processed_name = name.substring(1); // 去掉开头的下划线
|
|
681
1102
|
}
|
|
682
1103
|
|
|
683
1104
|
// 根据命名风格分割单词
|
|
684
|
-
if (processed_name.includes(
|
|
685
|
-
words = processed_name.split(
|
|
686
|
-
} else if (processed_name.includes(
|
|
687
|
-
words = processed_name.split(
|
|
1105
|
+
if (processed_name.includes("_")) {
|
|
1106
|
+
words = processed_name.split("_");
|
|
1107
|
+
} else if (processed_name.includes("-")) {
|
|
1108
|
+
words = processed_name.split("-");
|
|
688
1109
|
} else {
|
|
689
1110
|
// 驼峰命名法分割(保持原词大小写)
|
|
690
1111
|
words = processed_name.split(/(?=[A-Z])/);
|
|
@@ -692,11 +1113,11 @@ Detector.prototype._splitNameIntoWords = function (name) {
|
|
|
692
1113
|
|
|
693
1114
|
// 如果存在私有标识符,添加下划线作为第一个单词
|
|
694
1115
|
if (has_private_prefix) {
|
|
695
|
-
words.unshift(
|
|
1116
|
+
words.unshift("_");
|
|
696
1117
|
}
|
|
697
1118
|
|
|
698
1119
|
// 过滤空字符串
|
|
699
|
-
words = words.filter(function(word) {
|
|
1120
|
+
words = words.filter(function (word) {
|
|
700
1121
|
return word && word.length > 0;
|
|
701
1122
|
});
|
|
702
1123
|
|
|
@@ -711,48 +1132,101 @@ Detector.prototype._splitNameIntoWords = function (name) {
|
|
|
711
1132
|
*/
|
|
712
1133
|
Detector.prototype._isThirdPartyConfigProperty = function (node, parent_node) {
|
|
713
1134
|
try {
|
|
1135
|
+
// 处理新的父节点信息结构(包含node和parent属性)
|
|
1136
|
+
var actual_parent_node = parent_node;
|
|
1137
|
+
if (parent_node && typeof parent_node === "object" && parent_node.node) {
|
|
1138
|
+
actual_parent_node = parent_node.node;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
714
1141
|
// 检查当前节点是否为对象字面量的属性
|
|
715
|
-
if (!
|
|
1142
|
+
if (!actual_parent_node || actual_parent_node.type !== "ObjectExpression") {
|
|
716
1143
|
return false;
|
|
717
1144
|
}
|
|
718
1145
|
|
|
719
|
-
//
|
|
720
|
-
var
|
|
721
|
-
|
|
1146
|
+
// 递归查找调用表达式(处理嵌套对象的情况)
|
|
1147
|
+
var findCallExpression = function (current_node) {
|
|
1148
|
+
if (!current_node) {
|
|
1149
|
+
return null;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
if (current_node.type === "CallExpression") {
|
|
1153
|
+
return current_node;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
// 继续向上查找
|
|
1157
|
+
return findCallExpression(current_node.parent);
|
|
1158
|
+
};
|
|
1159
|
+
|
|
1160
|
+
// 优先使用新的父节点信息结构中的parent属性
|
|
1161
|
+
var grandparent =
|
|
1162
|
+
parent_node && typeof parent_node === "object" && parent_node.parent
|
|
1163
|
+
? parent_node.parent
|
|
1164
|
+
: actual_parent_node.parent;
|
|
1165
|
+
|
|
1166
|
+
// 查找调用表达式
|
|
1167
|
+
var call_expression = findCallExpression(grandparent);
|
|
1168
|
+
if (!call_expression) {
|
|
722
1169
|
return false;
|
|
723
1170
|
}
|
|
724
1171
|
|
|
725
1172
|
// 检查方法调用是否来自外部模块(非当前文件定义的函数)
|
|
726
|
-
var callee =
|
|
1173
|
+
var callee = call_expression.callee;
|
|
727
1174
|
if (!callee) {
|
|
728
1175
|
return false;
|
|
729
1176
|
}
|
|
730
1177
|
|
|
731
1178
|
// 如果是成员表达式(如 chokidar.watch),则认为是第三方库调用
|
|
732
|
-
if (callee.type ===
|
|
1179
|
+
if (callee.type === "MemberExpression") {
|
|
1180
|
+
// 检查成员表达式的对象是否为模块导入变量
|
|
1181
|
+
var is_module_import = this._isModuleImportVariable(callee.object);
|
|
1182
|
+
if (is_module_import) {
|
|
1183
|
+
return true;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// 对于其他成员表达式,也认为是第三方库调用(保守策略)
|
|
733
1187
|
return true;
|
|
734
1188
|
}
|
|
735
1189
|
|
|
736
1190
|
// 如果是标识符,检查是否是常见的第三方库函数名
|
|
737
|
-
if (callee.type ===
|
|
1191
|
+
if (callee.type === "Identifier") {
|
|
738
1192
|
var common_third_party_functions = [
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
1193
|
+
"watch",
|
|
1194
|
+
"require",
|
|
1195
|
+
"import",
|
|
1196
|
+
"create",
|
|
1197
|
+
"build",
|
|
1198
|
+
"compile",
|
|
1199
|
+
"parse",
|
|
1200
|
+
"stringify",
|
|
1201
|
+
"readFile",
|
|
1202
|
+
"writeFile",
|
|
1203
|
+
"mkdir",
|
|
1204
|
+
"exec",
|
|
1205
|
+
"spawn",
|
|
1206
|
+
"fork",
|
|
1207
|
+
"connect",
|
|
1208
|
+
"listen",
|
|
1209
|
+
"send",
|
|
742
1210
|
];
|
|
743
|
-
|
|
1211
|
+
|
|
744
1212
|
// 如果是常见的第三方库函数名,则认为是第三方库调用
|
|
745
1213
|
if (common_third_party_functions.includes(callee.name)) {
|
|
746
1214
|
return true;
|
|
747
1215
|
}
|
|
748
|
-
|
|
1216
|
+
|
|
1217
|
+
// 检查标识符是否为模块导入变量
|
|
1218
|
+
var is_module_import = this._isModuleImportVariable(callee);
|
|
1219
|
+
if (is_module_import) {
|
|
1220
|
+
return true;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
749
1223
|
// 对于其他标识符,暂时不认为是第三方库调用(避免误判)
|
|
750
1224
|
return false;
|
|
751
1225
|
}
|
|
752
1226
|
|
|
753
1227
|
return false;
|
|
754
1228
|
} catch (error) {
|
|
755
|
-
console.error(
|
|
1229
|
+
console.error("检查第三方库配置参数时出错:", error);
|
|
756
1230
|
return false;
|
|
757
1231
|
}
|
|
758
1232
|
};
|
|
@@ -766,59 +1240,125 @@ Detector.prototype._isThirdPartyConfigProperty = function (node, parent_node) {
|
|
|
766
1240
|
*/
|
|
767
1241
|
Detector.prototype._getPropType = function (val_node, prop_name, parent_node) {
|
|
768
1242
|
if (!val_node) {
|
|
769
|
-
return
|
|
1243
|
+
return "undefined_value"; // 未赋值类型
|
|
770
1244
|
}
|
|
771
1245
|
|
|
772
1246
|
// 检查是否为null值
|
|
773
|
-
if (val_node.type ===
|
|
774
|
-
return
|
|
1247
|
+
if (val_node.type === "NullLiteral") {
|
|
1248
|
+
return "null_value"; // null值类型
|
|
775
1249
|
}
|
|
776
1250
|
|
|
777
1251
|
// 检查是否为对象方法(在对象字面量中的函数)
|
|
778
1252
|
if (
|
|
779
1253
|
val_node &&
|
|
780
|
-
(val_node.type ===
|
|
781
|
-
val_node.type ===
|
|
1254
|
+
(val_node.type === "FunctionExpression" ||
|
|
1255
|
+
val_node.type === "ArrowFunctionExpression")
|
|
782
1256
|
) {
|
|
783
|
-
return
|
|
1257
|
+
return "method"; // 对象方法类型
|
|
784
1258
|
}
|
|
785
1259
|
|
|
786
1260
|
// 检查是否为类引用(属性类)
|
|
787
1261
|
if (
|
|
788
|
-
val_node.type ===
|
|
1262
|
+
val_node.type === "Identifier" &&
|
|
789
1263
|
val_node.name &&
|
|
790
1264
|
val_node.name[0] === val_node.name[0].toUpperCase()
|
|
791
1265
|
) {
|
|
792
1266
|
// 检查是否是特殊全局变量(如__dirname、__filename、process等)
|
|
793
|
-
var special_globals = [
|
|
1267
|
+
var special_globals = [
|
|
1268
|
+
"__dirname",
|
|
1269
|
+
"__filename",
|
|
1270
|
+
"process",
|
|
1271
|
+
"console",
|
|
1272
|
+
"module",
|
|
1273
|
+
"exports",
|
|
1274
|
+
"require",
|
|
1275
|
+
"global",
|
|
1276
|
+
];
|
|
794
1277
|
if (special_globals.includes(val_node.name)) {
|
|
795
|
-
return
|
|
1278
|
+
return "value"; // 特殊全局变量应该识别为属性值
|
|
796
1279
|
}
|
|
797
|
-
|
|
1280
|
+
|
|
798
1281
|
// 检查是否是类名引用(通常类名使用PascalCase)
|
|
799
|
-
return
|
|
1282
|
+
return "class"; // 属性类类型
|
|
800
1283
|
}
|
|
801
1284
|
|
|
802
1285
|
// 检查是否为类实例(new表达式)
|
|
803
|
-
if (val_node.type ===
|
|
804
|
-
return
|
|
1286
|
+
if (val_node.type === "NewExpression") {
|
|
1287
|
+
return "instance_class"; // 属性实例类类型
|
|
805
1288
|
}
|
|
806
1289
|
|
|
807
1290
|
// 检查是否为函数调用(可能返回实例)
|
|
808
|
-
if (val_node.type ===
|
|
1291
|
+
if (val_node.type === "CallExpression") {
|
|
809
1292
|
// 检查是否调用的是构造函数
|
|
810
1293
|
if (
|
|
811
1294
|
val_node.callee &&
|
|
812
|
-
val_node.callee.type ===
|
|
1295
|
+
val_node.callee.type === "Identifier" &&
|
|
813
1296
|
val_node.callee.name &&
|
|
814
1297
|
val_node.callee.name[0] === val_node.callee.name[0].toUpperCase()
|
|
815
1298
|
) {
|
|
816
|
-
return
|
|
1299
|
+
return "instance_class"; // 属性实例类类型
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
// 检查是否是工厂方法(返回实例)
|
|
1303
|
+
var factory_methods = ["create", "make", "build", "get", "fetch"];
|
|
1304
|
+
if (
|
|
1305
|
+
val_node.callee &&
|
|
1306
|
+
val_node.callee.type === "Identifier" &&
|
|
1307
|
+
factory_methods.some(function (method) {
|
|
1308
|
+
return val_node.callee.name.toLowerCase().startsWith(method);
|
|
1309
|
+
})
|
|
1310
|
+
) {
|
|
1311
|
+
return "instance_class"; // 工厂方法返回的实例
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
return "value"; // 默认值类型
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
// 检查是否为数组(包含对象实例)
|
|
1318
|
+
if (val_node.type === "ArrayExpression") {
|
|
1319
|
+
// 检查数组元素是否包含类实例
|
|
1320
|
+
if (val_node.elements && val_node.elements.length > 0) {
|
|
1321
|
+
var has_instance = val_node.elements.some(function (element) {
|
|
1322
|
+
return element && element.type === "NewExpression";
|
|
1323
|
+
});
|
|
1324
|
+
if (has_instance) {
|
|
1325
|
+
return "instance_class"; // 包含实例的数组
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
return "value"; // 普通数组
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
// 检查是否为对象字面量(可能包含类实例)
|
|
1332
|
+
if (val_node.type === "ObjectExpression") {
|
|
1333
|
+
// 检查对象属性是否包含类实例
|
|
1334
|
+
if (val_node.properties && val_node.properties.length > 0) {
|
|
1335
|
+
var has_instance = val_node.properties.some(function (property) {
|
|
1336
|
+
return (
|
|
1337
|
+
property && property.value && property.value.type === "NewExpression"
|
|
1338
|
+
);
|
|
1339
|
+
});
|
|
1340
|
+
if (has_instance) {
|
|
1341
|
+
return "instance_class"; // 包含实例的对象
|
|
1342
|
+
}
|
|
817
1343
|
}
|
|
818
|
-
return
|
|
1344
|
+
return "value"; // 普通对象
|
|
819
1345
|
}
|
|
820
1346
|
|
|
821
|
-
|
|
1347
|
+
// 检查是否为模板字面量(包含类实例)
|
|
1348
|
+
if (val_node.type === "TemplateLiteral") {
|
|
1349
|
+
// 检查模板表达式是否包含类实例
|
|
1350
|
+
if (val_node.expressions && val_node.expressions.length > 0) {
|
|
1351
|
+
var has_instance = val_node.expressions.some(function (expression) {
|
|
1352
|
+
return expression && expression.type === "NewExpression";
|
|
1353
|
+
});
|
|
1354
|
+
if (has_instance) {
|
|
1355
|
+
return "instance_class"; // 包含实例的模板
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
return "value"; // 普通模板
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
return "value";
|
|
822
1362
|
};
|
|
823
1363
|
|
|
824
1364
|
/**
|
|
@@ -837,131 +1377,195 @@ Detector.prototype._checkPropertyName = function (
|
|
|
837
1377
|
) {
|
|
838
1378
|
try {
|
|
839
1379
|
// 检查是否为解构导入中的属性
|
|
840
|
-
var is_destructured_import = this._isDestructuredImportProperty(
|
|
841
|
-
|
|
1380
|
+
var is_destructured_import = this._isDestructuredImportProperty(
|
|
1381
|
+
node,
|
|
1382
|
+
parent_node,
|
|
1383
|
+
);
|
|
1384
|
+
|
|
842
1385
|
// 如果是解构导入中的属性,则不进行属性名检测
|
|
843
1386
|
if (is_destructured_import) {
|
|
844
1387
|
return null;
|
|
845
1388
|
}
|
|
846
1389
|
|
|
847
1390
|
// 检查是否为第三方库的配置参数(方法调用中的对象字面量属性)
|
|
848
|
-
var is_third_party_config = this._isThirdPartyConfigProperty(
|
|
849
|
-
|
|
1391
|
+
var is_third_party_config = this._isThirdPartyConfigProperty(
|
|
1392
|
+
node,
|
|
1393
|
+
parent_node,
|
|
1394
|
+
);
|
|
1395
|
+
|
|
850
1396
|
// 如果是第三方库的配置参数,则不进行属性名检测
|
|
851
1397
|
if (is_third_party_config) {
|
|
852
1398
|
return null;
|
|
853
1399
|
}
|
|
854
1400
|
|
|
1401
|
+
// 检查是否为 module.exports 中的属性
|
|
1402
|
+
var is_module_exports = this._isModuleExportsProperty(node, parent_node);
|
|
1403
|
+
|
|
1404
|
+
// 如果是 module.exports 中的属性,则不进行属性名检测
|
|
1405
|
+
if (is_module_exports) {
|
|
1406
|
+
return null;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
855
1409
|
// 获取属性类型
|
|
856
1410
|
var prop_type = this._getPropType(val_node, prop_name, parent_node);
|
|
857
|
-
var rule_type =
|
|
1411
|
+
var rule_type = "";
|
|
858
1412
|
|
|
859
1413
|
// 根据属性类型选择对应的规则
|
|
860
1414
|
// 对于null值和未赋值属性,直接跳过命名规范检测
|
|
861
|
-
if (prop_type ===
|
|
1415
|
+
if (prop_type === "null_value" || prop_type === "undefined_value") {
|
|
862
1416
|
return null; // 不进行命名规范检测
|
|
863
1417
|
}
|
|
864
1418
|
|
|
865
1419
|
switch (prop_type) {
|
|
866
|
-
case
|
|
867
|
-
rule_type =
|
|
1420
|
+
case "class":
|
|
1421
|
+
rule_type = "property-class-name";
|
|
868
1422
|
break;
|
|
869
|
-
case
|
|
870
|
-
rule_type =
|
|
1423
|
+
case "instance_class":
|
|
1424
|
+
rule_type = "property-instance-class-name";
|
|
871
1425
|
break;
|
|
872
|
-
case
|
|
873
|
-
rule_type =
|
|
1426
|
+
case "method":
|
|
1427
|
+
rule_type = "property-method-name";
|
|
874
1428
|
break;
|
|
875
|
-
case
|
|
1429
|
+
case "value":
|
|
876
1430
|
default:
|
|
877
|
-
rule_type =
|
|
1431
|
+
rule_type = "property-value-name";
|
|
878
1432
|
break;
|
|
879
1433
|
}
|
|
880
1434
|
|
|
1435
|
+
// 将属性规则类型映射到对应的基础规则类型
|
|
1436
|
+
var base_rule_type = rule_type;
|
|
1437
|
+
if (rule_type.startsWith('property-')) {
|
|
1438
|
+
// 属性类名 -> 类名
|
|
1439
|
+
if (rule_type === 'property-class-name') {
|
|
1440
|
+
base_rule_type = 'class-name';
|
|
1441
|
+
}
|
|
1442
|
+
// 属性实例类名 -> 变量名
|
|
1443
|
+
else if (rule_type === 'property-instance-class-name') {
|
|
1444
|
+
base_rule_type = 'variable-name';
|
|
1445
|
+
}
|
|
1446
|
+
// 属性方法名 -> 方法名
|
|
1447
|
+
else if (rule_type === 'property-method-name') {
|
|
1448
|
+
base_rule_type = 'method-name';
|
|
1449
|
+
}
|
|
1450
|
+
// 属性值名 -> 变量名
|
|
1451
|
+
else if (rule_type === 'property-value-name') {
|
|
1452
|
+
base_rule_type = 'variable-name';
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
|
|
881
1456
|
// 检查忽略词
|
|
882
|
-
var ignored_words = this.config.getIgnoredWords(
|
|
1457
|
+
var ignored_words = this.config.getIgnoredWords(base_rule_type);
|
|
883
1458
|
if (ignored_words && ignored_words.includes(prop_name)) {
|
|
884
1459
|
return null; // 忽略词不进行命名规范检测
|
|
885
1460
|
}
|
|
886
1461
|
|
|
887
|
-
var rule = this.config.getRule(
|
|
1462
|
+
var rule = this.config.getRule(base_rule_type);
|
|
888
1463
|
if (!rule) {
|
|
889
1464
|
return null;
|
|
890
1465
|
}
|
|
891
1466
|
|
|
892
|
-
//
|
|
1467
|
+
// 首先检查命名风格
|
|
893
1468
|
var style_err = null;
|
|
894
|
-
|
|
895
|
-
if (rule_type ===
|
|
896
|
-
//
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
} else if (rule_type ===
|
|
906
|
-
//
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
// 属性实例类:支持公开实例类(camelCase)和私有实例类(_camelCase)
|
|
916
|
-
if (prop_name.startsWith('_')) {
|
|
917
|
-
// 私有实例类:检查是否符合私有实例类命名规范
|
|
918
|
-
style_err = this._validate_naming_style(prop_name, ['_camelCase'], rule_type);
|
|
919
|
-
} else {
|
|
920
|
-
// 公开实例类:检查是否符合公开实例类命名规范
|
|
921
|
-
style_err = this._validate_naming_style(prop_name, rule.styles, rule_type);
|
|
922
|
-
}
|
|
1469
|
+
|
|
1470
|
+
if (rule_type === "property-value-name") {
|
|
1471
|
+
// 对于属性值名,智能识别属性值类型并应用相应的命名规范
|
|
1472
|
+
style_err = this._checkPropertyValueStyle(prop_name, val_node, rule_type);
|
|
1473
|
+
} else if (rule_type === "property-method-name") {
|
|
1474
|
+
// 属性方法:智能识别方法类型并提供准确的命名规范
|
|
1475
|
+
style_err = this._checkPropertyMethodStyle(
|
|
1476
|
+
prop_name,
|
|
1477
|
+
val_node,
|
|
1478
|
+
rule_type,
|
|
1479
|
+
);
|
|
1480
|
+
} else if (rule_type === "property-instance-class-name") {
|
|
1481
|
+
// 属性实例类:智能识别实例类并提供准确的命名规范
|
|
1482
|
+
style_err = this._checkPropertyInstanceClassStyle(
|
|
1483
|
+
prop_name,
|
|
1484
|
+
val_node,
|
|
1485
|
+
rule_type,
|
|
1486
|
+
);
|
|
1487
|
+
} else if (rule_type === "property-class-name") {
|
|
1488
|
+
// 属性类:智能识别类引用并提供准确的命名规范
|
|
1489
|
+
style_err = this._checkPropertyClassStyle(prop_name, val_node, rule_type);
|
|
923
1490
|
} else {
|
|
924
1491
|
// 其他属性类型:使用原有逻辑
|
|
925
|
-
style_err = this._validate_naming_style(
|
|
1492
|
+
style_err = this._validate_naming_style(
|
|
1493
|
+
prop_name,
|
|
1494
|
+
rule.styles,
|
|
1495
|
+
rule_type,
|
|
1496
|
+
);
|
|
926
1497
|
}
|
|
927
1498
|
|
|
928
1499
|
if (style_err) {
|
|
929
1500
|
return {
|
|
930
1501
|
node: node,
|
|
931
1502
|
message: style_err,
|
|
1503
|
+
rule_type: rule_type, // 添加规则类型信息
|
|
932
1504
|
};
|
|
933
1505
|
}
|
|
934
1506
|
|
|
935
1507
|
// 检查长度
|
|
936
|
-
var len_err = this._checkNameLength(
|
|
1508
|
+
var len_err = this._checkNameLength(
|
|
1509
|
+
prop_name,
|
|
1510
|
+
rule.min,
|
|
1511
|
+
rule.max,
|
|
1512
|
+
rule_type,
|
|
1513
|
+
);
|
|
937
1514
|
if (len_err) {
|
|
1515
|
+
// 使用智能缩写生成推荐名称
|
|
1516
|
+
var smart_abbreviation = this._getSmartAbbreviation(prop_name, rule_type);
|
|
1517
|
+
var error_message = len_err;
|
|
1518
|
+
if (smart_abbreviation && smart_abbreviation !== prop_name) {
|
|
1519
|
+
error_message = len_err + ",建议使用: " + smart_abbreviation;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
938
1522
|
return {
|
|
939
1523
|
node: node,
|
|
940
|
-
message:
|
|
1524
|
+
message: error_message,
|
|
1525
|
+
rule_type: rule_type, // 添加规则类型信息
|
|
941
1526
|
};
|
|
942
1527
|
}
|
|
943
1528
|
|
|
944
1529
|
// 检查单词长度
|
|
945
|
-
var word_err = this._checkWordLength(
|
|
1530
|
+
var word_err = this._checkWordLength(
|
|
1531
|
+
prop_name,
|
|
1532
|
+
rule.single_word_len,
|
|
1533
|
+
rule_type,
|
|
1534
|
+
);
|
|
946
1535
|
if (word_err) {
|
|
1536
|
+
// 检查错误消息是否已经包含建议
|
|
1537
|
+
var error_message = word_err;
|
|
1538
|
+
if (!word_err.includes("建议使用")) {
|
|
1539
|
+
// 如果错误消息中不包含建议,则添加建议
|
|
1540
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
1541
|
+
prop_name,
|
|
1542
|
+
rule_type,
|
|
1543
|
+
);
|
|
1544
|
+
if (smart_abbreviation && smart_abbreviation !== prop_name) {
|
|
1545
|
+
error_message = word_err + ",建议使用: " + smart_abbreviation;
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
|
|
947
1549
|
return {
|
|
948
1550
|
node: node,
|
|
949
|
-
message:
|
|
1551
|
+
message: error_message,
|
|
1552
|
+
rule_type: rule_type, // 添加规则类型信息
|
|
950
1553
|
};
|
|
951
1554
|
}
|
|
952
1555
|
|
|
953
1556
|
// 检查禁止词汇
|
|
954
|
-
var forbid_err = this._checkForbiddenWords(prop_name,
|
|
1557
|
+
var forbid_err = this._checkForbiddenWords(prop_name, base_rule_type);
|
|
955
1558
|
if (forbid_err) {
|
|
956
1559
|
return {
|
|
957
1560
|
node: node,
|
|
958
1561
|
message: forbid_err,
|
|
1562
|
+
rule_type: rule_type, // 添加规则类型信息
|
|
959
1563
|
};
|
|
960
1564
|
}
|
|
961
1565
|
|
|
962
1566
|
return null;
|
|
963
1567
|
} catch (error) {
|
|
964
|
-
console.error(
|
|
1568
|
+
console.error("检测属性名时出错:", error);
|
|
965
1569
|
return null;
|
|
966
1570
|
}
|
|
967
1571
|
};
|
|
@@ -980,8 +1584,10 @@ Detector.prototype._checkAndRecommend = function (name, name_type) {
|
|
|
980
1584
|
}
|
|
981
1585
|
|
|
982
1586
|
var name_lower = name.toLowerCase();
|
|
1587
|
+
var is_private = name.startsWith("_");
|
|
1588
|
+
var name_without_prefix = is_private ? name.substring(1) : name;
|
|
1589
|
+
var name_without_prefix_lower = name_without_prefix.toLowerCase();
|
|
983
1590
|
|
|
984
|
-
var name_type_desc = this.config.name_type_map[name_type] || '名称';
|
|
985
1591
|
// 检查每个推荐词映射
|
|
986
1592
|
for (var rec_word in rec_words) {
|
|
987
1593
|
if (rec_words.hasOwnProperty(rec_word)) {
|
|
@@ -990,8 +1596,32 @@ Detector.prototype._checkAndRecommend = function (name, name_type) {
|
|
|
990
1596
|
// 检查名称是否包含任何一个原词
|
|
991
1597
|
for (var i = 0; i < original_words.length; i++) {
|
|
992
1598
|
var original_word = original_words[i].toLowerCase();
|
|
993
|
-
|
|
994
|
-
|
|
1599
|
+
|
|
1600
|
+
// 检查名称(去除私有前缀后)是否包含原词
|
|
1601
|
+
if (name_without_prefix_lower.includes(original_word)) {
|
|
1602
|
+
// 使用智能缩写生成完整的推荐名称
|
|
1603
|
+
var smart_abbreviation = this._getSmartAbbreviation(
|
|
1604
|
+
name,
|
|
1605
|
+
name_type,
|
|
1606
|
+
);
|
|
1607
|
+
var recommended_name =
|
|
1608
|
+
smart_abbreviation && smart_abbreviation !== name
|
|
1609
|
+
? smart_abbreviation
|
|
1610
|
+
: name;
|
|
1611
|
+
|
|
1612
|
+
return {
|
|
1613
|
+
type: "recommendation",
|
|
1614
|
+
message:
|
|
1615
|
+
"建议使用'" +
|
|
1616
|
+
recommended_name +
|
|
1617
|
+
"'替代'" +
|
|
1618
|
+
name +
|
|
1619
|
+
"'以获得更简洁的命名",
|
|
1620
|
+
recommended_name: recommended_name,
|
|
1621
|
+
original_name: name,
|
|
1622
|
+
original_word: original_words[i],
|
|
1623
|
+
recommended_word: rec_word,
|
|
1624
|
+
};
|
|
995
1625
|
}
|
|
996
1626
|
}
|
|
997
1627
|
}
|
|
@@ -999,7 +1629,7 @@ Detector.prototype._checkAndRecommend = function (name, name_type) {
|
|
|
999
1629
|
|
|
1000
1630
|
return null;
|
|
1001
1631
|
} catch (error) {
|
|
1002
|
-
console.error(
|
|
1632
|
+
console.error("检查并推荐更合适的词汇时出错:", error);
|
|
1003
1633
|
return null;
|
|
1004
1634
|
}
|
|
1005
1635
|
};
|
|
@@ -1019,17 +1649,17 @@ Detector.prototype._isBaseValue = function (val_node) {
|
|
|
1019
1649
|
var is_base_value = false;
|
|
1020
1650
|
|
|
1021
1651
|
switch (val_node.type) {
|
|
1022
|
-
case
|
|
1652
|
+
case "Literal": // 字面量:数字、字符串、布尔值
|
|
1023
1653
|
is_base_value = true;
|
|
1024
1654
|
break;
|
|
1025
|
-
case
|
|
1655
|
+
case "ArrayExpression": // 数组字面量
|
|
1026
1656
|
is_base_value = true;
|
|
1027
1657
|
break;
|
|
1028
|
-
case
|
|
1658
|
+
case "ObjectExpression": // 对象字面量
|
|
1029
1659
|
is_base_value = true;
|
|
1030
1660
|
break;
|
|
1031
|
-
case
|
|
1032
|
-
if (val_node.operator ===
|
|
1661
|
+
case "UnaryExpression": // 一元表达式(如 -1, +100)
|
|
1662
|
+
if (val_node.operator === "-" || val_node.operator === "+") {
|
|
1033
1663
|
is_base_value = true;
|
|
1034
1664
|
}
|
|
1035
1665
|
break;
|
|
@@ -1039,7 +1669,7 @@ Detector.prototype._isBaseValue = function (val_node) {
|
|
|
1039
1669
|
|
|
1040
1670
|
return is_base_value;
|
|
1041
1671
|
} catch (error) {
|
|
1042
|
-
console.error(
|
|
1672
|
+
console.error("检查值是否为基础值类型时出错:", error);
|
|
1043
1673
|
return false;
|
|
1044
1674
|
}
|
|
1045
1675
|
};
|
|
@@ -1056,22 +1686,51 @@ Detector.prototype._shouldUseLetInsteadOfConst = function (node, val_node) {
|
|
|
1056
1686
|
return false;
|
|
1057
1687
|
}
|
|
1058
1688
|
|
|
1689
|
+
// 检查是否为模块导入(需要排除的情况)
|
|
1690
|
+
var is_module_import = this._isModuleImport(node, val_node);
|
|
1691
|
+
if (is_module_import) {
|
|
1692
|
+
return false;
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1059
1695
|
// 检查是否为解构赋值
|
|
1060
1696
|
var is_destructuring = false;
|
|
1061
|
-
if (node.parent && node.parent.type ===
|
|
1697
|
+
if (node.parent && node.parent.type === "VariableDeclarator") {
|
|
1062
1698
|
var declarator = node.parent;
|
|
1063
|
-
if (
|
|
1699
|
+
if (
|
|
1700
|
+
declarator.id &&
|
|
1701
|
+
(declarator.id.type === "ObjectPattern" ||
|
|
1702
|
+
declarator.id.type === "ArrayPattern")
|
|
1703
|
+
) {
|
|
1064
1704
|
is_destructuring = true;
|
|
1065
1705
|
}
|
|
1066
1706
|
}
|
|
1067
1707
|
|
|
1068
|
-
//
|
|
1708
|
+
// 应该使用let的情况:
|
|
1709
|
+
// 1. 函数调用(CallExpression)- 返回值可能变化
|
|
1710
|
+
// 2. 变量引用(Identifier)- 可能被重新赋值
|
|
1711
|
+
// 3. 条件表达式等可能产生不同结果的情况
|
|
1712
|
+
|
|
1713
|
+
var should_use_let = false;
|
|
1714
|
+
|
|
1715
|
+
// 检查是否为函数调用
|
|
1716
|
+
if (val_node.type === "CallExpression") {
|
|
1717
|
+
should_use_let = true;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
// 检查是否为变量引用
|
|
1721
|
+
if (val_node.type === "Identifier") {
|
|
1722
|
+
should_use_let = true;
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
// 检查是否为解构赋值且右侧是复杂类型
|
|
1069
1726
|
var is_complex_type = this._isComplexType(val_node);
|
|
1727
|
+
if (is_destructuring && is_complex_type) {
|
|
1728
|
+
should_use_let = true;
|
|
1729
|
+
}
|
|
1070
1730
|
|
|
1071
|
-
|
|
1072
|
-
return is_destructuring && is_complex_type;
|
|
1731
|
+
return should_use_let;
|
|
1073
1732
|
} catch (error) {
|
|
1074
|
-
console.error(
|
|
1733
|
+
console.error("检查是否应该使用let时出错:", error);
|
|
1075
1734
|
return false;
|
|
1076
1735
|
}
|
|
1077
1736
|
};
|
|
@@ -1091,15 +1750,15 @@ Detector.prototype._isComplexType = function (val_node) {
|
|
|
1091
1750
|
var is_complex_type = false;
|
|
1092
1751
|
|
|
1093
1752
|
switch (val_node.type) {
|
|
1094
|
-
case
|
|
1095
|
-
case
|
|
1096
|
-
case
|
|
1097
|
-
case
|
|
1098
|
-
case
|
|
1099
|
-
case
|
|
1100
|
-
case
|
|
1101
|
-
case
|
|
1102
|
-
case
|
|
1753
|
+
case "FunctionExpression": // 函数表达式
|
|
1754
|
+
case "ArrowFunctionExpression": // 箭头函数
|
|
1755
|
+
case "NewExpression": // new 实例化
|
|
1756
|
+
case "CallExpression": // 函数调用
|
|
1757
|
+
case "MemberExpression": // 成员表达式
|
|
1758
|
+
case "Identifier": // 标识符(可能是变量或函数)
|
|
1759
|
+
case "ClassExpression": // 类表达式
|
|
1760
|
+
case "ThisExpression": // this表达式
|
|
1761
|
+
case "TemplateLiteral": // 模板字符串
|
|
1103
1762
|
is_complex_type = true;
|
|
1104
1763
|
break;
|
|
1105
1764
|
default:
|
|
@@ -1108,17 +1767,115 @@ Detector.prototype._isComplexType = function (val_node) {
|
|
|
1108
1767
|
|
|
1109
1768
|
return is_complex_type;
|
|
1110
1769
|
} catch (error) {
|
|
1111
|
-
console.error(
|
|
1770
|
+
console.error("检查值是否为复杂类型时出错:", error);
|
|
1112
1771
|
return false;
|
|
1113
1772
|
}
|
|
1114
1773
|
};
|
|
1115
1774
|
|
|
1116
1775
|
/**
|
|
1117
|
-
*
|
|
1118
|
-
* @param {object} node
|
|
1119
|
-
* @
|
|
1776
|
+
* 检查是否为模块导入(需要排除const检测的情况)
|
|
1777
|
+
* @param {object} node 变量声明节点
|
|
1778
|
+
* @param {object} val_node 值节点
|
|
1779
|
+
* @returns {boolean} 是否为模块导入
|
|
1120
1780
|
*/
|
|
1121
|
-
Detector.prototype.
|
|
1781
|
+
Detector.prototype._isModuleImport = function (node, val_node) {
|
|
1782
|
+
try {
|
|
1783
|
+
if (!node || !val_node) {
|
|
1784
|
+
return false;
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
// 情况1:const xxx = require('module') - 直接模块导入
|
|
1788
|
+
if (val_node.type === "CallExpression" && val_node.callee) {
|
|
1789
|
+
// 检查是否为require调用
|
|
1790
|
+
if (
|
|
1791
|
+
val_node.callee.type === "Identifier" &&
|
|
1792
|
+
val_node.callee.name === "require"
|
|
1793
|
+
) {
|
|
1794
|
+
return true;
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
// 检查是否为import()动态导入
|
|
1798
|
+
if (val_node.callee.type === "Import") {
|
|
1799
|
+
return true;
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
// 情况2:const {xxx} = require('module') - 解构模块导入
|
|
1804
|
+
if (node.parent && node.parent.type === "VariableDeclarator") {
|
|
1805
|
+
var declarator = node.parent;
|
|
1806
|
+
|
|
1807
|
+
// 检查是否为解构赋值
|
|
1808
|
+
if (declarator.id && declarator.id.type === "ObjectPattern") {
|
|
1809
|
+
// 检查右侧是否为require调用
|
|
1810
|
+
if (val_node.type === "CallExpression" && val_node.callee) {
|
|
1811
|
+
if (
|
|
1812
|
+
val_node.callee.type === "Identifier" &&
|
|
1813
|
+
val_node.callee.name === "require"
|
|
1814
|
+
) {
|
|
1815
|
+
return true;
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
return false;
|
|
1822
|
+
} catch (error) {
|
|
1823
|
+
console.error("检查是否为模块导入时出错:", error);
|
|
1824
|
+
return false;
|
|
1825
|
+
}
|
|
1826
|
+
};
|
|
1827
|
+
|
|
1828
|
+
/**
|
|
1829
|
+
* 检查标识符是否为模块导入变量
|
|
1830
|
+
* @param {object} node AST节点(Identifier类型)
|
|
1831
|
+
* @returns {boolean} 是否为模块导入变量
|
|
1832
|
+
*/
|
|
1833
|
+
Detector.prototype._isModuleImportVariable = function (node) {
|
|
1834
|
+
try {
|
|
1835
|
+
if (!node || node.type !== "Identifier") {
|
|
1836
|
+
return false;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
// 检查变量声明是否为模块导入
|
|
1840
|
+
if (node.parent && node.parent.parent) {
|
|
1841
|
+
var variable_declaration = node.parent.parent;
|
|
1842
|
+
|
|
1843
|
+
// 检查是否为const声明
|
|
1844
|
+
if (
|
|
1845
|
+
variable_declaration.type === "VariableDeclaration" &&
|
|
1846
|
+
variable_declaration.kind === "const"
|
|
1847
|
+
) {
|
|
1848
|
+
// 检查声明中是否有require调用
|
|
1849
|
+
var declarators = variable_declaration.declarations;
|
|
1850
|
+
for (var i = 0; i < declarators.length; i++) {
|
|
1851
|
+
var declarator = declarators[i];
|
|
1852
|
+
if (declarator.init && declarator.init.type === "CallExpression") {
|
|
1853
|
+
var init_call = declarator.init;
|
|
1854
|
+
if (
|
|
1855
|
+
init_call.callee &&
|
|
1856
|
+
init_call.callee.type === "Identifier" &&
|
|
1857
|
+
init_call.callee.name === "require"
|
|
1858
|
+
) {
|
|
1859
|
+
return true;
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
return false;
|
|
1867
|
+
} catch (error) {
|
|
1868
|
+
console.error("检查是否为模块导入变量时出错:", error);
|
|
1869
|
+
return false;
|
|
1870
|
+
}
|
|
1871
|
+
};
|
|
1872
|
+
|
|
1873
|
+
/**
|
|
1874
|
+
* 检查是否为解构导入
|
|
1875
|
+
* @param {object} node AST节点
|
|
1876
|
+
* @returns {boolean} 是否为解构导入
|
|
1877
|
+
*/
|
|
1878
|
+
Detector.prototype._isDestructuredImport = function (node) {
|
|
1122
1879
|
try {
|
|
1123
1880
|
if (!node || !node.parent) {
|
|
1124
1881
|
return false;
|
|
@@ -1128,56 +1885,63 @@ Detector.prototype._isDestructuredImport = function (node) {
|
|
|
1128
1885
|
var is_destructured = false;
|
|
1129
1886
|
|
|
1130
1887
|
// 情况1:节点是Property.key(解构赋值中的属性键)
|
|
1131
|
-
if (node.parent.type ===
|
|
1888
|
+
if (node.parent.type === "Property" && node.parent.key === node) {
|
|
1132
1889
|
var property = node.parent;
|
|
1133
|
-
|
|
1890
|
+
|
|
1134
1891
|
// 检查Property的父节点是否为ObjectPattern
|
|
1135
|
-
if (property.parent && property.parent.type ===
|
|
1892
|
+
if (property.parent && property.parent.type === "ObjectPattern") {
|
|
1136
1893
|
var object_pattern = property.parent;
|
|
1137
|
-
|
|
1894
|
+
|
|
1138
1895
|
// 检查ObjectPattern的父节点是否为VariableDeclarator
|
|
1139
|
-
if (
|
|
1896
|
+
if (
|
|
1897
|
+
object_pattern.parent &&
|
|
1898
|
+
object_pattern.parent.type === "VariableDeclarator"
|
|
1899
|
+
) {
|
|
1140
1900
|
var declarator = object_pattern.parent;
|
|
1141
|
-
|
|
1901
|
+
|
|
1142
1902
|
// 检查右侧是否为require调用或其他模块导入
|
|
1143
1903
|
if (declarator.init) {
|
|
1144
1904
|
var init_type = declarator.init.type;
|
|
1145
|
-
|
|
1905
|
+
|
|
1146
1906
|
// 常见的模块导入方式
|
|
1147
|
-
if (
|
|
1148
|
-
|
|
1149
|
-
|
|
1907
|
+
if (
|
|
1908
|
+
init_type === "CallExpression" &&
|
|
1909
|
+
declarator.init.callee &&
|
|
1910
|
+
declarator.init.callee.name === "require"
|
|
1911
|
+
) {
|
|
1150
1912
|
is_destructured = true;
|
|
1151
1913
|
}
|
|
1152
|
-
|
|
1914
|
+
|
|
1153
1915
|
// 如果是ImportDeclaration(ES6导入)
|
|
1154
|
-
if (init_type ===
|
|
1916
|
+
if (init_type === "ImportExpression") {
|
|
1155
1917
|
is_destructured = true;
|
|
1156
1918
|
}
|
|
1157
1919
|
}
|
|
1158
1920
|
}
|
|
1159
1921
|
}
|
|
1160
1922
|
}
|
|
1161
|
-
|
|
1923
|
+
|
|
1162
1924
|
// 情况2:节点是VariableDeclarator(简单变量声明)
|
|
1163
|
-
else if (node.parent.type ===
|
|
1925
|
+
else if (node.parent.type === "VariableDeclarator") {
|
|
1164
1926
|
var declarator = node.parent;
|
|
1165
|
-
|
|
1927
|
+
|
|
1166
1928
|
// 检查是否为解构模式(ObjectPattern或ArrayPattern)
|
|
1167
|
-
if (declarator.id && declarator.id.type ===
|
|
1929
|
+
if (declarator.id && declarator.id.type === "ObjectPattern") {
|
|
1168
1930
|
// 检查右侧是否为require调用或其他模块导入
|
|
1169
1931
|
if (declarator.init) {
|
|
1170
1932
|
var init_type = declarator.init.type;
|
|
1171
|
-
|
|
1933
|
+
|
|
1172
1934
|
// 常见的模块导入方式
|
|
1173
|
-
if (
|
|
1174
|
-
|
|
1175
|
-
|
|
1935
|
+
if (
|
|
1936
|
+
init_type === "CallExpression" &&
|
|
1937
|
+
declarator.init.callee &&
|
|
1938
|
+
declarator.init.callee.name === "require"
|
|
1939
|
+
) {
|
|
1176
1940
|
is_destructured = true;
|
|
1177
1941
|
}
|
|
1178
|
-
|
|
1942
|
+
|
|
1179
1943
|
// 如果是ImportDeclaration(ES6导入)
|
|
1180
|
-
if (init_type ===
|
|
1944
|
+
if (init_type === "ImportExpression") {
|
|
1181
1945
|
is_destructured = true;
|
|
1182
1946
|
}
|
|
1183
1947
|
}
|
|
@@ -1186,7 +1950,7 @@ Detector.prototype._isDestructuredImport = function (node) {
|
|
|
1186
1950
|
|
|
1187
1951
|
return is_destructured;
|
|
1188
1952
|
} catch (error) {
|
|
1189
|
-
console.error(
|
|
1953
|
+
console.error("检查是否为解构导入时出错:", error);
|
|
1190
1954
|
return false;
|
|
1191
1955
|
}
|
|
1192
1956
|
};
|
|
@@ -1197,31 +1961,137 @@ Detector.prototype._isDestructuredImport = function (node) {
|
|
|
1197
1961
|
* @param {object} parent_node 父节点
|
|
1198
1962
|
* @returns {boolean} 是否为解构导入中的属性
|
|
1199
1963
|
*/
|
|
1200
|
-
Detector.prototype._isDestructuredImportProperty = function (
|
|
1964
|
+
Detector.prototype._isDestructuredImportProperty = function (
|
|
1965
|
+
node,
|
|
1966
|
+
parent_node,
|
|
1967
|
+
) {
|
|
1201
1968
|
try {
|
|
1202
|
-
|
|
1969
|
+
// 处理新的父节点信息结构(包含node和parent属性)
|
|
1970
|
+
var actual_parent_node = parent_node;
|
|
1971
|
+
if (parent_node && typeof parent_node === "object" && parent_node.node) {
|
|
1972
|
+
actual_parent_node = parent_node.node;
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
if (!node || !actual_parent_node) {
|
|
1203
1976
|
return false;
|
|
1204
1977
|
}
|
|
1205
1978
|
|
|
1206
1979
|
// 检查父节点是否为ObjectPattern(解构模式)
|
|
1207
|
-
if (
|
|
1980
|
+
if (actual_parent_node.type === "ObjectPattern") {
|
|
1208
1981
|
// 检查父节点的父节点是否为VariableDeclarator
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1982
|
+
var actual_parent_parent =
|
|
1983
|
+
parent_node && typeof parent_node === "object" && parent_node.parent
|
|
1984
|
+
? parent_node.parent
|
|
1985
|
+
: actual_parent_node.parent;
|
|
1986
|
+
|
|
1987
|
+
if (
|
|
1988
|
+
actual_parent_parent &&
|
|
1989
|
+
actual_parent_parent.type === "VariableDeclarator"
|
|
1990
|
+
) {
|
|
1991
|
+
var declarator = actual_parent_parent;
|
|
1992
|
+
|
|
1212
1993
|
// 检查右侧是否为require调用或其他模块导入
|
|
1213
1994
|
if (declarator.init) {
|
|
1214
1995
|
var init_type = declarator.init.type;
|
|
1215
|
-
|
|
1996
|
+
|
|
1216
1997
|
// 常见的模块导入方式
|
|
1217
|
-
if (
|
|
1218
|
-
|
|
1219
|
-
|
|
1998
|
+
if (
|
|
1999
|
+
init_type === "CallExpression" &&
|
|
2000
|
+
declarator.init.callee &&
|
|
2001
|
+
declarator.init.callee.name === "require"
|
|
2002
|
+
) {
|
|
1220
2003
|
return true;
|
|
1221
2004
|
}
|
|
1222
|
-
|
|
2005
|
+
|
|
1223
2006
|
// 如果是ImportDeclaration(ES6导入)
|
|
1224
|
-
if (init_type ===
|
|
2007
|
+
if (init_type === "ImportExpression") {
|
|
2008
|
+
return true;
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
return false;
|
|
2015
|
+
} catch (error) {
|
|
2016
|
+
console.error("检查是否为解构导入中的属性时出错:", error);
|
|
2017
|
+
return false;
|
|
2018
|
+
}
|
|
2019
|
+
};
|
|
2020
|
+
|
|
2021
|
+
/**
|
|
2022
|
+
* 检查是否为函数赋值(函数表达式或箭头函数)
|
|
2023
|
+
* @param {object} node AST节点
|
|
2024
|
+
* @returns {boolean} 是否为函数赋值
|
|
2025
|
+
*/
|
|
2026
|
+
Detector.prototype._isFunctionAssignment = function (node) {
|
|
2027
|
+
try {
|
|
2028
|
+
if (!node) {
|
|
2029
|
+
return false;
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
// 检查节点是否为解构赋值中的属性
|
|
2033
|
+
if (node.type === "Property" && node.key === node) {
|
|
2034
|
+
// 检查父节点是否为ObjectPattern
|
|
2035
|
+
if (node.parent && node.parent.type === "ObjectPattern") {
|
|
2036
|
+
// 检查父节点的父节点是否为VariableDeclarator
|
|
2037
|
+
if (
|
|
2038
|
+
node.parent.parent &&
|
|
2039
|
+
node.parent.parent.type === "VariableDeclarator"
|
|
2040
|
+
) {
|
|
2041
|
+
var declarator = node.parent.parent;
|
|
2042
|
+
|
|
2043
|
+
// 检查右侧是否为函数表达式或箭头函数
|
|
2044
|
+
if (declarator.init) {
|
|
2045
|
+
var init_type = declarator.init.type;
|
|
2046
|
+
|
|
2047
|
+
// 函数表达式
|
|
2048
|
+
if (init_type === "FunctionExpression") {
|
|
2049
|
+
return true;
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
// 箭头函数
|
|
2053
|
+
if (init_type === "ArrowFunctionExpression") {
|
|
2054
|
+
return true;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
// 函数调用(可能返回函数)
|
|
2058
|
+
if (init_type === "CallExpression") {
|
|
2059
|
+
return true;
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
// 检查节点是否为解构赋值中的数组元素
|
|
2067
|
+
if (
|
|
2068
|
+
node.type === "Identifier" &&
|
|
2069
|
+
node.parent &&
|
|
2070
|
+
node.parent.type === "ArrayPattern"
|
|
2071
|
+
) {
|
|
2072
|
+
// 检查父节点的父节点是否为VariableDeclarator
|
|
2073
|
+
if (
|
|
2074
|
+
node.parent.parent &&
|
|
2075
|
+
node.parent.parent.type === "VariableDeclarator"
|
|
2076
|
+
) {
|
|
2077
|
+
var declarator = node.parent.parent;
|
|
2078
|
+
|
|
2079
|
+
// 检查右侧是否为函数表达式或箭头函数
|
|
2080
|
+
if (declarator.init) {
|
|
2081
|
+
var init_type = declarator.init.type;
|
|
2082
|
+
|
|
2083
|
+
// 函数表达式
|
|
2084
|
+
if (init_type === "FunctionExpression") {
|
|
2085
|
+
return true;
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
// 箭头函数
|
|
2089
|
+
if (init_type === "ArrowFunctionExpression") {
|
|
2090
|
+
return true;
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
// 函数调用(可能返回函数)
|
|
2094
|
+
if (init_type === "CallExpression") {
|
|
1225
2095
|
return true;
|
|
1226
2096
|
}
|
|
1227
2097
|
}
|
|
@@ -1230,7 +2100,7 @@ Detector.prototype._isDestructuredImportProperty = function (node, parent_node)
|
|
|
1230
2100
|
|
|
1231
2101
|
return false;
|
|
1232
2102
|
} catch (error) {
|
|
1233
|
-
console.error(
|
|
2103
|
+
console.error("检查是否为函数赋值时出错:", error);
|
|
1234
2104
|
return false;
|
|
1235
2105
|
}
|
|
1236
2106
|
};
|
|
@@ -1242,16 +2112,20 @@ Detector.prototype._isDestructuredImportProperty = function (node, parent_node)
|
|
|
1242
2112
|
*/
|
|
1243
2113
|
Detector.prototype._isConstantNameValid = function (constant_name) {
|
|
1244
2114
|
try {
|
|
1245
|
-
var rule = this.config.getRule(
|
|
2115
|
+
var rule = this.config.getRule("constant-name");
|
|
1246
2116
|
if (!rule) {
|
|
1247
2117
|
return false;
|
|
1248
2118
|
}
|
|
1249
2119
|
|
|
1250
2120
|
// 检查命名风格
|
|
1251
|
-
var style_err = this._validate_naming_style(
|
|
2121
|
+
var style_err = this._validate_naming_style(
|
|
2122
|
+
constant_name,
|
|
2123
|
+
rule.styles,
|
|
2124
|
+
"constant-name",
|
|
2125
|
+
);
|
|
1252
2126
|
return !style_err;
|
|
1253
2127
|
} catch (error) {
|
|
1254
|
-
console.error(
|
|
2128
|
+
console.error("检查常量名是否符合规范时出错:", error);
|
|
1255
2129
|
return false;
|
|
1256
2130
|
}
|
|
1257
2131
|
};
|
|
@@ -1277,8 +2151,8 @@ Detector.prototype._isIgnoredWord = function (name, name_type) {
|
|
|
1277
2151
|
}
|
|
1278
2152
|
|
|
1279
2153
|
return false;
|
|
1280
|
-
} catch (error) {
|
|
1281
|
-
console.error(
|
|
2154
|
+
} catch (error) {
|
|
2155
|
+
console.error("检查是否为忽略词时出错:", error);
|
|
1282
2156
|
return false;
|
|
1283
2157
|
}
|
|
1284
2158
|
};
|
|
@@ -1290,7 +2164,11 @@ Detector.prototype._isIgnoredWord = function (name, name_type) {
|
|
|
1290
2164
|
* @param {string} name_type 名称类型
|
|
1291
2165
|
* @returns {string|null} 推荐命名或null
|
|
1292
2166
|
*/
|
|
1293
|
-
Detector.prototype._generateRecommendedName = function (
|
|
2167
|
+
Detector.prototype._generateRecommendedName = function (
|
|
2168
|
+
original_name,
|
|
2169
|
+
long_word,
|
|
2170
|
+
name_type,
|
|
2171
|
+
) {
|
|
1294
2172
|
try {
|
|
1295
2173
|
// 获取推荐词映射
|
|
1296
2174
|
var recommended_words = this.config.getRecommendedWords(name_type);
|
|
@@ -1299,18 +2177,26 @@ Detector.prototype._generateRecommendedName = function (original_name, long_word
|
|
|
1299
2177
|
}
|
|
1300
2178
|
|
|
1301
2179
|
var long_word_lower = long_word.toLowerCase();
|
|
1302
|
-
|
|
2180
|
+
var is_private = original_name.startsWith("_");
|
|
2181
|
+
var original_name_without_prefix = is_private
|
|
2182
|
+
? original_name.substring(1)
|
|
2183
|
+
: original_name;
|
|
2184
|
+
|
|
1303
2185
|
// 检查推荐词映射中是否有对应的缩写
|
|
1304
2186
|
for (var short_word in recommended_words) {
|
|
1305
2187
|
if (recommended_words.hasOwnProperty(short_word)) {
|
|
1306
2188
|
var original_words = recommended_words[short_word];
|
|
1307
|
-
|
|
2189
|
+
|
|
1308
2190
|
// 检查过长的单词是否在推荐词的原词列表中
|
|
1309
2191
|
for (var i = 0; i < original_words.length; i++) {
|
|
1310
2192
|
var original_word = original_words[i].toLowerCase();
|
|
1311
2193
|
if (long_word_lower === original_word) {
|
|
1312
|
-
//
|
|
1313
|
-
var
|
|
2194
|
+
// 生成推荐命名:将原始名称中的长单词替换为推荐的缩写,保持私有前缀
|
|
2195
|
+
var recommended_name_without_prefix =
|
|
2196
|
+
original_name_without_prefix.replace(long_word, short_word);
|
|
2197
|
+
var recommended_name = is_private
|
|
2198
|
+
? "_" + recommended_name_without_prefix
|
|
2199
|
+
: recommended_name_without_prefix;
|
|
1314
2200
|
return recommended_name;
|
|
1315
2201
|
}
|
|
1316
2202
|
}
|
|
@@ -1319,85 +2205,1434 @@ Detector.prototype._generateRecommendedName = function (original_name, long_word
|
|
|
1319
2205
|
|
|
1320
2206
|
return null;
|
|
1321
2207
|
} catch (error) {
|
|
1322
|
-
console.error(
|
|
2208
|
+
console.error("生成推荐命名时出错:", error);
|
|
1323
2209
|
return null;
|
|
1324
2210
|
}
|
|
1325
2211
|
};
|
|
1326
2212
|
|
|
1327
2213
|
/**
|
|
1328
|
-
*
|
|
1329
|
-
* @param {string}
|
|
1330
|
-
* @param {
|
|
1331
|
-
* @
|
|
2214
|
+
* 转换命名风格
|
|
2215
|
+
* @param {string} name 原始名称
|
|
2216
|
+
* @param {string} target_style 目标命名风格
|
|
2217
|
+
* @param {string} name_type 名称类型
|
|
2218
|
+
* @returns {string} 转换后的名称
|
|
1332
2219
|
*/
|
|
1333
|
-
Detector.prototype.
|
|
2220
|
+
Detector.prototype._convertNamingStyle = function (
|
|
2221
|
+
name,
|
|
2222
|
+
target_style,
|
|
2223
|
+
name_type,
|
|
2224
|
+
) {
|
|
1334
2225
|
try {
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
return null;
|
|
2226
|
+
if (!name || !target_style) {
|
|
2227
|
+
return name;
|
|
1338
2228
|
}
|
|
1339
2229
|
|
|
1340
|
-
//
|
|
1341
|
-
|
|
1342
|
-
|
|
2230
|
+
// 处理私有标识符
|
|
2231
|
+
var has_private_prefix = name.startsWith("_");
|
|
2232
|
+
var processed_name = has_private_prefix ? name.substring(1) : name;
|
|
2233
|
+
|
|
2234
|
+
// 分割单词
|
|
2235
|
+
var words = this._splitNameIntoWords(processed_name);
|
|
2236
|
+
|
|
2237
|
+
// 过滤空字符串和私有标识符
|
|
2238
|
+
words = words.filter(function (word) {
|
|
2239
|
+
return word && word.length > 0 && word !== "_";
|
|
2240
|
+
});
|
|
2241
|
+
|
|
2242
|
+
if (words.length === 0) {
|
|
2243
|
+
return name;
|
|
1343
2244
|
}
|
|
1344
2245
|
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
2246
|
+
var converted_name = "";
|
|
2247
|
+
|
|
2248
|
+
// 根据目标风格转换
|
|
2249
|
+
switch (target_style) {
|
|
2250
|
+
case "camelCase":
|
|
2251
|
+
// 小驼峰命名法
|
|
2252
|
+
converted_name = words
|
|
2253
|
+
.map(function (word, index) {
|
|
2254
|
+
if (index === 0) {
|
|
2255
|
+
return word.toLowerCase();
|
|
2256
|
+
}
|
|
2257
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
2258
|
+
})
|
|
2259
|
+
.join("");
|
|
2260
|
+
break;
|
|
2261
|
+
|
|
2262
|
+
case "_camelCase":
|
|
2263
|
+
// 私有小驼峰命名法
|
|
2264
|
+
converted_name =
|
|
2265
|
+
"_" +
|
|
2266
|
+
words
|
|
2267
|
+
.map(function (word, index) {
|
|
2268
|
+
if (index === 0) {
|
|
2269
|
+
return word.toLowerCase();
|
|
2270
|
+
}
|
|
2271
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
2272
|
+
})
|
|
2273
|
+
.join("");
|
|
2274
|
+
break;
|
|
2275
|
+
|
|
2276
|
+
case "PascalCase":
|
|
2277
|
+
// 大驼峰命名法
|
|
2278
|
+
converted_name = words
|
|
2279
|
+
.map(function (word) {
|
|
2280
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
2281
|
+
})
|
|
2282
|
+
.join("");
|
|
2283
|
+
break;
|
|
2284
|
+
|
|
2285
|
+
case "snake_case":
|
|
2286
|
+
// 小写蛇形命名法
|
|
2287
|
+
converted_name = words
|
|
2288
|
+
.map(function (word) {
|
|
2289
|
+
return word.toLowerCase();
|
|
2290
|
+
})
|
|
2291
|
+
.join("_");
|
|
2292
|
+
break;
|
|
2293
|
+
|
|
2294
|
+
case "_snake_case":
|
|
2295
|
+
// 私有小写蛇形命名法
|
|
2296
|
+
converted_name =
|
|
2297
|
+
"_" +
|
|
2298
|
+
words
|
|
2299
|
+
.map(function (word) {
|
|
2300
|
+
return word.toLowerCase();
|
|
2301
|
+
})
|
|
2302
|
+
.join("_");
|
|
2303
|
+
break;
|
|
2304
|
+
|
|
2305
|
+
case "UPPER_SNAKE_CASE":
|
|
2306
|
+
// 大写蛇形命名法
|
|
2307
|
+
converted_name = words
|
|
2308
|
+
.map(function (word) {
|
|
2309
|
+
return word.toUpperCase();
|
|
2310
|
+
})
|
|
2311
|
+
.join("_");
|
|
2312
|
+
break;
|
|
2313
|
+
|
|
2314
|
+
default:
|
|
2315
|
+
converted_name = name;
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
// 如果原始名称有私有前缀但目标风格不是私有风格,则添加私有前缀
|
|
2319
|
+
if (
|
|
2320
|
+
has_private_prefix &&
|
|
2321
|
+
!target_style.startsWith("_") &&
|
|
2322
|
+
!converted_name.startsWith("_")
|
|
2323
|
+
) {
|
|
2324
|
+
converted_name = "_" + converted_name;
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
return converted_name;
|
|
2328
|
+
} catch (error) {
|
|
2329
|
+
console.error("转换命名风格时出错:", error);
|
|
2330
|
+
return name;
|
|
2331
|
+
}
|
|
2332
|
+
};
|
|
2333
|
+
|
|
2334
|
+
/**
|
|
2335
|
+
* 获取命名修复建议
|
|
2336
|
+
* @param {string} name 原始名称
|
|
2337
|
+
* @param {string} name_type 名称类型
|
|
2338
|
+
* @param {string} error_message 错误信息
|
|
2339
|
+
* @returns {object|null} 修复建议对象
|
|
2340
|
+
*/
|
|
2341
|
+
Detector.prototype._getFixSuggestion = function (
|
|
2342
|
+
name,
|
|
2343
|
+
name_type,
|
|
2344
|
+
error_message,
|
|
2345
|
+
) {
|
|
2346
|
+
try {
|
|
2347
|
+
var rule = this.config.getRule(name_type);
|
|
2348
|
+
if (!rule || !rule.styles || rule.styles.length === 0) {
|
|
1350
2349
|
return null;
|
|
1351
2350
|
}
|
|
1352
2351
|
|
|
1353
|
-
//
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
2352
|
+
// 根据名称类型智能选择目标风格
|
|
2353
|
+
var target_style = this._getSmartTargetStyle(name, name_type, rule.styles);
|
|
2354
|
+
|
|
2355
|
+
// 生成修复后的名称
|
|
2356
|
+
var fixed_name = this._convertNamingStyle(name, target_style, name_type);
|
|
2357
|
+
|
|
2358
|
+
// 优先检查错误消息中是否有建议使用的名称
|
|
2359
|
+
if (error_message && error_message.includes("建议使用:")) {
|
|
2360
|
+
// 从错误消息中提取建议的名称
|
|
2361
|
+
var suggestion_match = error_message.match(/建议使用:\s*([\w_]+)/);
|
|
2362
|
+
if (suggestion_match && suggestion_match[1]) {
|
|
2363
|
+
fixed_name = suggestion_match[1];
|
|
2364
|
+
|
|
2365
|
+
// 对于私有方法(以_开头),根据错误消息确定正确的命名风格
|
|
2366
|
+
if (name_type === "method-name" && fixed_name.startsWith("_")) {
|
|
2367
|
+
// 检查错误消息中是否指定了命名风格
|
|
2368
|
+
if (error_message.includes("_camelCase")) {
|
|
2369
|
+
target_style = "_camelCase";
|
|
2370
|
+
} else if (error_message.includes("_snake_case")) {
|
|
2371
|
+
target_style = "_snake_case";
|
|
2372
|
+
} else {
|
|
2373
|
+
// 默认使用_snake_case风格
|
|
2374
|
+
target_style = "_snake_case";
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
1359
2377
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
2378
|
+
// 验证建议的名称是否有效
|
|
2379
|
+
var suggestion_validation = this._validate_naming_style(
|
|
2380
|
+
fixed_name,
|
|
2381
|
+
[target_style],
|
|
2382
|
+
name_type,
|
|
2383
|
+
);
|
|
2384
|
+
|
|
2385
|
+
if (suggestion_validation) {
|
|
2386
|
+
// 建议的名称无效,回退到原始转换逻辑
|
|
2387
|
+
fixed_name = this._convertNamingStyle(name, target_style, name_type);
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
1367
2390
|
}
|
|
1368
2391
|
|
|
1369
|
-
//
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
2392
|
+
// 检查是否需要智能缩写(长度过长的问题)
|
|
2393
|
+
if (error_message && error_message.includes("长度过长")) {
|
|
2394
|
+
// 如果错误消息中已经有建议名称,使用建议名称
|
|
2395
|
+
if (error_message.includes("建议使用:")) {
|
|
2396
|
+
// 已经处理过建议名称,直接使用
|
|
2397
|
+
} else {
|
|
2398
|
+
// 如果没有建议名称,使用智能缩写
|
|
2399
|
+
fixed_name = this._getSmartAbbreviation(name, name_type);
|
|
2400
|
+
|
|
2401
|
+
// 如果智能缩写后名称仍然相同,则不提供修复建议
|
|
2402
|
+
if (fixed_name === name) {
|
|
2403
|
+
return null;
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2406
|
+
// 支持多次缩写直到满足长度要求
|
|
2407
|
+
var max_length = rule.max || 20;
|
|
2408
|
+
var current_name = fixed_name;
|
|
2409
|
+
var max_attempts = 5; // 最多尝试5次
|
|
2410
|
+
|
|
2411
|
+
for (var attempt = 0; attempt < max_attempts; attempt++) {
|
|
2412
|
+
if (current_name.length <= max_length) {
|
|
2413
|
+
break; // 长度满足要求,退出循环
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
var next_name = this._getSmartAbbreviation(current_name, name_type);
|
|
2417
|
+
if (next_name === current_name) {
|
|
2418
|
+
break; // 无法进一步缩写,退出循环
|
|
2419
|
+
}
|
|
2420
|
+
current_name = next_name;
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
fixed_name = current_name;
|
|
2424
|
+
}
|
|
2425
|
+
} else if (fixed_name === name) {
|
|
2426
|
+
// 其他情况下,转换后名称相同,不提供修复建议
|
|
2427
|
+
return null;
|
|
1376
2428
|
}
|
|
1377
2429
|
|
|
1378
|
-
//
|
|
1379
|
-
var
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
2430
|
+
// 检查修复后的名称是否仍然有错误
|
|
2431
|
+
var fixed_style_err = this._validate_naming_style(
|
|
2432
|
+
fixed_name,
|
|
2433
|
+
[target_style],
|
|
2434
|
+
name_type,
|
|
2435
|
+
);
|
|
2436
|
+
if (fixed_style_err) {
|
|
2437
|
+
// 修复后的名称仍然有错误,尝试其他风格
|
|
2438
|
+
for (var i = 1; i < rule.styles.length; i++) {
|
|
2439
|
+
var alternative_style = rule.styles[i];
|
|
2440
|
+
var alternative_name = this._convertNamingStyle(
|
|
2441
|
+
name,
|
|
2442
|
+
alternative_style,
|
|
2443
|
+
name_type,
|
|
2444
|
+
);
|
|
2445
|
+
var alternative_err = this._validate_naming_style(
|
|
2446
|
+
alternative_name,
|
|
2447
|
+
[alternative_style],
|
|
2448
|
+
name_type,
|
|
2449
|
+
);
|
|
2450
|
+
|
|
2451
|
+
if (!alternative_err) {
|
|
2452
|
+
fixed_name = alternative_name;
|
|
2453
|
+
target_style = alternative_style;
|
|
2454
|
+
break;
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
1385
2457
|
}
|
|
1386
2458
|
|
|
1387
|
-
//
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
2459
|
+
// 如果名称长度仍然过长,且错误消息中没有建议名称,进行智能缩写处理
|
|
2460
|
+
if (
|
|
2461
|
+
error_message &&
|
|
2462
|
+
error_message.includes("长度过长") &&
|
|
2463
|
+
!error_message.includes("建议使用:")
|
|
2464
|
+
) {
|
|
2465
|
+
fixed_name = this._getSmartAbbreviation(name, name_type);
|
|
1394
2466
|
}
|
|
1395
2467
|
|
|
1396
|
-
return
|
|
2468
|
+
return {
|
|
2469
|
+
fixed_name: fixed_name,
|
|
2470
|
+
target_style: target_style,
|
|
2471
|
+
};
|
|
1397
2472
|
} catch (error) {
|
|
1398
|
-
console.error(
|
|
2473
|
+
console.error("获取命名修复建议时出错:", error);
|
|
1399
2474
|
return null;
|
|
1400
2475
|
}
|
|
1401
2476
|
};
|
|
1402
2477
|
|
|
2478
|
+
/**
|
|
2479
|
+
* 智能缩写处理(针对长度过长的名称)
|
|
2480
|
+
* @param {string} name 原始名称
|
|
2481
|
+
* @param {string} name_type 名称类型
|
|
2482
|
+
* @returns {string} 缩写后的名称
|
|
2483
|
+
*/
|
|
2484
|
+
Detector.prototype._getSmartAbbreviation = function (name, name_type) {
|
|
2485
|
+
try {
|
|
2486
|
+
// 处理私有标识符
|
|
2487
|
+
var has_private_prefix = name.startsWith("_");
|
|
2488
|
+
var processed_name = has_private_prefix ? name.substring(1) : name;
|
|
2489
|
+
|
|
2490
|
+
// 分割单词
|
|
2491
|
+
var words = this._splitNameIntoWords(processed_name);
|
|
2492
|
+
|
|
2493
|
+
// 过滤空字符串
|
|
2494
|
+
words = words.filter(function (word) {
|
|
2495
|
+
return word && word.length > 0;
|
|
2496
|
+
});
|
|
2497
|
+
|
|
2498
|
+
if (words.length === 0) {
|
|
2499
|
+
return name;
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2502
|
+
// 获取配置中的推荐词映射
|
|
2503
|
+
var rec_words = {};
|
|
2504
|
+
if (
|
|
2505
|
+
this.config.getRecommendedWords &&
|
|
2506
|
+
typeof this.config.getRecommendedWords === "function"
|
|
2507
|
+
) {
|
|
2508
|
+
rec_words = this.config.getRecommendedWords(name_type);
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
// 获取配置中的禁止词列表(作为禁止拼接词)
|
|
2512
|
+
var forbidden_words = [];
|
|
2513
|
+
if (
|
|
2514
|
+
this.config.getForbiddenWords &&
|
|
2515
|
+
typeof this.config.getForbiddenWords === "function"
|
|
2516
|
+
) {
|
|
2517
|
+
forbidden_words = this.config.getForbiddenWords(name_type);
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
if (!rec_words || Object.keys(rec_words).length === 0) {
|
|
2521
|
+
return name;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
// 处理每个单词,使用推荐词替换
|
|
2525
|
+
var processed_words = [];
|
|
2526
|
+
for (var i = 0; i < words.length; i++) {
|
|
2527
|
+
var word = words[i];
|
|
2528
|
+
var word_lower = word.toLowerCase();
|
|
2529
|
+
var replaced = false;
|
|
2530
|
+
|
|
2531
|
+
// 检查是否需要替换为推荐词
|
|
2532
|
+
for (var rec_word in rec_words) {
|
|
2533
|
+
if (rec_words.hasOwnProperty(rec_word)) {
|
|
2534
|
+
var original_words = rec_words[rec_word];
|
|
2535
|
+
|
|
2536
|
+
for (var j = 0; j < original_words.length; j++) {
|
|
2537
|
+
var original_word = original_words[j].toLowerCase();
|
|
2538
|
+
|
|
2539
|
+
// 如果当前单词包含原词(不区分大小写),则替换为推荐词
|
|
2540
|
+
if (word_lower.includes(original_word)) {
|
|
2541
|
+
// 保持首字母大小写
|
|
2542
|
+
if (word[0] === word[0].toUpperCase()) {
|
|
2543
|
+
processed_words.push(
|
|
2544
|
+
rec_word[0].toUpperCase() + rec_word.substring(1),
|
|
2545
|
+
);
|
|
2546
|
+
} else {
|
|
2547
|
+
processed_words.push(rec_word);
|
|
2548
|
+
}
|
|
2549
|
+
replaced = true;
|
|
2550
|
+
break;
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
if (replaced) break;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
// 如果没有找到推荐词,检查是否为禁止拼接词
|
|
2559
|
+
if (!replaced) {
|
|
2560
|
+
var is_forbidden = false;
|
|
2561
|
+
for (var f = 0; f < forbidden_words.length; f++) {
|
|
2562
|
+
var forbidden_word = forbidden_words[f].toLowerCase();
|
|
2563
|
+
if (word_lower === forbidden_word) {
|
|
2564
|
+
is_forbidden = true;
|
|
2565
|
+
break;
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
|
|
2569
|
+
// 如果不是禁止拼接词,保留原词
|
|
2570
|
+
if (!is_forbidden) {
|
|
2571
|
+
processed_words.push(word);
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
// 根据名称类型确定目标风格
|
|
2577
|
+
var target_style = "camelCase";
|
|
2578
|
+
if (name_type === "constant-name") {
|
|
2579
|
+
target_style = "UPPER_SNAKE_CASE";
|
|
2580
|
+
} else if (
|
|
2581
|
+
name_type === "class-name" ||
|
|
2582
|
+
name_type === "property-class-name"
|
|
2583
|
+
) {
|
|
2584
|
+
target_style = "PascalCase";
|
|
2585
|
+
} else if (
|
|
2586
|
+
name_type === "variable-name" ||
|
|
2587
|
+
name_type === "property-value-name"
|
|
2588
|
+
) {
|
|
2589
|
+
target_style = "snake_case";
|
|
2590
|
+
}
|
|
2591
|
+
// 函数名、方法名等保持默认的 camelCase
|
|
2592
|
+
|
|
2593
|
+
var abbreviated_name = "";
|
|
2594
|
+
|
|
2595
|
+
switch (target_style) {
|
|
2596
|
+
case "camelCase":
|
|
2597
|
+
for (var k = 0; k < processed_words.length; k++) {
|
|
2598
|
+
if (k === 0) {
|
|
2599
|
+
abbreviated_name += processed_words[k].toLowerCase();
|
|
2600
|
+
} else {
|
|
2601
|
+
abbreviated_name +=
|
|
2602
|
+
processed_words[k][0].toUpperCase() +
|
|
2603
|
+
processed_words[k].substring(1).toLowerCase();
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
break;
|
|
2607
|
+
case "PascalCase":
|
|
2608
|
+
for (var l = 0; l < processed_words.length; l++) {
|
|
2609
|
+
abbreviated_name +=
|
|
2610
|
+
processed_words[l][0].toUpperCase() +
|
|
2611
|
+
processed_words[l].substring(1).toLowerCase();
|
|
2612
|
+
}
|
|
2613
|
+
break;
|
|
2614
|
+
case "snake_case":
|
|
2615
|
+
abbreviated_name = processed_words.join("_").toLowerCase();
|
|
2616
|
+
break;
|
|
2617
|
+
case "UPPER_SNAKE_CASE":
|
|
2618
|
+
abbreviated_name = processed_words.join("_").toUpperCase();
|
|
2619
|
+
break;
|
|
2620
|
+
default:
|
|
2621
|
+
abbreviated_name = processed_words.join("");
|
|
2622
|
+
}
|
|
2623
|
+
|
|
2624
|
+
// 恢复私有标识符
|
|
2625
|
+
if (has_private_prefix) {
|
|
2626
|
+
abbreviated_name = "_" + abbreviated_name;
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
// 检查长度:如果缩写后长度没有变短,尝试其他策略
|
|
2630
|
+
if (abbreviated_name.length >= name.length) {
|
|
2631
|
+
return name;
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
// 如果缩写后仍然超过最大长度,尝试进一步优化
|
|
2635
|
+
var max_length = 20;
|
|
2636
|
+
if (abbreviated_name.length > max_length) {
|
|
2637
|
+
// 策略1: 截断过长的单词
|
|
2638
|
+
var optimized_words = [];
|
|
2639
|
+
for (var k = 0; k < processed_words.length; k++) {
|
|
2640
|
+
var word = processed_words[k];
|
|
2641
|
+
if (word.length > 8) {
|
|
2642
|
+
// 截断过长的单词到8个字符
|
|
2643
|
+
optimized_words.push(word.substring(0, 8));
|
|
2644
|
+
} else {
|
|
2645
|
+
optimized_words.push(word);
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
// 重新生成名称
|
|
2650
|
+
var optimized_name = "";
|
|
2651
|
+
switch (target_style) {
|
|
2652
|
+
case "camelCase":
|
|
2653
|
+
for (var m = 0; m < optimized_words.length; m++) {
|
|
2654
|
+
if (m === 0) {
|
|
2655
|
+
optimized_name += optimized_words[m].toLowerCase();
|
|
2656
|
+
} else {
|
|
2657
|
+
optimized_name +=
|
|
2658
|
+
optimized_words[m][0].toUpperCase() +
|
|
2659
|
+
optimized_words[m].substring(1).toLowerCase();
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
break;
|
|
2663
|
+
case "PascalCase":
|
|
2664
|
+
for (var n = 0; n < optimized_words.length; n++) {
|
|
2665
|
+
optimized_name +=
|
|
2666
|
+
optimized_words[n][0].toUpperCase() +
|
|
2667
|
+
optimized_words[n].substring(1).toLowerCase();
|
|
2668
|
+
}
|
|
2669
|
+
break;
|
|
2670
|
+
case "snake_case":
|
|
2671
|
+
optimized_name = optimized_words.join("_").toLowerCase();
|
|
2672
|
+
break;
|
|
2673
|
+
case "UPPER_SNAKE_CASE":
|
|
2674
|
+
optimized_name = optimized_words.join("_").toUpperCase();
|
|
2675
|
+
break;
|
|
2676
|
+
default:
|
|
2677
|
+
optimized_name = optimized_words.join("");
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
// 恢复私有标识符
|
|
2681
|
+
if (has_private_prefix) {
|
|
2682
|
+
optimized_name = "_" + optimized_name;
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
// 如果优化后名称更短,使用优化后的名称
|
|
2686
|
+
if (optimized_name.length < abbreviated_name.length) {
|
|
2687
|
+
abbreviated_name = optimized_name;
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
// 如果仍然超过长度,尝试移除不重要的单词
|
|
2691
|
+
if (abbreviated_name.length > max_length && processed_words.length > 2) {
|
|
2692
|
+
// 保留前2个和后1个单词
|
|
2693
|
+
var important_words = [
|
|
2694
|
+
processed_words[0],
|
|
2695
|
+
processed_words[1],
|
|
2696
|
+
processed_words[processed_words.length - 1],
|
|
2697
|
+
];
|
|
2698
|
+
|
|
2699
|
+
// 根据目标风格生成简化名称
|
|
2700
|
+
var simplified_name = "";
|
|
2701
|
+
switch (target_style) {
|
|
2702
|
+
case "camelCase":
|
|
2703
|
+
for (var o = 0; o < important_words.length; o++) {
|
|
2704
|
+
if (o === 0) {
|
|
2705
|
+
simplified_name += important_words[o].toLowerCase();
|
|
2706
|
+
} else {
|
|
2707
|
+
simplified_name +=
|
|
2708
|
+
important_words[o][0].toUpperCase() +
|
|
2709
|
+
important_words[o].substring(1).toLowerCase();
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
break;
|
|
2713
|
+
case "PascalCase":
|
|
2714
|
+
for (var p = 0; p < important_words.length; p++) {
|
|
2715
|
+
simplified_name +=
|
|
2716
|
+
important_words[p][0].toUpperCase() +
|
|
2717
|
+
important_words[p].substring(1).toLowerCase();
|
|
2718
|
+
}
|
|
2719
|
+
break;
|
|
2720
|
+
case "snake_case":
|
|
2721
|
+
simplified_name = important_words.join("_").toLowerCase();
|
|
2722
|
+
break;
|
|
2723
|
+
case "UPPER_SNAKE_CASE":
|
|
2724
|
+
simplified_name = important_words.join("_").toUpperCase();
|
|
2725
|
+
break;
|
|
2726
|
+
default:
|
|
2727
|
+
simplified_name = important_words.join("");
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
// 恢复私有标识符
|
|
2731
|
+
if (has_private_prefix) {
|
|
2732
|
+
simplified_name = "_" + simplified_name;
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
// 如果简化后名称更短且不超过最大长度,使用简化后的名称
|
|
2736
|
+
if (
|
|
2737
|
+
simplified_name.length <= max_length &&
|
|
2738
|
+
simplified_name.length < abbreviated_name.length
|
|
2739
|
+
) {
|
|
2740
|
+
abbreviated_name = simplified_name;
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
return abbreviated_name;
|
|
2746
|
+
} catch (error) {
|
|
2747
|
+
console.error("智能缩写处理时出错:", error);
|
|
2748
|
+
return name;
|
|
2749
|
+
}
|
|
2750
|
+
};
|
|
2751
|
+
|
|
2752
|
+
/**
|
|
2753
|
+
* 智能选择目标命名风格
|
|
2754
|
+
* @param {string} name 原始名称
|
|
2755
|
+
* @param {string} name_type 名称类型
|
|
2756
|
+
* @param {array} available_styles 可用的命名风格
|
|
2757
|
+
* @returns {string} 目标命名风格
|
|
2758
|
+
*/
|
|
2759
|
+
Detector.prototype._getSmartTargetStyle = function (
|
|
2760
|
+
name,
|
|
2761
|
+
name_type,
|
|
2762
|
+
available_styles,
|
|
2763
|
+
) {
|
|
2764
|
+
try {
|
|
2765
|
+
// 默认使用第一个风格
|
|
2766
|
+
var target_style = available_styles[0];
|
|
2767
|
+
|
|
2768
|
+
// 根据名称类型和原始名称特征智能选择
|
|
2769
|
+
switch (name_type) {
|
|
2770
|
+
case "property-value-name":
|
|
2771
|
+
// 属性值:根据是否为私有属性和值类型选择风格
|
|
2772
|
+
if (name.startsWith("_")) {
|
|
2773
|
+
// 私有属性值:优先使用私有蛇形命名
|
|
2774
|
+
target_style =
|
|
2775
|
+
available_styles.find(function (style) {
|
|
2776
|
+
return style === "_snake_case";
|
|
2777
|
+
}) || target_style;
|
|
2778
|
+
} else {
|
|
2779
|
+
// 公开属性值:优先使用蛇形命名
|
|
2780
|
+
target_style =
|
|
2781
|
+
available_styles.find(function (style) {
|
|
2782
|
+
return style === "snake_case";
|
|
2783
|
+
}) || target_style;
|
|
2784
|
+
}
|
|
2785
|
+
break;
|
|
2786
|
+
|
|
2787
|
+
case "property-class-name":
|
|
2788
|
+
// 属性类:根据是否为私有类选择风格
|
|
2789
|
+
if (name.startsWith("_")) {
|
|
2790
|
+
// 私有属性类:优先使用私有大驼峰命名
|
|
2791
|
+
target_style =
|
|
2792
|
+
available_styles.find(function (style) {
|
|
2793
|
+
return style === "_PascalCase";
|
|
2794
|
+
}) || target_style;
|
|
2795
|
+
} else {
|
|
2796
|
+
// 公开属性类:优先使用大驼峰命名
|
|
2797
|
+
target_style =
|
|
2798
|
+
available_styles.find(function (style) {
|
|
2799
|
+
return style === "PascalCase";
|
|
2800
|
+
}) || target_style;
|
|
2801
|
+
}
|
|
2802
|
+
break;
|
|
2803
|
+
|
|
2804
|
+
case "property-instance-class-name":
|
|
2805
|
+
case "property-method-name":
|
|
2806
|
+
// 属性实例类和属性方法:根据是否为私有选择风格
|
|
2807
|
+
if (name.startsWith("_")) {
|
|
2808
|
+
// 私有实例类/方法:优先使用私有小驼峰命名
|
|
2809
|
+
target_style =
|
|
2810
|
+
available_styles.find(function (style) {
|
|
2811
|
+
return style === "_camelCase";
|
|
2812
|
+
}) || target_style;
|
|
2813
|
+
} else {
|
|
2814
|
+
// 公开实例类/方法:优先使用小驼峰命名
|
|
2815
|
+
target_style =
|
|
2816
|
+
available_styles.find(function (style) {
|
|
2817
|
+
return style === "camelCase";
|
|
2818
|
+
}) || target_style;
|
|
2819
|
+
}
|
|
2820
|
+
break;
|
|
2821
|
+
|
|
2822
|
+
default:
|
|
2823
|
+
// 其他类型:使用默认风格
|
|
2824
|
+
target_style = available_styles[0];
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2827
|
+
return target_style;
|
|
2828
|
+
} catch (error) {
|
|
2829
|
+
console.error("智能选择目标命名风格时出错:", error);
|
|
2830
|
+
return available_styles[0];
|
|
2831
|
+
}
|
|
2832
|
+
};
|
|
2833
|
+
|
|
2834
|
+
/**
|
|
2835
|
+
* 检测解构赋值中的常量名
|
|
2836
|
+
* @param {string} constant_name 常量名
|
|
2837
|
+
* @param {object} node AST节点
|
|
2838
|
+
* @returns {object|null} 错误信息或null
|
|
2839
|
+
*/
|
|
2840
|
+
Detector.prototype._checkConstantNameForDestructuring = function (
|
|
2841
|
+
constant_name,
|
|
2842
|
+
node,
|
|
2843
|
+
) {
|
|
2844
|
+
try {
|
|
2845
|
+
// 解构赋值中的变量应该使用变量规则,而不是常量规则
|
|
2846
|
+
var rule = this.config.getRule("variable-name");
|
|
2847
|
+
if (!rule) {
|
|
2848
|
+
return null;
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2851
|
+
// 检查是否为忽略词
|
|
2852
|
+
if (this._isIgnoredWord(constant_name, "variable-name")) {
|
|
2853
|
+
return null;
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2856
|
+
// 检查是否为解构导入(从模块导入的变量)
|
|
2857
|
+
var is_destructured_import = this._isDestructuredImport(node);
|
|
2858
|
+
|
|
2859
|
+
// 如果是解构导入,则不进行变量检测
|
|
2860
|
+
if (is_destructured_import) {
|
|
2861
|
+
return null;
|
|
2862
|
+
}
|
|
2863
|
+
|
|
2864
|
+
// 检查是否为函数赋值(函数表达式或箭头函数)
|
|
2865
|
+
var is_function_assignment = this._isFunctionAssignment(node);
|
|
2866
|
+
|
|
2867
|
+
// 如果是函数赋值,允许camelCase命名风格
|
|
2868
|
+
var allowed_styles = [];
|
|
2869
|
+
if (is_function_assignment) {
|
|
2870
|
+
allowed_styles = ["camelCase", "UPPER_SNAKE_CASE"];
|
|
2871
|
+
} else {
|
|
2872
|
+
allowed_styles = rule.styles;
|
|
2873
|
+
}
|
|
2874
|
+
|
|
2875
|
+
// 检查命名风格
|
|
2876
|
+
var style_err = this._validate_naming_style(
|
|
2877
|
+
constant_name,
|
|
2878
|
+
allowed_styles,
|
|
2879
|
+
"variable-name",
|
|
2880
|
+
);
|
|
2881
|
+
if (style_err) {
|
|
2882
|
+
return {
|
|
2883
|
+
node: node,
|
|
2884
|
+
message: style_err,
|
|
2885
|
+
};
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
// 检查并推荐更合适的词汇(作为命名风格检查的补充)
|
|
2889
|
+
var recommend_info = this._checkAndRecommend(
|
|
2890
|
+
constant_name,
|
|
2891
|
+
"variable-name",
|
|
2892
|
+
);
|
|
2893
|
+
if (recommend_info) {
|
|
2894
|
+
// 如果有推荐建议,在错误消息中提示可以使用更简洁的词汇
|
|
2895
|
+
return {
|
|
2896
|
+
node: node,
|
|
2897
|
+
message:
|
|
2898
|
+
"变量名'" +
|
|
2899
|
+
constant_name +
|
|
2900
|
+
"'长度过长,最大长度为20字符,建议使用: " +
|
|
2901
|
+
recommend_info.recommended_name,
|
|
2902
|
+
};
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
// 检查长度
|
|
2906
|
+
var len_err = this._checkNameLength(
|
|
2907
|
+
constant_name,
|
|
2908
|
+
rule.min,
|
|
2909
|
+
rule.max,
|
|
2910
|
+
"variable-name",
|
|
2911
|
+
);
|
|
2912
|
+
if (len_err) {
|
|
2913
|
+
return {
|
|
2914
|
+
node: node,
|
|
2915
|
+
message: len_err,
|
|
2916
|
+
};
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2919
|
+
// 检查单词长度
|
|
2920
|
+
var word_err = this._checkWordLength(
|
|
2921
|
+
constant_name,
|
|
2922
|
+
rule.single_word_len,
|
|
2923
|
+
"constant-name",
|
|
2924
|
+
);
|
|
2925
|
+
if (word_err) {
|
|
2926
|
+
return {
|
|
2927
|
+
node: node,
|
|
2928
|
+
message: word_err,
|
|
2929
|
+
};
|
|
2930
|
+
}
|
|
2931
|
+
|
|
2932
|
+
// 检查禁止词汇
|
|
2933
|
+
var forbid_err = this._checkForbiddenWords(constant_name, "constant-name");
|
|
2934
|
+
if (forbid_err) {
|
|
2935
|
+
return {
|
|
2936
|
+
node: node,
|
|
2937
|
+
message: forbid_err,
|
|
2938
|
+
};
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
return null;
|
|
2942
|
+
} catch (error) {
|
|
2943
|
+
console.error("检测解构赋值常量名时出错:", error);
|
|
2944
|
+
return null;
|
|
2945
|
+
}
|
|
2946
|
+
};
|
|
2947
|
+
|
|
2948
|
+
/**
|
|
2949
|
+
* 检查属性值命名风格
|
|
2950
|
+
* @param {string} prop_name 属性名
|
|
2951
|
+
* @param {object} val_node 属性值节点
|
|
2952
|
+
* @param {string} rule_type 规则类型
|
|
2953
|
+
* @returns {string|null} 错误信息或null
|
|
2954
|
+
*/
|
|
2955
|
+
Detector.prototype._checkPropertyValueStyle = function (
|
|
2956
|
+
prop_name,
|
|
2957
|
+
val_node,
|
|
2958
|
+
rule_type,
|
|
2959
|
+
) {
|
|
2960
|
+
try {
|
|
2961
|
+
// 首先检查禁止拼接词
|
|
2962
|
+
var forbid_err = this._checkForbiddenWords(prop_name, "variable-name");
|
|
2963
|
+
if (forbid_err) {
|
|
2964
|
+
return forbid_err;
|
|
2965
|
+
}
|
|
2966
|
+
|
|
2967
|
+
// 检查属性值类型,智能选择命名规范
|
|
2968
|
+
var is_constant_value = this._isConstantValue(val_node);
|
|
2969
|
+
var is_private_property = prop_name.startsWith("_");
|
|
2970
|
+
|
|
2971
|
+
// 属性值应该允许满足常量或变量命名规则之一即可
|
|
2972
|
+
// 构建允许的命名风格列表
|
|
2973
|
+
var allowed_styles = [];
|
|
2974
|
+
|
|
2975
|
+
// 常量值:允许常量命名规范
|
|
2976
|
+
if (is_constant_value) {
|
|
2977
|
+
allowed_styles.push("UPPER_SNAKE_CASE");
|
|
2978
|
+
}
|
|
2979
|
+
|
|
2980
|
+
// 私有属性:允许私有变量命名规范
|
|
2981
|
+
if (is_private_property) {
|
|
2982
|
+
allowed_styles.push("_snake_case");
|
|
2983
|
+
}
|
|
2984
|
+
|
|
2985
|
+
// 普通属性值:允许变量命名规范
|
|
2986
|
+
allowed_styles.push("snake_case");
|
|
2987
|
+
|
|
2988
|
+
// 检查命名风格 - 只要满足其中一种风格即可
|
|
2989
|
+
for (var i = 0; i < allowed_styles.length; i++) {
|
|
2990
|
+
var style_check = this._validate_naming_style(
|
|
2991
|
+
prop_name,
|
|
2992
|
+
[allowed_styles[i]],
|
|
2993
|
+
rule_type,
|
|
2994
|
+
);
|
|
2995
|
+
if (!style_check) {
|
|
2996
|
+
// 当前风格符合要求,无需报错
|
|
2997
|
+
return null;
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
// 所有风格都不符合,生成错误信息
|
|
3002
|
+
var style_names = allowed_styles.join("、");
|
|
3003
|
+
|
|
3004
|
+
return (
|
|
3005
|
+
"属性值名'" + prop_name + "'不符合" + style_names + "命名风格中的任何一种"
|
|
3006
|
+
);
|
|
3007
|
+
} catch (error) {
|
|
3008
|
+
console.error("检查属性值命名风格时出错:", error);
|
|
3009
|
+
return null;
|
|
3010
|
+
}
|
|
3011
|
+
};
|
|
3012
|
+
|
|
3013
|
+
/**
|
|
3014
|
+
* 检查属性方法命名风格
|
|
3015
|
+
* @param {string} prop_name 属性名
|
|
3016
|
+
* @param {object} val_node 属性值节点
|
|
3017
|
+
* @param {string} rule_type 规则类型
|
|
3018
|
+
* @returns {string|null} 错误信息或null
|
|
3019
|
+
*/
|
|
3020
|
+
Detector.prototype._checkPropertyMethodStyle = function (
|
|
3021
|
+
prop_name,
|
|
3022
|
+
val_node,
|
|
3023
|
+
rule_type,
|
|
3024
|
+
) {
|
|
3025
|
+
try {
|
|
3026
|
+
// 首先检查禁止拼接词 - 使用 method-name 规则类型
|
|
3027
|
+
var forbid_err = this._checkForbiddenWords(prop_name, "method-name");
|
|
3028
|
+
if (forbid_err) {
|
|
3029
|
+
return forbid_err;
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
// 检查是否为私有属性方法
|
|
3033
|
+
var is_private_method = prop_name.startsWith("_");
|
|
3034
|
+
|
|
3035
|
+
// 属性方法应该允许满足公开方法或私有方法命名规则之一即可
|
|
3036
|
+
// 构建允许的命名风格列表
|
|
3037
|
+
var allowed_styles = [];
|
|
3038
|
+
|
|
3039
|
+
// 私有属性方法:允许私有方法命名规范
|
|
3040
|
+
if (is_private_method) {
|
|
3041
|
+
allowed_styles.push("_camelCase");
|
|
3042
|
+
}
|
|
3043
|
+
|
|
3044
|
+
// 公开属性方法:允许公开方法命名规范
|
|
3045
|
+
allowed_styles.push("camelCase");
|
|
3046
|
+
|
|
3047
|
+
// 检查命名风格 - 只要满足其中一种风格即可
|
|
3048
|
+
for (var i = 0; i < allowed_styles.length; i++) {
|
|
3049
|
+
var style_check = this._validate_naming_style(
|
|
3050
|
+
prop_name,
|
|
3051
|
+
[allowed_styles[i]],
|
|
3052
|
+
rule_type,
|
|
3053
|
+
);
|
|
3054
|
+
if (!style_check) {
|
|
3055
|
+
// 当前风格符合要求,无需报错
|
|
3056
|
+
return null;
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
// 所有风格都不符合,生成错误信息
|
|
3061
|
+
var style_names = allowed_styles.join("、");
|
|
3062
|
+
|
|
3063
|
+
return (
|
|
3064
|
+
"属性方法名'" + prop_name + "'不符合" + style_names + "命名风格中的任何一种"
|
|
3065
|
+
);
|
|
3066
|
+
} catch (error) {
|
|
3067
|
+
console.error("检查属性方法命名风格时出错:", error);
|
|
3068
|
+
return null;
|
|
3069
|
+
}
|
|
3070
|
+
};
|
|
3071
|
+
|
|
3072
|
+
/**
|
|
3073
|
+
* 检查属性实例类命名风格
|
|
3074
|
+
* @param {string} prop_name 属性名
|
|
3075
|
+
* @param {object} val_node 属性值节点
|
|
3076
|
+
* @param {string} rule_type 规则类型
|
|
3077
|
+
* @returns {string|null} 错误信息或null
|
|
3078
|
+
*/
|
|
3079
|
+
Detector.prototype._checkPropertyInstanceClassStyle = function (
|
|
3080
|
+
prop_name,
|
|
3081
|
+
val_node,
|
|
3082
|
+
rule_type,
|
|
3083
|
+
) {
|
|
3084
|
+
try {
|
|
3085
|
+
// 首先检查禁止拼接词
|
|
3086
|
+
var forbid_err = this._checkForbiddenWords(prop_name, "method-name");
|
|
3087
|
+
if (forbid_err) {
|
|
3088
|
+
return forbid_err;
|
|
3089
|
+
}
|
|
3090
|
+
|
|
3091
|
+
// 检查是否为私有属性实例类
|
|
3092
|
+
var is_private_instance = prop_name.startsWith("_");
|
|
3093
|
+
|
|
3094
|
+
// 属性类实例应该允许满足公开或私有命名规则之一即可
|
|
3095
|
+
// 构建允许的命名风格列表
|
|
3096
|
+
var allowed_styles = [];
|
|
3097
|
+
|
|
3098
|
+
// 私有属性实例类:允许私有实例类命名规范
|
|
3099
|
+
if (is_private_instance) {
|
|
3100
|
+
allowed_styles.push("_camelCase");
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
// 公开属性实例类:允许公开实例类命名规范
|
|
3104
|
+
allowed_styles.push("camelCase");
|
|
3105
|
+
|
|
3106
|
+
// 检查命名风格 - 只要满足其中一种风格即可
|
|
3107
|
+
for (var i = 0; i < allowed_styles.length; i++) {
|
|
3108
|
+
var style_check = this._validate_naming_style(
|
|
3109
|
+
prop_name,
|
|
3110
|
+
[allowed_styles[i]],
|
|
3111
|
+
rule_type,
|
|
3112
|
+
);
|
|
3113
|
+
if (!style_check) {
|
|
3114
|
+
// 当前风格符合要求,无需报错
|
|
3115
|
+
return null;
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
|
|
3119
|
+
// 所有风格都不符合,生成错误信息
|
|
3120
|
+
var style_names = allowed_styles.join("、");
|
|
3121
|
+
|
|
3122
|
+
return (
|
|
3123
|
+
"属性实例类名'" +
|
|
3124
|
+
prop_name +
|
|
3125
|
+
"'不符合" +
|
|
3126
|
+
style_names +
|
|
3127
|
+
"命名风格中的任何一种"
|
|
3128
|
+
);
|
|
3129
|
+
} catch (error) {
|
|
3130
|
+
console.error("检查属性实例类命名风格时出错:", error);
|
|
3131
|
+
return null;
|
|
3132
|
+
}
|
|
3133
|
+
};
|
|
3134
|
+
|
|
3135
|
+
/**
|
|
3136
|
+
* 检查属性类命名风格
|
|
3137
|
+
* @param {string} prop_name 属性名
|
|
3138
|
+
* @param {object} val_node 属性值节点
|
|
3139
|
+
* @param {string} rule_type 规则类型
|
|
3140
|
+
* @returns {string|null} 错误信息或null
|
|
3141
|
+
*/
|
|
3142
|
+
Detector.prototype._checkPropertyClassStyle = function (
|
|
3143
|
+
prop_name,
|
|
3144
|
+
val_node,
|
|
3145
|
+
rule_type,
|
|
3146
|
+
) {
|
|
3147
|
+
try {
|
|
3148
|
+
// 首先检查禁止拼接词
|
|
3149
|
+
var forbid_err = this._checkForbiddenWords(prop_name, "class-name");
|
|
3150
|
+
if (forbid_err) {
|
|
3151
|
+
return forbid_err;
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
// 检查是否为私有属性类
|
|
3155
|
+
var is_private_class = prop_name.startsWith("_");
|
|
3156
|
+
|
|
3157
|
+
// 根据属性类类型选择合适的命名规范
|
|
3158
|
+
var allowed_styles = [];
|
|
3159
|
+
|
|
3160
|
+
if (is_private_class) {
|
|
3161
|
+
// 私有属性类:使用私有类命名规范
|
|
3162
|
+
allowed_styles = ["_PascalCase"];
|
|
3163
|
+
} else {
|
|
3164
|
+
// 公开属性类:使用类命名规范
|
|
3165
|
+
allowed_styles = ["PascalCase"];
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
// 检查命名风格
|
|
3169
|
+
var style_err = null;
|
|
3170
|
+
for (var i = 0; i < allowed_styles.length; i++) {
|
|
3171
|
+
var style_check = this._validate_naming_style(
|
|
3172
|
+
prop_name,
|
|
3173
|
+
[allowed_styles[i]],
|
|
3174
|
+
rule_type,
|
|
3175
|
+
);
|
|
3176
|
+
if (!style_check) {
|
|
3177
|
+
// 当前风格符合要求,无需报错
|
|
3178
|
+
return null;
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
// 所有风格都不符合,生成错误信息
|
|
3183
|
+
var style_names = allowed_styles.join("、");
|
|
3184
|
+
|
|
3185
|
+
return (
|
|
3186
|
+
"属性类名'" + prop_name + "'不符合" + style_names + "命名风格中的任何一种"
|
|
3187
|
+
);
|
|
3188
|
+
} catch (error) {
|
|
3189
|
+
console.error("检查属性类命名风格时出错:", error);
|
|
3190
|
+
return null;
|
|
3191
|
+
}
|
|
3192
|
+
};
|
|
3193
|
+
|
|
3194
|
+
/**
|
|
3195
|
+
* 检查是否为常量值
|
|
3196
|
+
* @param {object} val_node 属性值节点
|
|
3197
|
+
* @returns {boolean} 是否为常量值
|
|
3198
|
+
*/
|
|
3199
|
+
Detector.prototype._isConstantValue = function (val_node) {
|
|
3200
|
+
try {
|
|
3201
|
+
if (!val_node) {
|
|
3202
|
+
return false;
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
// 常量值类型:字面量、基础值、不可变值
|
|
3206
|
+
var is_constant = false;
|
|
3207
|
+
|
|
3208
|
+
switch (val_node.type) {
|
|
3209
|
+
case "Literal": // 字面量:数字、字符串、布尔值
|
|
3210
|
+
is_constant = true;
|
|
3211
|
+
break;
|
|
3212
|
+
case "UnaryExpression": // 一元表达式(如 -1, +100)
|
|
3213
|
+
if (val_node.operator === "-" || val_node.operator === "+") {
|
|
3214
|
+
is_constant = true;
|
|
3215
|
+
}
|
|
3216
|
+
break;
|
|
3217
|
+
case "ArrayExpression": // 数组字面量(空数组或包含常量值的数组)
|
|
3218
|
+
if (!val_node.elements || val_node.elements.length === 0) {
|
|
3219
|
+
is_constant = true;
|
|
3220
|
+
} else {
|
|
3221
|
+
// 检查数组元素是否都是常量值
|
|
3222
|
+
is_constant = val_node.elements.every(function (element) {
|
|
3223
|
+
return this._isConstantValue(element);
|
|
3224
|
+
}, this);
|
|
3225
|
+
}
|
|
3226
|
+
break;
|
|
3227
|
+
case "ObjectExpression": // 对象字面量(空对象或包含常量值的对象)
|
|
3228
|
+
if (!val_node.properties || val_node.properties.length === 0) {
|
|
3229
|
+
is_constant = true;
|
|
3230
|
+
} else {
|
|
3231
|
+
// 检查对象属性值是否都是常量值
|
|
3232
|
+
is_constant = val_node.properties.every(function (property) {
|
|
3233
|
+
return (
|
|
3234
|
+
property &&
|
|
3235
|
+
property.value &&
|
|
3236
|
+
this._isConstantValue(property.value)
|
|
3237
|
+
);
|
|
3238
|
+
}, this);
|
|
3239
|
+
}
|
|
3240
|
+
break;
|
|
3241
|
+
case "TemplateLiteral": // 模板字面量(包含常量值的模板)
|
|
3242
|
+
if (!val_node.expressions || val_node.expressions.length === 0) {
|
|
3243
|
+
is_constant = true;
|
|
3244
|
+
} else {
|
|
3245
|
+
// 检查模板表达式是否都是常量值
|
|
3246
|
+
is_constant = val_node.expressions.every(function (expression) {
|
|
3247
|
+
return this._isConstantValue(expression);
|
|
3248
|
+
}, this);
|
|
3249
|
+
}
|
|
3250
|
+
break;
|
|
3251
|
+
default:
|
|
3252
|
+
is_constant = false;
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
return is_constant;
|
|
3256
|
+
} catch (error) {
|
|
3257
|
+
console.error("检查是否为常量值时出错:", error);
|
|
3258
|
+
return false;
|
|
3259
|
+
}
|
|
3260
|
+
};
|
|
3261
|
+
|
|
3262
|
+
/**
|
|
3263
|
+
* 检测参数声明与函数内部引用是否一致
|
|
3264
|
+
* @param {object} context ESLint上下文
|
|
3265
|
+
* @param {object} node 函数节点(FunctionDeclaration、FunctionExpression、ArrowFunctionExpression)
|
|
3266
|
+
*/
|
|
3267
|
+
Detector.prototype._checkParamReferences = function (context, node) {
|
|
3268
|
+
try {
|
|
3269
|
+
// 获取函数参数列表
|
|
3270
|
+
var params = node.params || [];
|
|
3271
|
+
if (params.length === 0) {
|
|
3272
|
+
return; // 没有参数,无需检查
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3275
|
+
// 提取参数名
|
|
3276
|
+
var param_names = [];
|
|
3277
|
+
for (var i = 0; i < params.length; i++) {
|
|
3278
|
+
var param = params[i];
|
|
3279
|
+
if (param.type === 'Identifier') {
|
|
3280
|
+
param_names.push(param.name);
|
|
3281
|
+
}
|
|
3282
|
+
// 处理解构参数
|
|
3283
|
+
else if (param.type === 'ObjectPattern' && param.properties) {
|
|
3284
|
+
for (var p = 0; p < param.properties.length; p++) {
|
|
3285
|
+
var property = param.properties[p];
|
|
3286
|
+
if (property.key && property.key.type === 'Identifier') {
|
|
3287
|
+
param_names.push(property.key.name);
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3293
|
+
if (param_names.length === 0) {
|
|
3294
|
+
return; // 没有有效的参数名
|
|
3295
|
+
}
|
|
3296
|
+
|
|
3297
|
+
// 分析函数体内的标识符引用
|
|
3298
|
+
var body_identifiers = this._extractIdentifiers(node.body);
|
|
3299
|
+
|
|
3300
|
+
// 检查每个参数是否被正确引用
|
|
3301
|
+
for (var j = 0; j < param_names.length; j++) {
|
|
3302
|
+
var param_name = param_names[j];
|
|
3303
|
+
var is_referenced = false;
|
|
3304
|
+
var reference_errors = [];
|
|
3305
|
+
|
|
3306
|
+
// 检查参数是否被引用
|
|
3307
|
+
for (var k = 0; k < body_identifiers.length; k++) {
|
|
3308
|
+
var identifier = body_identifiers[k];
|
|
3309
|
+
|
|
3310
|
+
// 检查标识符名称与参数名的相似性
|
|
3311
|
+
if (this._isSimilarIdentifier(identifier.name, param_name)) {
|
|
3312
|
+
if (identifier.name === param_name) {
|
|
3313
|
+
// 完全匹配,正确引用
|
|
3314
|
+
is_referenced = true;
|
|
3315
|
+
break;
|
|
3316
|
+
} else {
|
|
3317
|
+
// 相似但不完全匹配,可能是拼写错误
|
|
3318
|
+
reference_errors.push({
|
|
3319
|
+
node: identifier.node,
|
|
3320
|
+
actual_name: identifier.name,
|
|
3321
|
+
expected_name: param_name
|
|
3322
|
+
});
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
|
|
3327
|
+
// 如果没有正确引用但有相似引用,报告错误
|
|
3328
|
+
if (!is_referenced && reference_errors.length > 0) {
|
|
3329
|
+
for (var m = 0; m < reference_errors.length; m++) {
|
|
3330
|
+
var error = reference_errors[m];
|
|
3331
|
+
|
|
3332
|
+
// 检查参数名是否符合命名规范,如果不符合,使用符合规范的名称
|
|
3333
|
+
var param_name_err = this._checkParamName(param_name, null);
|
|
3334
|
+
var recommended_name = param_name;
|
|
3335
|
+
|
|
3336
|
+
if (param_name_err) {
|
|
3337
|
+
var fix_suggestion = this._getFixSuggestion(param_name, 'param-name', param_name_err.message);
|
|
3338
|
+
if (fix_suggestion && fix_suggestion.fixed_name !== param_name) {
|
|
3339
|
+
recommended_name = fix_suggestion.fixed_name;
|
|
3340
|
+
}
|
|
3341
|
+
}
|
|
3342
|
+
|
|
3343
|
+
context.report({
|
|
3344
|
+
node: error.node,
|
|
3345
|
+
message: "参数引用不一致:声明为 '" + param_name + "',但引用为 '" + error.actual_name + "',建议使用: " + recommended_name,
|
|
3346
|
+
fix: function(fixer) {
|
|
3347
|
+
return fixer.replaceText(error.node, recommended_name);
|
|
3348
|
+
}
|
|
3349
|
+
});
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
}
|
|
3353
|
+
} catch (error) {
|
|
3354
|
+
console.error("检查参数引用一致性时出错:", error);
|
|
3355
|
+
}
|
|
3356
|
+
};
|
|
3357
|
+
|
|
3358
|
+
/**
|
|
3359
|
+
* 提取函数体内的所有标识符
|
|
3360
|
+
* @param {object} node AST节点
|
|
3361
|
+
* @returns {array} 标识符数组
|
|
3362
|
+
*/
|
|
3363
|
+
Detector.prototype._extractIdentifiers = function (node) {
|
|
3364
|
+
var identifiers = [];
|
|
3365
|
+
|
|
3366
|
+
if (!node) {
|
|
3367
|
+
return identifiers;
|
|
3368
|
+
}
|
|
3369
|
+
|
|
3370
|
+
var visited_nodes = new Set(); // 防止循环引用
|
|
3371
|
+
var max_depth = 100; // 最大递归深度
|
|
3372
|
+
|
|
3373
|
+
// 递归遍历AST节点,提取标识符
|
|
3374
|
+
function traverse(current_node, depth) {
|
|
3375
|
+
if (!current_node || depth > max_depth) return;
|
|
3376
|
+
|
|
3377
|
+
// 防止循环引用
|
|
3378
|
+
if (visited_nodes.has(current_node)) return;
|
|
3379
|
+
visited_nodes.add(current_node);
|
|
3380
|
+
|
|
3381
|
+
// 如果是标识符节点,添加到结果中
|
|
3382
|
+
if (current_node.type === 'Identifier') {
|
|
3383
|
+
identifiers.push({
|
|
3384
|
+
name: current_node.name,
|
|
3385
|
+
node: current_node
|
|
3386
|
+
});
|
|
3387
|
+
return;
|
|
3388
|
+
}
|
|
3389
|
+
|
|
3390
|
+
// 遍历子节点
|
|
3391
|
+
var child_nodes = [];
|
|
3392
|
+
|
|
3393
|
+
switch (current_node.type) {
|
|
3394
|
+
case 'FunctionExpression':
|
|
3395
|
+
case 'FunctionDeclaration':
|
|
3396
|
+
case 'ArrowFunctionExpression':
|
|
3397
|
+
// 跳过函数定义,避免递归到参数
|
|
3398
|
+
if (current_node.body) {
|
|
3399
|
+
traverse(current_node.body, depth + 1);
|
|
3400
|
+
}
|
|
3401
|
+
break;
|
|
3402
|
+
|
|
3403
|
+
case 'BlockStatement':
|
|
3404
|
+
child_nodes = current_node.body || [];
|
|
3405
|
+
break;
|
|
3406
|
+
|
|
3407
|
+
case 'VariableDeclaration':
|
|
3408
|
+
child_nodes = current_node.declarations || [];
|
|
3409
|
+
break;
|
|
3410
|
+
|
|
3411
|
+
case 'VariableDeclarator':
|
|
3412
|
+
if (current_node.id) traverse(current_node.id, depth + 1);
|
|
3413
|
+
if (current_node.init) traverse(current_node.init, depth + 1);
|
|
3414
|
+
break;
|
|
3415
|
+
|
|
3416
|
+
case 'ExpressionStatement':
|
|
3417
|
+
if (current_node.expression) traverse(current_node.expression, depth + 1);
|
|
3418
|
+
break;
|
|
3419
|
+
|
|
3420
|
+
case 'CallExpression':
|
|
3421
|
+
if (current_node.callee) traverse(current_node.callee, depth + 1);
|
|
3422
|
+
child_nodes = current_node.arguments || [];
|
|
3423
|
+
break;
|
|
3424
|
+
|
|
3425
|
+
case 'MemberExpression':
|
|
3426
|
+
if (current_node.object) traverse(current_node.object, depth + 1);
|
|
3427
|
+
if (current_node.property) traverse(current_node.property, depth + 1);
|
|
3428
|
+
break;
|
|
3429
|
+
|
|
3430
|
+
case 'ReturnStatement':
|
|
3431
|
+
if (current_node.argument) traverse(current_node.argument, depth + 1);
|
|
3432
|
+
break;
|
|
3433
|
+
|
|
3434
|
+
case 'BinaryExpression':
|
|
3435
|
+
case 'LogicalExpression':
|
|
3436
|
+
if (current_node.left) traverse(current_node.left, depth + 1);
|
|
3437
|
+
if (current_node.right) traverse(current_node.right, depth + 1);
|
|
3438
|
+
break;
|
|
3439
|
+
|
|
3440
|
+
case 'UnaryExpression':
|
|
3441
|
+
if (current_node.argument) traverse(current_node.argument, depth + 1);
|
|
3442
|
+
break;
|
|
3443
|
+
|
|
3444
|
+
case 'ConditionalExpression':
|
|
3445
|
+
if (current_node.test) traverse(current_node.test, depth + 1);
|
|
3446
|
+
if (current_node.consequent) traverse(current_node.consequent, depth + 1);
|
|
3447
|
+
if (current_node.alternate) traverse(current_node.alternate, depth + 1);
|
|
3448
|
+
break;
|
|
3449
|
+
|
|
3450
|
+
case 'ArrayExpression':
|
|
3451
|
+
child_nodes = current_node.elements || [];
|
|
3452
|
+
break;
|
|
3453
|
+
|
|
3454
|
+
case 'ObjectExpression':
|
|
3455
|
+
child_nodes = current_node.properties || [];
|
|
3456
|
+
break;
|
|
3457
|
+
|
|
3458
|
+
case 'Property':
|
|
3459
|
+
if (current_node.key) traverse(current_node.key, depth + 1);
|
|
3460
|
+
if (current_node.value) traverse(current_node.value, depth + 1);
|
|
3461
|
+
break;
|
|
3462
|
+
|
|
3463
|
+
case 'Literal':
|
|
3464
|
+
// 字面量,跳过
|
|
3465
|
+
break;
|
|
3466
|
+
|
|
3467
|
+
default:
|
|
3468
|
+
// 对于其他节点类型,只遍历已知的AST属性,避免无限递归
|
|
3469
|
+
var ast_props = ['body', 'declarations', 'expression', 'callee', 'arguments',
|
|
3470
|
+
'object', 'property', 'argument', 'left', 'right', 'test',
|
|
3471
|
+
'consequent', 'alternate', 'elements', 'properties', 'key', 'value'];
|
|
3472
|
+
|
|
3473
|
+
for (var i = 0; i < ast_props.length; i++) {
|
|
3474
|
+
var prop = ast_props[i];
|
|
3475
|
+
var value = current_node[prop];
|
|
3476
|
+
|
|
3477
|
+
if (Array.isArray(value)) {
|
|
3478
|
+
for (var j = 0; j < value.length; j++) {
|
|
3479
|
+
if (value[j] && typeof value[j] === 'object' && value[j].type) {
|
|
3480
|
+
traverse(value[j], depth + 1);
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
} else if (value && typeof value === 'object' && value.type) {
|
|
3484
|
+
traverse(value, depth + 1);
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
break;
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3490
|
+
// 遍历子节点数组
|
|
3491
|
+
for (var k = 0; k < child_nodes.length; k++) {
|
|
3492
|
+
if (child_nodes[k] && typeof child_nodes[k] === 'object' && child_nodes[k].type) {
|
|
3493
|
+
traverse(child_nodes[k], depth + 1);
|
|
3494
|
+
}
|
|
3495
|
+
}
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3498
|
+
traverse(node, 0);
|
|
3499
|
+
return identifiers;
|
|
3500
|
+
};
|
|
3501
|
+
|
|
3502
|
+
/**
|
|
3503
|
+
* 检查两个标识符是否相似(用于检测拼写错误)
|
|
3504
|
+
* @param {string} actual_name 实际使用的名称
|
|
3505
|
+
* @param {string} expected_name 期望的名称
|
|
3506
|
+
* @returns {boolean} 是否相似
|
|
3507
|
+
*/
|
|
3508
|
+
Detector.prototype._isSimilarIdentifier = function (actual_name, expected_name) {
|
|
3509
|
+
if (actual_name === expected_name) {
|
|
3510
|
+
return true;
|
|
3511
|
+
}
|
|
3512
|
+
|
|
3513
|
+
// 检查大小写不一致的情况
|
|
3514
|
+
if (actual_name.toLowerCase() === expected_name.toLowerCase()) {
|
|
3515
|
+
return true;
|
|
3516
|
+
}
|
|
3517
|
+
|
|
3518
|
+
// 检查常见的拼写错误模式
|
|
3519
|
+
var common_patterns = [
|
|
3520
|
+
// 下划线相关错误
|
|
3521
|
+
{ pattern: /_/g, replacement: '' }, // 忘记下划线
|
|
3522
|
+
{ pattern: /([a-z])([A-Z])/g, replacement: '$1_$2' }, // 驼峰转蛇形
|
|
3523
|
+
{ pattern: /_([a-z])/g, replacement: function(match, p1) { return p1.toUpperCase(); } } // 蛇形转驼峰
|
|
3524
|
+
];
|
|
3525
|
+
|
|
3526
|
+
for (var i = 0; i < common_patterns.length; i++) {
|
|
3527
|
+
var pattern = common_patterns[i];
|
|
3528
|
+
var transformed_actual = actual_name.replace(pattern.pattern, pattern.replacement);
|
|
3529
|
+
var transformed_expected = expected_name.replace(pattern.pattern, pattern.replacement);
|
|
3530
|
+
|
|
3531
|
+
if (transformed_actual === transformed_expected ||
|
|
3532
|
+
transformed_actual.toLowerCase() === transformed_expected.toLowerCase()) {
|
|
3533
|
+
return true;
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3536
|
+
|
|
3537
|
+
// 检查编辑距离(简单的相似度检查)
|
|
3538
|
+
var distance = this._levenshteinDistance(actual_name.toLowerCase(), expected_name.toLowerCase());
|
|
3539
|
+
var max_length = Math.max(actual_name.length, expected_name.length);
|
|
3540
|
+
var similarity = 1 - (distance / max_length);
|
|
3541
|
+
|
|
3542
|
+
return similarity > 0.7; // 相似度超过70%认为相似
|
|
3543
|
+
};
|
|
3544
|
+
|
|
3545
|
+
/**
|
|
3546
|
+
* 计算两个字符串的编辑距离(Levenshtein距离)
|
|
3547
|
+
* @param {string} a 字符串A
|
|
3548
|
+
* @param {string} b 字符串B
|
|
3549
|
+
* @returns {number} 编辑距离
|
|
3550
|
+
*/
|
|
3551
|
+
Detector.prototype._levenshteinDistance = function (a, b) {
|
|
3552
|
+
if (a.length === 0) return b.length;
|
|
3553
|
+
if (b.length === 0) return a.length;
|
|
3554
|
+
|
|
3555
|
+
var matrix = [];
|
|
3556
|
+
|
|
3557
|
+
// 初始化矩阵
|
|
3558
|
+
for (var i = 0; i <= b.length; i++) {
|
|
3559
|
+
matrix[i] = [i];
|
|
3560
|
+
}
|
|
3561
|
+
|
|
3562
|
+
for (var j = 0; j <= a.length; j++) {
|
|
3563
|
+
matrix[0][j] = j;
|
|
3564
|
+
}
|
|
3565
|
+
|
|
3566
|
+
// 计算编辑距离
|
|
3567
|
+
for (i = 1; i <= b.length; i++) {
|
|
3568
|
+
for (j = 1; j <= a.length; j++) {
|
|
3569
|
+
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
3570
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
3571
|
+
} else {
|
|
3572
|
+
matrix[i][j] = Math.min(
|
|
3573
|
+
matrix[i - 1][j - 1] + 1, // 替换
|
|
3574
|
+
matrix[i][j - 1] + 1, // 插入
|
|
3575
|
+
matrix[i - 1][j] + 1 // 删除
|
|
3576
|
+
);
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
|
|
3581
|
+
return matrix[b.length][a.length];
|
|
3582
|
+
};
|
|
3583
|
+
|
|
3584
|
+
/**
|
|
3585
|
+
* 检查是否为 module.exports 中的属性
|
|
3586
|
+
* @param {object} node 属性节点
|
|
3587
|
+
* @param {object} parent_node 父节点信息
|
|
3588
|
+
* @returns {boolean} 是否为 module.exports 中的属性
|
|
3589
|
+
*/
|
|
3590
|
+
Detector.prototype._isModuleExportsProperty = function (node, parent_node) {
|
|
3591
|
+
try {
|
|
3592
|
+
// 处理新的父节点信息结构(包含node和parent属性)
|
|
3593
|
+
var actual_parent_node = parent_node;
|
|
3594
|
+
if (parent_node && typeof parent_node === "object" && parent_node.node) {
|
|
3595
|
+
actual_parent_node = parent_node.node;
|
|
3596
|
+
}
|
|
3597
|
+
|
|
3598
|
+
if (!node || !actual_parent_node) {
|
|
3599
|
+
return false;
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3602
|
+
// 检查父节点是否为 ObjectExpression(对象字面量)
|
|
3603
|
+
if (actual_parent_node.type === "ObjectExpression") {
|
|
3604
|
+
// 检查父节点的父节点是否为 AssignmentExpression
|
|
3605
|
+
var actual_parent_parent =
|
|
3606
|
+
parent_node && typeof parent_node === "object" && parent_node.parent
|
|
3607
|
+
? parent_node.parent
|
|
3608
|
+
: null;
|
|
3609
|
+
|
|
3610
|
+
if (
|
|
3611
|
+
actual_parent_parent &&
|
|
3612
|
+
actual_parent_parent.type === "AssignmentExpression"
|
|
3613
|
+
) {
|
|
3614
|
+
// 检查赋值表达式的左侧是否为 module.exports
|
|
3615
|
+
var left = actual_parent_parent.left;
|
|
3616
|
+
if (
|
|
3617
|
+
left &&
|
|
3618
|
+
left.type === "MemberExpression" &&
|
|
3619
|
+
left.object &&
|
|
3620
|
+
left.object.type === "Identifier" &&
|
|
3621
|
+
left.object.name === "module" &&
|
|
3622
|
+
left.property &&
|
|
3623
|
+
left.property.type === "Identifier" &&
|
|
3624
|
+
left.property.name === "exports"
|
|
3625
|
+
) {
|
|
3626
|
+
return true;
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3629
|
+
}
|
|
3630
|
+
|
|
3631
|
+
return false;
|
|
3632
|
+
} catch (error) {
|
|
3633
|
+
console.error("检查是否为 module.exports 中的属性时出错:", error);
|
|
3634
|
+
return false;
|
|
3635
|
+
}
|
|
3636
|
+
};
|
|
3637
|
+
|
|
1403
3638
|
module.exports = { Detector };
|