mm_eslint 1.4.4 → 1.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,519 @@
1
+ const { Name } = require('./name.js');
2
+
3
+ /**
4
+ * 常量名检测器类
5
+ * 负责检测常量名是否符合命名规范
6
+ */
7
+ class ConstName extends Name {
8
+ constructor(context, config) {
9
+ super(context, config);
10
+ }
11
+ }
12
+
13
+ /**
14
+ * 变量声明节点检测函数(常量声明)
15
+ * @param {Object} node - 变量声明节点
16
+ * @returns {Object|undefined} - 检测结果对象或undefined
17
+ */
18
+ ConstName.prototype.VariableDeclaration = function (node) {
19
+ // 判断是否为常量声明(const)
20
+ if (node.kind === 'const') {
21
+ for (let i = 0; i < node.declarations.length; i++) {
22
+ let decl = node.declarations[i];
23
+ if (decl.id && decl.id.type === 'Identifier') {
24
+ // 排除类实例:如果右边是 new 表达式,则不是常量
25
+ if (decl.init && decl.init.type === 'NewExpression') {
26
+ continue;
27
+ }
28
+
29
+ // 排除正则表达式字面量(RegExp实例)
30
+ if (decl.init && decl.init.type === 'Literal' && decl.init.regex) {
31
+ continue;
32
+ }
33
+
34
+ // 排除函数:如果右边是函数表达式或箭头函数,则不是常量
35
+ if (decl.init && (decl.init.type === 'FunctionExpression' || decl.init.type === 'ArrowFunctionExpression')) {
36
+ continue;
37
+ }
38
+
39
+ // 排除类:如果右边是类表达式,则不是常量
40
+ if (decl.init && decl.init.type === 'ClassExpression') {
41
+ continue;
42
+ }
43
+
44
+ // 排除函数引用:如果右边是标识符且指向函数,则不是常量
45
+ if (decl.init && decl.init.type === 'Identifier' && this._isFunctionReference(decl.init)) {
46
+ continue;
47
+ }
48
+
49
+ // 判断是否为常量(包括 Object.freeze() 等情况)
50
+ if (this._isConstantValue(decl.init)) {
51
+ // 检测常量名
52
+ let name = decl.id.name;
53
+ let original_type = 'constant';
54
+ let error = this.check(node, name, original_type);
55
+ this.report(node, error, original_type);
56
+
57
+ if (error) {
58
+ return error;
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ /**
67
+ * 属性节点检测函数(常量属性)
68
+ * @param {Object} node - 属性节点
69
+ * @returns {Object|undefined} - 检测结果对象或undefined
70
+ */
71
+ ConstName.prototype.Property = function (node) {
72
+ // 判断是否为常量属性(对象字面量中的常量属性)
73
+ // 只有当属性在常量对象中时才进行常量检测
74
+ if (!this._isInConstantObject(node)) {
75
+ return;
76
+ }
77
+
78
+ // 排除类实例:如果右边是 new 表达式,则不是常量属性
79
+ if (node.value && node.value.type === 'NewExpression') {
80
+ return;
81
+ }
82
+
83
+ // 排除函数:如果右边是函数表达式或箭头函数,则不是常量属性
84
+ if (node.value && (node.value.type === 'FunctionExpression' || node.value.type === 'ArrowFunctionExpression')) {
85
+ return;
86
+ }
87
+
88
+ // 排除类:如果右边是类表达式,则不是常量属性
89
+ if (node.value && node.value.type === 'ClassExpression') {
90
+ return;
91
+ }
92
+
93
+ // 判断属性值是否为基本类型或字面量
94
+ if (this._isPrimitiveOrLiteral(node.value)) {
95
+ let name = node.key.name;
96
+ let error = this.check(node, name, 'property-constant');
97
+ this.report(node, error, 'property-constant');
98
+ return error;
99
+ }
100
+ }
101
+
102
+ /**
103
+ * 判断节点值是否为基本类型或字面量
104
+ * @param {Object} value_node - 值节点
105
+ * @returns {boolean} 是否为基本类型或字面量
106
+ */
107
+ ConstName.prototype._isPrimitiveOrLiteral = function (value_node) {
108
+ if (!value_node) {
109
+ return false;
110
+ }
111
+
112
+ // 基本类型:字符串、数字、布尔值、null、undefined
113
+ const primitive_types = [
114
+ 'Literal', // 字面量(字符串、数字、布尔值、正则表达式等)
115
+ 'StringLiteral', // 字符串字面量
116
+ 'NumericLiteral', // 数字字面量
117
+ 'BooleanLiteral', // 布尔字面量
118
+ 'NullLiteral', // null字面量
119
+ 'RegExpLiteral', // 正则表达式字面量
120
+ 'TemplateLiteral' // 模板字符串字面量
121
+ ];
122
+
123
+ // 对象字面量和数组字面量也视为常量
124
+ const literal_types = [
125
+ 'ObjectExpression', // 对象字面量
126
+ 'ArrayExpression' // 数组字面量
127
+ ];
128
+
129
+ return primitive_types.includes(value_node.type) || literal_types.includes(value_node.type);
130
+ }
131
+
132
+ /**
133
+ * 判断一个值是否为常量
134
+ * @param {Object} value_node - 值节点
135
+ * @returns {boolean} 是否为常量
136
+ */
137
+ ConstName.prototype._isConstantValue = function (value_node) {
138
+ if (!value_node) {
139
+ return true; // 没有初始值也视为常量
140
+ }
141
+
142
+ // 基本类型和字面量都是常量
143
+ if (this._isPrimitiveOrLiteral(value_node)) {
144
+ return true;
145
+ }
146
+
147
+ // Object.freeze() 调用是常量
148
+ if (value_node.type === 'CallExpression' &&
149
+ value_node.callee &&
150
+ value_node.callee.type === 'MemberExpression' &&
151
+ value_node.callee.object &&
152
+ value_node.callee.object.name === 'Object' &&
153
+ value_node.callee.property &&
154
+ value_node.callee.property.name === 'freeze') {
155
+ return true;
156
+ }
157
+
158
+ // Object.seal() 调用是常量
159
+ if (value_node.type === 'CallExpression' &&
160
+ value_node.callee &&
161
+ value_node.callee.type === 'MemberExpression' &&
162
+ value_node.callee.object &&
163
+ value_node.callee.object.name === 'Object' &&
164
+ value_node.callee.property &&
165
+ value_node.callee.property.name === 'seal') {
166
+ return true;
167
+ }
168
+
169
+ // Object.preventExtensions() 调用是常量
170
+ if (value_node.type === 'CallExpression' &&
171
+ value_node.callee &&
172
+ value_node.callee.type === 'MemberExpression' &&
173
+ value_node.callee.object &&
174
+ value_node.callee.object.name === 'Object' &&
175
+ value_node.callee.property &&
176
+ value_node.callee.property.name === 'preventExtensions') {
177
+ return true;
178
+ }
179
+
180
+ // 其他情况:标识符引用(需要进一步判断)
181
+ if (value_node.type === 'Identifier') {
182
+ // 这里可以进一步判断标识符是否为常量
183
+ // 暂时返回true,让命名规范检测
184
+ return true;
185
+ }
186
+
187
+ // 默认情况下,如果不是排除的类型,就认为是常量
188
+ return true;
189
+ }
190
+
191
+ /**
192
+ * 判断节点是否为类定义
193
+ * @param {Object} node - AST节点
194
+ * @returns {boolean} 是否为类定义
195
+ */
196
+ ConstName.prototype._isClassDefinition = function (node) {
197
+ if (!node) {
198
+ return false;
199
+ }
200
+
201
+ // 类表达式
202
+ if (node.type === 'ClassExpression') {
203
+ return true;
204
+ }
205
+
206
+ // 类声明(通过标识符引用)
207
+ if (node.type === 'Identifier') {
208
+ // 检查标识符是否指向类定义
209
+ // 通过查找同级节点中的类声明来判断
210
+ let current_node = node;
211
+ while (current_node.parent) {
212
+ // 查找同级节点中的类声明
213
+ if (current_node.parent.body && Array.isArray(current_node.parent.body)) {
214
+ for (let sibling of current_node.parent.body) {
215
+ if (sibling.type === 'ClassDeclaration' && sibling.id && sibling.id.name === node.name) {
216
+ return true;
217
+ }
218
+ }
219
+ }
220
+ current_node = current_node.parent;
221
+ }
222
+ }
223
+
224
+ // 其他情况不是类定义
225
+ return false;
226
+ }
227
+
228
+ /**
229
+ * 判断标识符是否指向类实例
230
+ * @param {Object} node - 标识符节点
231
+ * @returns {boolean} 是否指向类实例
232
+ */
233
+ ConstName.prototype._isClassInstanceReference = function (node) {
234
+ if (!node || node.type !== 'Identifier') {
235
+ return false;
236
+ }
237
+
238
+ // 查找同级节点中的变量声明,判断是否通过 new 表达式创建
239
+ let current_node = node;
240
+ while (current_node.parent) {
241
+ // 查找同级节点中的变量声明
242
+ if (current_node.parent.body && Array.isArray(current_node.parent.body)) {
243
+ for (let sibling of current_node.parent.body) {
244
+ // 检查变量声明
245
+ if (sibling.type === 'VariableDeclaration' && sibling.declarations) {
246
+ for (let decl of sibling.declarations) {
247
+ if (decl.id && decl.id.type === 'Identifier' && decl.id.name === node.name) {
248
+ // 检查变量是否通过 new 表达式初始化
249
+ if (decl.init && decl.init.type === 'NewExpression') {
250
+ return true;
251
+ }
252
+ }
253
+ }
254
+ }
255
+ }
256
+ }
257
+ current_node = current_node.parent;
258
+ }
259
+
260
+ return false;
261
+ }
262
+
263
+ /**
264
+ * 判断标识符是否指向函数
265
+ * @param {Object} node - 标识符节点
266
+ * @returns {boolean} 是否指向函数
267
+ */
268
+ ConstName.prototype._isFunctionReference = function (node) {
269
+ if (!node || node.type !== 'Identifier') {
270
+ return false;
271
+ }
272
+
273
+ // 查找同级节点中的函数声明或变量声明
274
+ let current_node = node;
275
+ while (current_node.parent) {
276
+ // 查找同级节点中的函数声明
277
+ if (current_node.parent.body && Array.isArray(current_node.parent.body)) {
278
+ for (let sibling of current_node.parent.body) {
279
+ // 检查函数声明
280
+ if (sibling.type === 'FunctionDeclaration' && sibling.id && sibling.id.name === node.name) {
281
+ return true;
282
+ }
283
+
284
+ // 检查变量声明中的函数表达式
285
+ if (sibling.type === 'VariableDeclaration' && sibling.declarations) {
286
+ for (let decl of sibling.declarations) {
287
+ if (decl.id && decl.id.type === 'Identifier' && decl.id.name === node.name) {
288
+ // 检查变量是否通过函数表达式初始化
289
+ if (decl.init && (decl.init.type === 'FunctionExpression' || decl.init.type === 'ArrowFunctionExpression')) {
290
+ return true;
291
+ }
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }
297
+ current_node = current_node.parent;
298
+ }
299
+
300
+ return false;
301
+ }
302
+
303
+ /**
304
+ * 判断节点是否在函数体内
305
+ * @param {Object} node - AST节点
306
+ * @returns {boolean} 是否在函数体内
307
+ */
308
+ ConstName.prototype._isInFunctionBody = function (node) {
309
+ let current_node = node;
310
+ while (current_node.parent) {
311
+ // 检查是否在函数体、箭头函数体或方法体内
312
+ if (current_node.parent.type === 'BlockStatement' &&
313
+ (current_node.parent.parent &&
314
+ (current_node.parent.parent.type === 'FunctionDeclaration' ||
315
+ current_node.parent.parent.type === 'FunctionExpression' ||
316
+ current_node.parent.parent.type === 'ArrowFunctionExpression' ||
317
+ current_node.parent.parent.type === 'MethodDefinition'))) {
318
+ return true;
319
+ }
320
+
321
+ // 检查是否在箭头函数的表达式体内(没有大括号的情况)
322
+ if (current_node.parent.type === 'ArrowFunctionExpression') {
323
+ return true;
324
+ }
325
+
326
+ current_node = current_node.parent;
327
+ }
328
+
329
+ return false;
330
+ }
331
+
332
+ /**
333
+ * 判断属性是否在常量对象中
334
+ * @param {Object} node - 属性节点
335
+ * @returns {boolean} 是否在常量对象中
336
+ */
337
+ ConstName.prototype._isInConstantObject = function (node) {
338
+ // 向上查找父节点,判断是否在常量声明中
339
+ let current_node = node;
340
+ while (current_node.parent) {
341
+ // 排除函数体内的对象字面量
342
+ if (this._isInFunctionBody(current_node)) {
343
+ return false;
344
+ }
345
+
346
+ // 检查是否为常量声明(const)中的对象字面量
347
+ if (current_node.parent.type === 'VariableDeclarator' &&
348
+ current_node.parent.parent &&
349
+ current_node.parent.parent.type === 'VariableDeclaration' &&
350
+ current_node.parent.parent.kind === 'const') {
351
+ return true;
352
+ }
353
+
354
+ // 检查是否为 Object.freeze() 调用中的对象字面量
355
+ if (current_node.parent.type === 'CallExpression' &&
356
+ current_node.parent.callee &&
357
+ current_node.parent.callee.type === 'MemberExpression' &&
358
+ current_node.parent.callee.object &&
359
+ current_node.parent.callee.object.name === 'Object' &&
360
+ current_node.parent.callee.property &&
361
+ current_node.parent.callee.property.name === 'freeze') {
362
+ return true;
363
+ }
364
+
365
+ // 检查是否为 module.exports 或 exports 赋值中的对象字面量
366
+ if (current_node.parent.type === 'AssignmentExpression' &&
367
+ current_node.parent.left &&
368
+ current_node.parent.left.type === 'MemberExpression') {
369
+ let left_object = current_node.parent.left.object;
370
+ let is_exports = false;
371
+
372
+ if (left_object.type === 'Identifier' && left_object.name === 'exports') {
373
+ is_exports = true;
374
+ } else if (left_object.type === 'MemberExpression' &&
375
+ left_object.object.type === 'Identifier' &&
376
+ left_object.object.name === 'module' &&
377
+ left_object.property.type === 'Identifier' &&
378
+ left_object.property.name === 'exports') {
379
+ is_exports = true;
380
+ }
381
+
382
+ if (is_exports) {
383
+ return true;
384
+ }
385
+ }
386
+
387
+ current_node = current_node.parent;
388
+ }
389
+
390
+ // 默认情况下,不在常量对象中
391
+ return false;
392
+ }
393
+
394
+ /**
395
+ * 赋值表达式节点检测函数(常量赋值)
396
+ * @param {Object} node - 赋值表达式节点
397
+ * @returns {Object|undefined} - 检测结果对象或undefined
398
+ */
399
+ ConstName.prototype.AssignmentExpression = function (node) {
400
+ // 检测 exports 或 module.exports 赋值:exports.CONSTANT_NAME = value;
401
+ // 排除右边是对象字面量的情况,交由Property检测器处理
402
+ if (node.operator === '=' && node.left && node.left.type === 'MemberExpression' &&
403
+ node.right && node.right.type !== 'ObjectExpression') {
404
+ // 检查左边是否为 exports 或 module.exports
405
+ let left_object = node.left.object;
406
+ let is_exports = false;
407
+
408
+ if (left_object.type === 'Identifier' && left_object.name === 'exports') {
409
+ is_exports = true;
410
+ } else if (left_object.type === 'MemberExpression' &&
411
+ left_object.object.type === 'Identifier' &&
412
+ left_object.object.name === 'module' &&
413
+ left_object.property.type === 'Identifier' &&
414
+ left_object.property.name === 'exports') {
415
+ is_exports = true;
416
+ }
417
+
418
+ if (is_exports && node.left.property && node.left.property.type === 'Identifier') {
419
+ // 排除类实例(new表达式)
420
+ if (node.right && node.right.type === 'NewExpression') {
421
+ return;
422
+ }
423
+
424
+ // 排除类实例引用(标识符指向类实例)
425
+ if (node.right && node.right.type === 'Identifier' && this._isClassInstanceReference(node.right)) {
426
+ return;
427
+ }
428
+
429
+ // 排除函数引用(标识符指向函数)
430
+ if (node.right && node.right.type === 'Identifier' && this._isFunctionReference(node.right)) {
431
+ return;
432
+ }
433
+
434
+ // 判断右边值是否为常量,同时排除类定义的情况
435
+ if (this._isConstantValue(node.right) && !this._isClassDefinition(node.right)) {
436
+ let name = node.left.property.name;
437
+ let original_type = 'property-constant';
438
+ let error = this.check(node.left.property, name, original_type);
439
+ this.report(node.left.property, error, original_type);
440
+ return error;
441
+ }
442
+ }
443
+ }
444
+ }
445
+
446
+ /**
447
+ * 默认导出节点检测函数(常量导出)
448
+ * @param {Object} node - 默认导出节点
449
+ * @returns {Object|undefined} - 检测结果对象或undefined
450
+ */
451
+ ConstName.prototype.ExportDefaultDeclaration = function (node) {
452
+ // 检测导出的常量
453
+ if (node.declaration && node.declaration.type === 'Identifier') {
454
+ // 先判断导出的标识符是否为常量
455
+ let type = this._getOriginalType(node.declaration, 'ExportDefaultDeclaration');
456
+ if (type === 'constant') {
457
+ let name = node.declaration.name;
458
+ let original_type = 'export-constant';
459
+ let error = this.check(node.declaration, name, original_type);
460
+ this.report(node.declaration, error, original_type);
461
+ return error;
462
+ }
463
+ }
464
+ }
465
+
466
+ /**
467
+ * 命名导出节点检测函数(常量导出)
468
+ * @param {Object} node - 命名导出节点
469
+ * @returns {Object|undefined} - 检测结果对象或undefined
470
+ */
471
+ ConstName.prototype.ExportNamedDeclaration = function (node) {
472
+ // 检测导出的常量声明(如 export const CONSTANT_NAME = value)
473
+ if (node.declaration && node.declaration.type === 'VariableDeclaration') {
474
+ for (let i = 0; i < node.declaration.declarations.length; i++) {
475
+ let declaration = node.declaration.declarations[i];
476
+ if (declaration.id && declaration.id.type === 'Identifier') {
477
+ let name = declaration.id.name;
478
+ let error = this.check(node, name, 'export-constant');
479
+ this.report(node, error, 'export-constant');
480
+ return error;
481
+ }
482
+ }
483
+ }
484
+
485
+ // 检测导出的常量引用
486
+ if (node.specifiers && node.specifiers.length > 0) {
487
+ for (let i = 0; i < node.specifiers.length; i++) {
488
+ let specifier = node.specifiers[i];
489
+
490
+ // 检测导出的标识符(避免重复检测)
491
+ // 优先检测 exported 属性,如果存在则使用它,否则使用 local 属性
492
+ let identifier_to_check = null;
493
+ let identifier_name = '';
494
+
495
+ if (specifier.exported && specifier.exported.type === 'Identifier') {
496
+ identifier_to_check = specifier.exported;
497
+ identifier_name = specifier.exported.name;
498
+ } else if (specifier.local && specifier.local.type === 'Identifier') {
499
+ identifier_to_check = specifier.local;
500
+ identifier_name = specifier.local.name;
501
+ }
502
+
503
+ // 只有当找到有效标识符时才进行检测
504
+ if (identifier_to_check) {
505
+ let original_type = this._getOriginalType(specifier, 'ExportSpecifier');
506
+
507
+ // 只有当导出的是常量时才检测
508
+ if (original_type === 'constant') {
509
+ let error = this.check(identifier_to_check, identifier_name, 'export-constant');
510
+ this.report(identifier_to_check, error, 'export-constant');
511
+ }
512
+ }
513
+ }
514
+ }
515
+ }
516
+
517
+ module.exports = {
518
+ ConstName
519
+ };