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.
@@ -15,6 +15,7 @@ class Config {
15
15
  'class-instance': [],
16
16
  'function': [],
17
17
  'param': [],
18
+ 'object': [],
18
19
  'variable': [],
19
20
  'constant': []
20
21
  },
@@ -24,6 +25,7 @@ class Config {
24
25
  'class-instance': [],
25
26
  'function': [],
26
27
  'param': [],
28
+ 'object': [],
27
29
  'variable': [],
28
30
  'constant': []
29
31
  },
@@ -33,6 +35,7 @@ class Config {
33
35
  'class-instance': {},
34
36
  'function': {},
35
37
  'param': {},
38
+ 'object': {},
36
39
  'variable': {},
37
40
  'constant': {}
38
41
  }
@@ -47,8 +50,8 @@ class Config {
47
50
  */
48
51
  Config.prototype.getRegex = function (style) {
49
52
  var regex = {
50
- "PascalCase": /^[A-Z][a-z]*([A-Z][a-z]*)*$/,
51
- "camelCase": /^[a-z][a-z]*([A-Z][a-z]*)*$/,
53
+ "PascalCase": /^[A-Z][a-z]+[A-Za-z]*$/,
54
+ "camelCase": /^[a-z][a-z]*([A-Z][a-z]*)*[a-z0-9]*$/,
52
55
  "snake_case": /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,
53
56
  "UPPER_SNAKE_CASE": /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/,
54
57
  "lowercase": /^[a-z]+([a-z0-9]+)*$/,
@@ -65,7 +68,7 @@ Config.prototype.getRegex = function (style) {
65
68
  * @returns {Array} 禁止拼接词列表
66
69
  */
67
70
  Config.prototype.getForbiddenWords = function (name_type) {
68
- let type = name_type.replace('property-', '').replace('instance-', '');
71
+ let type = this.getType(name_type);
69
72
  var forbidden = {
70
73
  'class': [
71
74
  'manager',
@@ -103,6 +106,7 @@ Config.prototype.getForbiddenWords = function (name_type) {
103
106
  'field',
104
107
  'property',
105
108
  'entity',
109
+ 'data'
106
110
  ],
107
111
  'function': [
108
112
  'data',
@@ -149,10 +153,10 @@ Config.prototype.getForbiddenWords = function (name_type) {
149
153
  'array',
150
154
  'map',
151
155
  'set',
152
- 'collection',
153
156
  'container',
154
157
  'instance',
155
158
  'data',
159
+ 'collection',
156
160
  'item',
157
161
  'items',
158
162
  'element',
@@ -300,6 +304,14 @@ Config.prototype.getBaseRule = function (name_type) {
300
304
  single_word: true,
301
305
  single_word_len: 8
302
306
  },
307
+ 'object': {
308
+ name: '对象名',
309
+ min: 1,
310
+ max: 20,
311
+ styles: ['camelCase', 'snake_case'],
312
+ single_word: true,
313
+ single_word_len: 8
314
+ },
303
315
  'variable': {
304
316
  name: '变量名',
305
317
  min: 1,
@@ -308,6 +320,14 @@ Config.prototype.getBaseRule = function (name_type) {
308
320
  single_word: true,
309
321
  single_word_len: 8
310
322
  },
323
+ 'property': {
324
+ name: '属性名',
325
+ min: 1,
326
+ max: 20,
327
+ styles: ['snake_case', 'camelCase', 'PascalCase'],
328
+ single_word: true,
329
+ single_word_len: 8
330
+ },
311
331
  'constant': {
312
332
  name: '常量名',
313
333
  min: 1,
@@ -341,13 +361,7 @@ Config.prototype.getRule = function (name_type) {
341
361
  * @returns {object} 推荐词映射
342
362
  */
343
363
  Config.prototype.getRecommendWords = function (name_type) {
344
- let type = name_type.replace('property-', '').replace('instance-', '');
345
- if (type == 'function') {
346
- type = 'function';
347
- }
348
- else if (type == 'value') {
349
- type = 'variable';
350
- }
364
+ let type = this.getType(name_type);
351
365
  var recommend = {
352
366
  'class': {
353
367
  'App': ['Application'],
@@ -460,17 +474,33 @@ Config.prototype.getRecommendWords = function (name_type) {
460
474
  return {};
461
475
  };
462
476
 
477
+ Config.prototype.getType = function (name_type) {
478
+ let type = name_type.replace('property-', '').replace('internal-', '').replace('private-', '').replace('internal-', '').replace('prototype-', '').replace('use-', '').replace('super-', '').replace('static-', '').replace('param-', '').replace('export-', '');
479
+ return type;
480
+ }
481
+
463
482
  /**
464
483
  * 获取忽略词列表
465
484
  * @param {string} name_type 名称类型
466
485
  * @returns {Array} 忽略词列表
467
486
  */
468
487
  Config.prototype.getIgnoreWords = function (name_type) {
469
- let type = name_type.replace('property-', '').replace('instance-', '');
488
+ let type = this.getType(name_type);
470
489
  var ignore = {
471
490
  'class': [
472
491
  'exports', 'Middleware', 'Component', 'Controller', 'Repository', 'Interface', 'Transformer', 'Template'
473
492
  ],
493
+ 'class-instance': [
494
+ // JavaScript 内置全局对象(只保留不符合小驼峰规范的)
495
+ 'JSON', 'Math', 'RegExp', 'EvalError', 'RangeError', 'ReferenceError',
496
+ 'SyntaxError', 'TypeError', 'URIError', 'WeakMap', 'WeakSet', 'Promise',
497
+ 'Proxy', 'Reflect', 'Intl', 'ArrayBuffer', 'DataView', 'Float32Array', 'Float64Array',
498
+ 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array',
499
+ 'Uint8ClampedArray', 'BigInt64Array', 'BigUint64Array', 'Atomics', 'SharedArrayBuffer',
500
+ 'URL', 'URLSearchParams', 'Headers', 'Request', 'Response', 'FormData', 'Blob', 'File',
501
+ 'FileReader', 'Image', 'Audio', 'Video', 'Canvas', 'WebSocket', 'EventSource',
502
+ 'XMLHttpRequest', 'Infinity', 'NaN', 'global'
503
+ ],
474
504
  'function': [
475
505
  'constructor', 'prototype', 'hasOwnProperty',
476
506
  'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString',
@@ -531,27 +561,62 @@ Config.prototype.getTypeNameMap = function () {
531
561
  var type_name_map = {
532
562
  'function': '函数',
533
563
  'variable': '变量',
534
- 'param': '参数',
564
+ 'object': '对象',
535
565
  'class-instance': '类实例',
536
566
  'class': '类',
537
567
  'constant': '常量',
538
- 'property-function': '属性函数',
539
- 'property-variable': '属性变量',
540
- 'property-class-instance': '属性类实例',
541
- 'property-class': '属性类',
542
- 'property-constant': '属性常量',
543
- 'static-function': '静态函数',
544
- 'static-variable': '静态变量',
545
- 'static-class-instance': '静态类实例',
546
- 'static-class': '静态类',
547
- 'static-constant': '静态常量',
548
- 'prototype-function': '原型函数',
549
- 'prototype-variable': '原型变量',
550
- 'prototype-class-instance': '原型类实例',
551
- 'prototype-class': '原型类',
552
- 'prototype-constant': '原型常量',
553
- 'private-function': '私有函数',
554
- 'private-variable': '私有变量'
568
+ 'super-class': '继承-类',
569
+ // 属性
570
+ 'property': '属性',
571
+ 'property-function': '属性—函数',
572
+ 'property-variable': '属性—变量',
573
+ 'property-object': '属性—对象',
574
+ 'property-class-instance': '属性—类实例',
575
+ 'property-class': '属性—类',
576
+ 'property-constant': '属性—常量',
577
+ // 静态属性
578
+ 'static-function': '静态属性—函数',
579
+ 'static-variable': '静态属性—变量',
580
+ 'static-object': '静态属性—对象',
581
+ 'static-class-instance': '静态属性—类实例',
582
+ 'static-class': '静态属性—类',
583
+ 'static-constant': '静态属性—常量',
584
+ // 原型属性
585
+ 'prototype-class-instance': '原型属性—类实例',
586
+ 'prototype-function': '原型属性—函数',
587
+ 'prototype-variable': '原型属性—变量',
588
+ 'prototype-object': '原型属性—对象',
589
+ // 私有属性
590
+ 'private-function': '私有属性—函数',
591
+ 'private-variable': '私有属性—变量',
592
+ 'private-object': '私有属性—对象',
593
+ 'private-class-instance': '私有属性—类实例',
594
+ // 内部属性
595
+ 'internal-function': '内部属性—函数',
596
+ 'internal-variable': '内部属性—变量',
597
+ 'internal-object': '内部属性—对象',
598
+ 'internal-class-instance': '内部属性—类实例',
599
+ // 引用
600
+ 'use-variable': '引用-变量',
601
+ 'use-function': '引用-函数',
602
+ 'use-object': '引用-对象',
603
+ 'use-class': '引用-类',
604
+ 'use-constant': '引用-常量',
605
+ 'use-class-instance': '引用-类实例',
606
+ // 参数
607
+ 'param': '参数',
608
+ 'param-class': '参数—类',
609
+ 'param-class-instance': '参数—类实例',
610
+ 'param-variable': '参数—变量',
611
+ 'param-object': '参数—对象',
612
+ 'param-function': '参数—函数',
613
+ // 导出
614
+ 'export-class': '导出-类',
615
+ 'export-class-instance': '导出-类实例',
616
+ 'export-variable': '导出-变量',
617
+ 'export-object': '导出-对象',
618
+ 'export-function': '导出-函数',
619
+ 'export-constant': '导出-常量'
555
620
  };
556
621
  return type_name_map;
557
622
  }
@@ -43,7 +43,15 @@ Corrector.prototype.getSuggestion = function (error) {
43
43
  } catch {
44
44
  return error.name;
45
45
  }
46
- return error.prefix + word;
46
+
47
+ var suggestion = error.prefix + word;
48
+
49
+ // 检查建议名称是否与原名称相同,如果相同则不显示建议
50
+ if (suggestion === error.name || word === error.name) {
51
+ return null;
52
+ }
53
+
54
+ return suggestion;
47
55
  };
48
56
 
49
57
  /**
@@ -273,9 +281,54 @@ Corrector.prototype._filterForbiddenWord = function (words, forbidden_words) {
273
281
  new_word.push(word);
274
282
  }
275
283
  }
284
+ if (new_word.length === 0) {
285
+ new_word.push(words[words.length - 1]);
286
+ }
276
287
  return new_word;
277
288
  }
278
289
 
290
+ /**
291
+ * 替换禁止词汇为推荐词汇
292
+ * @param {string[]} words 单词数组
293
+ * @param {Array} forbidden_words 禁止词列表
294
+ * @param {object} recommend_words 推荐词配置
295
+ * @returns {string[]} 替换后的单词数组
296
+ */
297
+ Corrector.prototype._replaceForbiddenWords = function (words, forbidden_words, recommend_words) {
298
+ var new_words = [];
299
+ for (let i = 0; i < words.length; i++) {
300
+ let word = words[i];
301
+ if (this._isForbiddenWord(word, forbidden_words)) {
302
+ // 尝试为禁用词找到替代建议
303
+ var replacement = this._getForbiddenWordReplacement(word, recommend_words);
304
+ if (replacement) {
305
+ new_words.push(replacement);
306
+ }
307
+ } else {
308
+ new_words.push(word);
309
+ }
310
+ }
311
+ return new_words;
312
+ }
313
+
314
+ /**
315
+ * 获取禁用词的替代建议
316
+ * @param {string} forbidden_word 禁用词
317
+ * @param {object} recommend_words 推荐词配置
318
+ * @returns {string} 替代建议词
319
+ */
320
+ Corrector.prototype._getForbiddenWordReplacement = function (forbidden_word, recommend_words) {
321
+ for (var replacement in recommend_words) {
322
+ var forbidden_list = recommend_words[replacement];
323
+ for (let i = 0; i < forbidden_list.length; i++) {
324
+ if (forbidden_word.toLowerCase() === forbidden_list[i].toLowerCase()) {
325
+ return replacement;
326
+ }
327
+ }
328
+ }
329
+ return null;
330
+ }
331
+
279
332
  /**
280
333
  * 获取推荐的单词
281
334
  * @param {string[]} words 单词数组
@@ -284,7 +337,6 @@ Corrector.prototype._filterForbiddenWord = function (words, forbidden_words) {
284
337
  * @returns {string[]} 推荐的单词数组
285
338
  */
286
339
  Corrector.prototype._toRecommendWords = function (words, recommend, single_word_len) {
287
- // console.log('推荐单词', words, recommend, single_word_len);
288
340
  let recommend_words = [];
289
341
  for (let i = 0; i < words.length; i++) {
290
342
  let word = words[i];
@@ -0,0 +1,246 @@
1
+ const { Name } = require('./name.js');
2
+
3
+ /**
4
+ * 类实例名检测器类
5
+ * 负责检测类实例名是否符合命名规范
6
+ */
7
+ class ClassInstanceName 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
+ ClassInstanceName.prototype.VariableDeclaration = function (node) {
19
+ // 判断右边是否有 new 表达式
20
+ if (node.declarations[0].init && node.declarations[0].init.type === 'NewExpression') {
21
+ let name = node.declarations[0].id.name;
22
+ let original_type = 'class-instance';
23
+ let error = this.check(node.declarations[0].id, name, original_type);
24
+ this.report(node.declarations[0].id, error, original_type);
25
+ return error;
26
+ }
27
+
28
+ // 判断右边是否有正则表达式字面量(RegExp实例)
29
+ if (node.declarations[0].init && node.declarations[0].init.type === 'Literal' &&
30
+ node.declarations[0].init.regex) {
31
+ let name = node.declarations[0].id.name;
32
+ let original_type = 'class-instance';
33
+ let error = this.check(node.declarations[0].id, name, original_type);
34
+ this.report(node.declarations[0].id, error, original_type);
35
+ return error;
36
+ }
37
+
38
+ // 判断右边是否直接赋值类实例名
39
+ if (node.declarations[0].init && node.declarations[0].init.type === 'Identifier') {
40
+ // 根据右边值的类型决定左边变量的类型
41
+ let original_type = this._getOriginalType(node.declarations[0], 'VariableDeclaration');
42
+
43
+ // 如果右边是类实例,左边变量应该按照类实例的命名规范检测(小驼峰)
44
+ if (original_type === 'class-instance') {
45
+ let name = node.declarations[0].id.name;
46
+ let error = this.check(node.declarations[0].id, name, 'class-instance');
47
+ this.report(node.declarations[0].id, error, 'class-instance');
48
+ return error;
49
+ }
50
+ }
51
+ }
52
+
53
+ /**
54
+ * 属性节点检测函数
55
+ * @param {Object} node - 属性节点
56
+ * @returns {Object|undefined} - 检测结果对象或undefined
57
+ */
58
+ ClassInstanceName.prototype.Property = function (node) {
59
+ // 判断右边是否有 new 表达式
60
+ if (node.value.type === 'NewExpression') {
61
+ let name = node.key.name;
62
+ let original_type = 'property-class-instance';
63
+ let error = this.check(node, name, original_type);
64
+ this.report(node, error, original_type);
65
+ return error;
66
+ }
67
+
68
+ // 判断右边是否直接定义为类实例名
69
+ if (node.value.type === 'Identifier') {
70
+ // 根据右边值的类型决定左边属性的类型
71
+ let original_type = this._getOriginalType(node, 'Property');
72
+
73
+ // 如果右边是类实例,左边属性应该按照类实例的命名规范检测(小驼峰)
74
+ if (original_type === 'class-instance') {
75
+ let name = node.key.name;
76
+ let error = this.check(node, name, 'property-class-instance');
77
+ this.report(node, error, 'property-class-instance');
78
+ return error;
79
+ }
80
+ }
81
+ }
82
+
83
+ /**
84
+ * 类属性定义节点检测函数
85
+ * @param {Object} node - 类属性定义节点
86
+ * @returns {Object|undefined} - 检测结果对象或undefined
87
+ */
88
+ ClassInstanceName.prototype.PropertyDefinition = function (node) {
89
+ // 判断右边是否有 new 表达式
90
+ if (node.value && node.value.type === 'NewExpression') {
91
+ let name = node.key.name;
92
+ let original_type = 'property-class-instance';
93
+ if (node.static) {
94
+ original_type = 'static-class-instance';
95
+ }
96
+ else if (node.key.type === 'PrivateIdentifier') {
97
+ original_type = 'private-class-instance';
98
+ }
99
+ else if (name.startsWith('_')) {
100
+ original_type = 'internal-class-instance';
101
+ }
102
+ let error = this.check(node, name, original_type);
103
+ this.report(node, error, original_type);
104
+ return error;
105
+ }
106
+
107
+ // 判断右边是否直接定义为类实例名
108
+ if (node.value && node.value.type === 'Identifier') {
109
+ // 根据右边值的类型决定左边属性的类型
110
+ let original_type = this._getOriginalType(node, 'PropertyDefinition');
111
+
112
+ // 如果右边是类实例,左边属性应该按照类实例的命名规范检测(小驼峰)
113
+ if (original_type === 'class-instance') {
114
+ let name = node.key.name;
115
+ let original_type = 'property-class-instance';
116
+ if (node.static) {
117
+ original_type = 'static-class-instance';
118
+ }
119
+ else if (node.key.type === 'PrivateIdentifier') {
120
+ original_type = 'private-class-instance';
121
+ }
122
+ else if (name.startsWith('_')) {
123
+ original_type = 'internal-class-instance';
124
+ }
125
+ let error = this.check(node, name, original_type);
126
+ this.report(node, error, original_type);
127
+ return error;
128
+ }
129
+ }
130
+ }
131
+
132
+ /**
133
+ * 赋值表达式节点检测函数
134
+ * @param {Object} node - 赋值表达式节点
135
+ * @returns {Object|undefined} - 检测结果对象或undefined
136
+ */
137
+ ClassInstanceName.prototype.AssignmentExpression = function (node) {
138
+ // 检测 exports 或 module.exports 赋值:exports.classInstance = classInstance;
139
+ // 排除右边是对象字面量的情况,交由Property检测器处理
140
+ if (node.operator === '=' && node.left && node.left.type === 'MemberExpression' &&
141
+ node.right && node.right.type !== 'ObjectExpression') {
142
+ // 检查左边是否为 exports 或 module.exports
143
+ let left_object = node.left.object;
144
+ let is_exports = false;
145
+
146
+ if (left_object.type === 'Identifier' && left_object.name === 'exports') {
147
+ is_exports = true;
148
+ } else if (left_object.type === 'MemberExpression' &&
149
+ left_object.object.type === 'Identifier' &&
150
+ left_object.object.name === 'module' &&
151
+ left_object.property.type === 'Identifier' &&
152
+ left_object.property.name === 'exports') {
153
+ is_exports = true;
154
+ }
155
+
156
+ if (is_exports && node.right && node.right.type === 'Identifier') {
157
+ // 先判断右边是否为类实例
158
+ let original_type = this._getOriginalType(node, 'AssignmentExpression');
159
+
160
+ // 如果右边是类实例,才检测左边的属性名
161
+ if (original_type === 'class-instance') {
162
+ let left_property = node.left.property;
163
+ if (left_property && left_property.type === 'Identifier') {
164
+ let name = left_property.name;
165
+ let error = this.check(left_property, name, 'property-class-instance');
166
+ this.report(left_property, error, 'property-class-instance');
167
+ return error;
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
173
+
174
+ /**
175
+ * 默认导出节点检测函数
176
+ * @param {Object} node - 默认导出节点
177
+ * @returns {Object|undefined} - 检测结果对象或undefined
178
+ */
179
+ ClassInstanceName.prototype.ExportDefaultDeclaration = function (node) {
180
+ // 检测导出的类实例名
181
+ if (node.declaration && node.declaration.type === 'Identifier') {
182
+ let name = node.declaration.name;
183
+ let type = this._getOriginalType(node.declaration, 'ExportDefaultDeclaration');
184
+ if (type === 'class-instance') {
185
+ let original_type = 'export-class-instance';
186
+ let error = this.check(node.declaration, name, original_type);
187
+ this.report(node.declaration, error, original_type);
188
+ return error;
189
+ }
190
+ }
191
+ }
192
+
193
+ /**
194
+ * 命名导出节点检测函数
195
+ * @param {Object} node - 命名导出节点
196
+ * @returns {Object|undefined} - 检测结果对象或undefined
197
+ */
198
+ ClassInstanceName.prototype.ExportNamedDeclaration = function (node) {
199
+ // 检测导出的类实例声明(如 export const myInstance = new ClassName())
200
+ if (node.declaration && node.declaration.type === 'VariableDeclaration') {
201
+ for (let i = 0; i < node.declaration.declarations.length; i++) {
202
+ let declaration = node.declaration.declarations[i];
203
+ if (declaration.init && declaration.init.type === 'NewExpression') {
204
+ let name = declaration.id.name;
205
+ let error = this.check(node, name, 'export-class-instance');
206
+ this.report(node, error, 'export-class-instance');
207
+ return error;
208
+ }
209
+ }
210
+ }
211
+
212
+ // 检测命名导出的类实例引用
213
+ if (node.specifiers && node.specifiers.length > 0) {
214
+ for (let i = 0; i < node.specifiers.length; i++) {
215
+ let specifier = node.specifiers[i];
216
+
217
+ // 检测导出的标识符(避免重复检测)
218
+ // 优先检测 exported 属性,如果存在则使用它,否则使用 local 属性
219
+ let identifier_to_check = null;
220
+ let identifier_name = '';
221
+
222
+ if (specifier.exported && specifier.exported.type === 'Identifier') {
223
+ identifier_to_check = specifier.exported;
224
+ identifier_name = specifier.exported.name;
225
+ } else if (specifier.local && specifier.local.type === 'Identifier') {
226
+ identifier_to_check = specifier.local;
227
+ identifier_name = specifier.local.name;
228
+ }
229
+
230
+ // 只有当找到有效标识符时才进行检测
231
+ if (identifier_to_check) {
232
+ let original_type = this._getOriginalType(specifier, 'ExportSpecifier');
233
+
234
+ // 只有当导出的是类实例时才检测
235
+ if (original_type === 'class-instance') {
236
+ let error = this.check(identifier_to_check, identifier_name, 'export-class-instance');
237
+ this.report(identifier_to_check, error, 'export-class-instance');
238
+ }
239
+ }
240
+ }
241
+ }
242
+ }
243
+
244
+ module.exports = {
245
+ ClassInstanceName
246
+ };