mm_eslint 1.4.3 → 1.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +336 -0
- package/README_EN.md +336 -0
- package/config.js +626 -573
- package/corrector.js +375 -0
- package/detector.js +1040 -3413
- package/eslint.config.js +25 -0
- package/fix.js +441 -0
- package/handler.js +993 -0
- package/index.js +211 -1164
- package/package.json +59 -49
- package/tip.js +85 -0
- package/util.js +241 -0
- package/validator.js +266 -0
package/package.json
CHANGED
|
@@ -1,49 +1,59 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mm_eslint",
|
|
3
|
-
"version": "1.4.
|
|
4
|
-
"description": "ESLint plugin for naming conventions - PascalCase, camelCase, snake_case, and UPPER_SNAKE_CASE naming rules",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"eslint",
|
|
8
|
-
"eslintplugin",
|
|
9
|
-
"eslint-plugin",
|
|
10
|
-
"naming-convention",
|
|
11
|
-
"naming-rules",
|
|
12
|
-
"coding-standards",
|
|
13
|
-
"pascalcase",
|
|
14
|
-
"camelcase",
|
|
15
|
-
"snake-case",
|
|
16
|
-
"code-quality"
|
|
17
|
-
],
|
|
18
|
-
"author": "qww",
|
|
19
|
-
"license": "ISC",
|
|
20
|
-
"repository": {
|
|
21
|
-
"type": "git",
|
|
22
|
-
"url": "https://gitee.com/qiuwenwu91/mm_eslint.git"
|
|
23
|
-
},
|
|
24
|
-
"homepage": "https://gitee.com/qiuwenwu91/mm_eslint",
|
|
25
|
-
"bugs": {
|
|
26
|
-
"url": "https://gitee.com/qiuwenwu91/mm_eslint/issues"
|
|
27
|
-
},
|
|
28
|
-
"engines": {
|
|
29
|
-
"node": ">=12.0.0"
|
|
30
|
-
},
|
|
31
|
-
"peerDependencies": {
|
|
32
|
-
"eslint": ">=8.0.0"
|
|
33
|
-
},
|
|
34
|
-
"scripts": {
|
|
35
|
-
"test": "node
|
|
36
|
-
"lint": "npx eslint . --config eslint.config.js"
|
|
37
|
-
},
|
|
38
|
-
"files": [
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "mm_eslint",
|
|
3
|
+
"version": "1.4.5",
|
|
4
|
+
"description": "ESLint plugin for naming conventions - PascalCase, camelCase, snake_case, and UPPER_SNAKE_CASE naming rules",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"eslint",
|
|
8
|
+
"eslintplugin",
|
|
9
|
+
"eslint-plugin",
|
|
10
|
+
"naming-convention",
|
|
11
|
+
"naming-rules",
|
|
12
|
+
"coding-standards",
|
|
13
|
+
"pascalcase",
|
|
14
|
+
"camelcase",
|
|
15
|
+
"snake-case",
|
|
16
|
+
"code-quality"
|
|
17
|
+
],
|
|
18
|
+
"author": "qww",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://gitee.com/qiuwenwu91/mm_eslint.git"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://gitee.com/qiuwenwu91/mm_eslint",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://gitee.com/qiuwenwu91/mm_eslint/issues"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=12.0.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"eslint": ">=8.0.0"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"test": "node test_module_integration.js",
|
|
36
|
+
"lint": "npx eslint . --config eslint.config.js"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"config.js",
|
|
40
|
+
"corrector.js",
|
|
41
|
+
"detector.js",
|
|
42
|
+
"eslint.config.js",
|
|
43
|
+
"fix.js",
|
|
44
|
+
"handler.js",
|
|
45
|
+
"index.js",
|
|
46
|
+
"tip.js",
|
|
47
|
+
"util.js",
|
|
48
|
+
"validator.js",
|
|
49
|
+
"README.md",
|
|
50
|
+
"README_EN.md",
|
|
51
|
+
"LICENSE"
|
|
52
|
+
],
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"eslint-plugin-jsdoc": "^61.5.0"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@babel/parser": "^7.28.6"
|
|
58
|
+
}
|
|
59
|
+
}
|
package/tip.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
var { Config } = require('./config');
|
|
2
|
+
var { Corrector } = require('./corrector');
|
|
3
|
+
var corrector = new Corrector();
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 提示管理类
|
|
7
|
+
* 统一管理所有错误提示和建议使用词的生成
|
|
8
|
+
*/
|
|
9
|
+
class Tip {
|
|
10
|
+
/**
|
|
11
|
+
* 构造函数
|
|
12
|
+
* @param {object} config 配置对象
|
|
13
|
+
*/
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = config || new Config();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 生成完整的错误提示
|
|
21
|
+
* @param {object} error 错误信息
|
|
22
|
+
* @param {string} fix_suggestion 修正建议
|
|
23
|
+
* @returns {string} 完整的错误提示
|
|
24
|
+
*/
|
|
25
|
+
Tip.prototype.getFullMessage = function(error, fix_suggestion) {
|
|
26
|
+
var base_message = this._getBaseMessage(error);
|
|
27
|
+
var suggestion = fix_suggestion || corrector.getSuggestion(error);
|
|
28
|
+
if (suggestion) {
|
|
29
|
+
return base_message + ',建议使用:' + suggestion;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return base_message;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 获取声明方式问题的错误消息
|
|
37
|
+
* @param {string} issue_type 问题类型
|
|
38
|
+
* @param {string} name 名称
|
|
39
|
+
* @returns {string} 错误消息
|
|
40
|
+
*/
|
|
41
|
+
Tip.prototype.getDeclarationIssueMessage = function(issue_type, name) {
|
|
42
|
+
switch (issue_type) {
|
|
43
|
+
case 'const-should-be-let':
|
|
44
|
+
return `变量'${name}'应该用let声明而不是const`;
|
|
45
|
+
default:
|
|
46
|
+
return `变量'${name}'声明方式不符合规范`;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 获取基础错误消息
|
|
52
|
+
* @param {object} error 错误信息对象
|
|
53
|
+
* @returns {string} 基础错误消息
|
|
54
|
+
*/
|
|
55
|
+
Tip.prototype._getBaseMessage = function(error) {
|
|
56
|
+
var type_name_map = this.config.getTypeNameMap();
|
|
57
|
+
var name = error.name;
|
|
58
|
+
var original_type = error.original_type || 'variable';
|
|
59
|
+
var type_name = type_name_map[original_type] || '名称';
|
|
60
|
+
|
|
61
|
+
switch (error.type) {
|
|
62
|
+
case 'style':
|
|
63
|
+
var styles = error.rule.styles.join('、');
|
|
64
|
+
return `${type_name}'${name}'命名不符合${styles}风格`;
|
|
65
|
+
|
|
66
|
+
case 'length':
|
|
67
|
+
if (error.min_length) {
|
|
68
|
+
return `${type_name}'${name}'小于最小长度${error.min_length}字符`;
|
|
69
|
+
} else {
|
|
70
|
+
return `${type_name}'${name}'超过最大长度${error.max_length}字符`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
case 'word_length':
|
|
74
|
+
var word = error.word || name;
|
|
75
|
+
return `${type_name}'${name}'拼接单词"${word}"超过最大长度${error.max_word_length}字符`;
|
|
76
|
+
|
|
77
|
+
case 'forbidden_word':
|
|
78
|
+
return `${type_name}'${name}'拼接了禁用词"${error.forbidden_word}"`;
|
|
79
|
+
|
|
80
|
+
default:
|
|
81
|
+
return `${type_name}'${name}'不符合命名规范`;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
module.exports = { Tip };
|
package/util.js
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
|
|
2
|
+
module.exports = {
|
|
3
|
+
/**
|
|
4
|
+
* 分割单词
|
|
5
|
+
* @param {string} name 名称
|
|
6
|
+
* @returns {array} 单词数组
|
|
7
|
+
*/
|
|
8
|
+
splitWords(name) {
|
|
9
|
+
if (!name || name.length === 0) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
var words = [];
|
|
14
|
+
var current_word = '';
|
|
15
|
+
var last_char_type = null; // 'upper', 'lower', 'underscore', 'digit', 'other'
|
|
16
|
+
|
|
17
|
+
for (var i = 0; i < name.length; i++) {
|
|
18
|
+
var char = name[i];
|
|
19
|
+
var is_upper = char >= 'A' && char <= 'Z';
|
|
20
|
+
var is_lower = char >= 'a' && char <= 'z';
|
|
21
|
+
var is_digit = char >= '0' && char <= '9';
|
|
22
|
+
var is_underscore = char === '_';
|
|
23
|
+
|
|
24
|
+
// 处理下划线和数字:直接作为单词分隔符
|
|
25
|
+
if (is_underscore || is_digit) {
|
|
26
|
+
if (current_word.length > 0) {
|
|
27
|
+
words.push(current_word);
|
|
28
|
+
current_word = '';
|
|
29
|
+
}
|
|
30
|
+
if (is_digit) {
|
|
31
|
+
// 数字作为独立的单词
|
|
32
|
+
words.push(char);
|
|
33
|
+
last_char_type = 'digit';
|
|
34
|
+
} else {
|
|
35
|
+
last_char_type = 'underscore';
|
|
36
|
+
}
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 处理第一个字符
|
|
41
|
+
if (current_word.length === 0) {
|
|
42
|
+
current_word = char;
|
|
43
|
+
if (is_upper) {
|
|
44
|
+
last_char_type = 'upper';
|
|
45
|
+
} else if (is_lower) {
|
|
46
|
+
last_char_type = 'lower';
|
|
47
|
+
} else if (is_digit) {
|
|
48
|
+
last_char_type = 'digit';
|
|
49
|
+
} else {
|
|
50
|
+
last_char_type = 'other';
|
|
51
|
+
}
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 判断当前字符类型
|
|
56
|
+
var current_char_type;
|
|
57
|
+
if (is_upper) {
|
|
58
|
+
current_char_type = 'upper';
|
|
59
|
+
} else if (is_lower) {
|
|
60
|
+
current_char_type = 'lower';
|
|
61
|
+
} else if (is_digit) {
|
|
62
|
+
current_char_type = 'digit';
|
|
63
|
+
} else {
|
|
64
|
+
current_char_type = 'other';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 大小写转换逻辑(仅对字母字符有效)
|
|
68
|
+
if ((last_char_type === 'upper' || last_char_type === 'lower') &&
|
|
69
|
+
(current_char_type === 'upper' || current_char_type === 'lower')) {
|
|
70
|
+
|
|
71
|
+
if (last_char_type === 'upper' && current_char_type === 'lower') {
|
|
72
|
+
// 大写转小写:将上一个词组的最后一个字符作为下一个词的开头
|
|
73
|
+
if (current_word.length > 1) {
|
|
74
|
+
var last_char = current_word[current_word.length - 1];
|
|
75
|
+
words.push(current_word.substring(0, current_word.length - 1));
|
|
76
|
+
current_word = last_char + char;
|
|
77
|
+
} else {
|
|
78
|
+
current_word += char;
|
|
79
|
+
}
|
|
80
|
+
} else if (last_char_type === 'lower' && current_char_type === 'upper') {
|
|
81
|
+
// 小写转大写:大写开头就是下个单词的开头
|
|
82
|
+
words.push(current_word);
|
|
83
|
+
current_word = char;
|
|
84
|
+
} else {
|
|
85
|
+
// 相同类型字符,继续当前单词
|
|
86
|
+
current_word += char;
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
// 数字或其他字符,直接添加到当前单词
|
|
90
|
+
current_word += char;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
last_char_type = current_char_type;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 添加最后一个单词
|
|
97
|
+
if (current_word.length > 0) {
|
|
98
|
+
words.push(current_word);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return words;
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 获取实际名称和前缀
|
|
106
|
+
* @param {string} name 名称
|
|
107
|
+
* @returns {object} 包含前缀和实际名称的对象
|
|
108
|
+
*/
|
|
109
|
+
getRealName(name) {
|
|
110
|
+
var real_name = name;
|
|
111
|
+
var prefix = '';
|
|
112
|
+
if (real_name.indexOf('_') === 0) {
|
|
113
|
+
prefix = '_';
|
|
114
|
+
real_name = real_name.replace('_', '');
|
|
115
|
+
}
|
|
116
|
+
else if (real_name.indexOf('#') === 0) {
|
|
117
|
+
prefix = '#';
|
|
118
|
+
real_name = real_name.replace('#', '');
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
prefix,
|
|
122
|
+
real_name
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 智能驼峰分割函数(外部使用)
|
|
129
|
+
* @param {string} name 名称
|
|
130
|
+
* @param {array} common_abbreviations 常见缩写词字典
|
|
131
|
+
* @returns {array} 分割后的单词数组
|
|
132
|
+
*/
|
|
133
|
+
function _smartSplitCamelCase(name, common_abbreviations) {
|
|
134
|
+
// 智能分割:结合下划线分割和驼峰分割
|
|
135
|
+
// 先按下划线分割
|
|
136
|
+
var underscore_words = name.split('_').filter(function (word) { return word.length > 0; });
|
|
137
|
+
|
|
138
|
+
// 对每个下划线分割后的单词,再进行驼峰分割
|
|
139
|
+
var final_words = [];
|
|
140
|
+
underscore_words.forEach(function (word) {
|
|
141
|
+
// 如果是单个字母,直接添加
|
|
142
|
+
if (word.length === 1) {
|
|
143
|
+
final_words.push(word);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 智能驼峰分割:识别连续大写字母和常见缩写词
|
|
148
|
+
var camel_words = [];
|
|
149
|
+
var current_word = '';
|
|
150
|
+
var last_char_was_upper = false;
|
|
151
|
+
|
|
152
|
+
for (var i = 0; i < word.length; i++) {
|
|
153
|
+
var char = word[i];
|
|
154
|
+
var is_upper = char >= 'A' && char <= 'Z';
|
|
155
|
+
|
|
156
|
+
// 如果是大写字母
|
|
157
|
+
if (is_upper) {
|
|
158
|
+
// 如果上一个字符也是大写,继续当前单词(缩写词)
|
|
159
|
+
if (last_char_was_upper) {
|
|
160
|
+
current_word += char;
|
|
161
|
+
} else {
|
|
162
|
+
// 如果当前单词不为空,先保存
|
|
163
|
+
if (current_word.length > 0) {
|
|
164
|
+
camel_words.push(current_word);
|
|
165
|
+
}
|
|
166
|
+
current_word = char;
|
|
167
|
+
}
|
|
168
|
+
last_char_was_upper = true;
|
|
169
|
+
} else {
|
|
170
|
+
// 如果是小写字母
|
|
171
|
+
// 如果上一个字符是大写且当前单词长度>1,说明是缩写词结束
|
|
172
|
+
if (last_char_was_upper && current_word.length > 1) {
|
|
173
|
+
camel_words.push(current_word);
|
|
174
|
+
current_word = char;
|
|
175
|
+
} else {
|
|
176
|
+
current_word += char;
|
|
177
|
+
}
|
|
178
|
+
last_char_was_upper = false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// 添加最后一个单词
|
|
183
|
+
if (current_word.length > 0) {
|
|
184
|
+
camel_words.push(current_word);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 后处理:合并已知的常见缩写词
|
|
188
|
+
var processed_words = [];
|
|
189
|
+
var i = 0;
|
|
190
|
+
while (i < camel_words.length) {
|
|
191
|
+
var current = camel_words[i];
|
|
192
|
+
|
|
193
|
+
// 检查是否是常见缩写词
|
|
194
|
+
var found_abbr = false;
|
|
195
|
+
for (var j = common_abbreviations.length - 1; j >= 0; j--) {
|
|
196
|
+
var abbr = common_abbreviations[j];
|
|
197
|
+
if (current.toUpperCase() === abbr) {
|
|
198
|
+
processed_words.push(abbr);
|
|
199
|
+
found_abbr = true;
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (found_abbr) {
|
|
205
|
+
i++;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// 尝试合并连续的单个大写字母(可能是缩写词的一部分)
|
|
210
|
+
if (current.length === 1 && /[A-Z]/.test(current)) {
|
|
211
|
+
var combined = current;
|
|
212
|
+
var k = i + 1;
|
|
213
|
+
while (k < camel_words.length && camel_words[k].length === 1 && /[A-Z]/.test(camel_words[k])) {
|
|
214
|
+
combined += camel_words[k];
|
|
215
|
+
k++;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 检查合并后的结果是否是常见缩写词
|
|
219
|
+
var is_known_abbr = common_abbreviations.includes(combined);
|
|
220
|
+
if (is_known_abbr) {
|
|
221
|
+
processed_words.push(combined);
|
|
222
|
+
i = k;
|
|
223
|
+
} else {
|
|
224
|
+
// 如果不是已知缩写词,保持原样
|
|
225
|
+
processed_words.push(current);
|
|
226
|
+
i++;
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
processed_words.push(current);
|
|
230
|
+
i++;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 如果有多个单词,分别添加
|
|
235
|
+
processed_words.forEach(function (w) {
|
|
236
|
+
final_words.push(w);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
return final_words;
|
|
241
|
+
}
|
package/validator.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
const { Config } = require('./config');
|
|
2
|
+
const { splitWords, getRealName } = require('./util');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 命名规范验证器类
|
|
6
|
+
* 负责验证命名是否符合规范
|
|
7
|
+
*/
|
|
8
|
+
class Validator {
|
|
9
|
+
/**
|
|
10
|
+
* 构造函数
|
|
11
|
+
* @param {object} config 配置对象
|
|
12
|
+
*/
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config || new Config();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 验证命名是否符合规范
|
|
20
|
+
* @param {string} name 名称
|
|
21
|
+
* @param {string} original_type 原始类型
|
|
22
|
+
* @returns {object|null} 错误信息对象或null
|
|
23
|
+
*/
|
|
24
|
+
Validator.prototype.validate = function (name, original_type) {
|
|
25
|
+
// 获取命名规则
|
|
26
|
+
var name_type = this._getValidationType(original_type);
|
|
27
|
+
// 获取命名规则
|
|
28
|
+
var rule = this.config.getRule(name_type);
|
|
29
|
+
// 如果没有配置规则,直接返回null
|
|
30
|
+
if (!rule) {
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
var {
|
|
34
|
+
prefix,
|
|
35
|
+
real_name
|
|
36
|
+
} = getRealName(name);
|
|
37
|
+
var words = splitWords(real_name);
|
|
38
|
+
var error = this.check(real_name, words, rule);
|
|
39
|
+
if (error) {
|
|
40
|
+
error.name = name;
|
|
41
|
+
error.prefix = prefix;
|
|
42
|
+
error.real_name = real_name;
|
|
43
|
+
error.name_type = name_type;
|
|
44
|
+
error.original_type = original_type;
|
|
45
|
+
error.words = words;
|
|
46
|
+
error.rule = rule;
|
|
47
|
+
}
|
|
48
|
+
return error;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 检查命名是否符合规范
|
|
53
|
+
* @param {string} name 名称
|
|
54
|
+
* @param {string} name_type 名称类型
|
|
55
|
+
* @returns {object|null} 错误信息对象或null
|
|
56
|
+
*/
|
|
57
|
+
Validator.prototype.check = function (name, words, rule) {
|
|
58
|
+
try {
|
|
59
|
+
// 如果是忽略检测的词,直接返回null
|
|
60
|
+
var is_ignore = this._isIgnoreWord(name, rule.ignore_words);
|
|
61
|
+
if (is_ignore) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 检查命名风格,最重要,错误级。
|
|
66
|
+
var style_error = this._validateNamingStyle(name, rule.styles);
|
|
67
|
+
if (style_error) {
|
|
68
|
+
return style_error;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 检查名称长度,其次,警告级。
|
|
72
|
+
var length_error = this._validateLength(name, rule.min, rule.max);
|
|
73
|
+
if (length_error) {
|
|
74
|
+
return length_error;
|
|
75
|
+
}
|
|
76
|
+
if (!rule.single_word || words.length < 2) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 检查禁止拼接词,警告级。
|
|
81
|
+
var forbidden_error = this._validateForbiddenWords(words, rule.forbidden_words);
|
|
82
|
+
if (forbidden_error) {
|
|
83
|
+
return forbidden_error;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 检查每个单词的长度, 警告级。
|
|
87
|
+
var word_error = this._validateWordLength(words, rule.single_word_len);
|
|
88
|
+
if (word_error) {
|
|
89
|
+
return word_error;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return null;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
// 验证过程中出现异常,返回null
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 判断名称是否为忽略词
|
|
101
|
+
* @param {string} name 名称
|
|
102
|
+
* @param {array} ignore_words 忽略词数组
|
|
103
|
+
* @returns {boolean} 是否为忽略词
|
|
104
|
+
*/
|
|
105
|
+
Validator.prototype._isIgnoreWord = function (name, ignore_words) {
|
|
106
|
+
if (!ignore_words || ignore_words.length === 0) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
for (var i = 0; i < ignore_words.length; i++) {
|
|
110
|
+
var ignore_word = ignore_words[i];
|
|
111
|
+
if (ignore_word.toLowerCase() === name.toLowerCase()) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 验证名称长度
|
|
120
|
+
* @param {string} name 名称
|
|
121
|
+
* @param {number} min 最小长度
|
|
122
|
+
* @param {number} max 最大长度
|
|
123
|
+
* @returns {object|null} 错误信息或null
|
|
124
|
+
*/
|
|
125
|
+
Validator.prototype._validateLength = function (name, min = 1, max = 32) {
|
|
126
|
+
if (!name || name.length === 0) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
var name_length = name.length;
|
|
130
|
+
if (name_length < min) {
|
|
131
|
+
return {
|
|
132
|
+
type: 'length',
|
|
133
|
+
severity: 'warning',
|
|
134
|
+
name_length,
|
|
135
|
+
min_length: min
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
if (name_length > max) {
|
|
139
|
+
return {
|
|
140
|
+
type: 'length',
|
|
141
|
+
severity: 'warning',
|
|
142
|
+
name_length,
|
|
143
|
+
max_length: max
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 获取验证类型
|
|
151
|
+
* @param {string} original_type 原始类型
|
|
152
|
+
* @returns {string} 验证类型
|
|
153
|
+
*/
|
|
154
|
+
Validator.prototype._getValidationType = function (original_type) {
|
|
155
|
+
return original_type.replace('property-', '').replace('static-', '').replace('prototype-', '').replace('private-', '').replace('internal-', '').replace('use-', '').replace('param-', '');
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 验证命名风格
|
|
160
|
+
* @param {string} name 名称
|
|
161
|
+
* @param {object} styles 规则配置
|
|
162
|
+
* @returns {object|null} 错误信息或null
|
|
163
|
+
*/
|
|
164
|
+
Validator.prototype._validateNamingStyle = function (name, styles) {
|
|
165
|
+
if (!styles || styles.length === 0) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
// 检查是否匹配任一允许的风格
|
|
169
|
+
var is_valid = styles.some((style) => {
|
|
170
|
+
return this.isValidStyle(name, style);
|
|
171
|
+
}, this);
|
|
172
|
+
|
|
173
|
+
if (!is_valid) {
|
|
174
|
+
return {
|
|
175
|
+
type: 'style',
|
|
176
|
+
severity: 'error',
|
|
177
|
+
style: styles[0]
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return null;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 验证单词长度
|
|
186
|
+
* @param {array} words 单词数组
|
|
187
|
+
* @param {number} single_word_len 单个单词最大长度
|
|
188
|
+
* @returns {object|null} 错误信息或null
|
|
189
|
+
*/
|
|
190
|
+
Validator.prototype._validateWordLength = function (words, single_word_len = 16) {
|
|
191
|
+
if (!words || words.length === 0) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
// 检查每个单词的长度
|
|
195
|
+
for (var i = 0; i < words.length; i++) {
|
|
196
|
+
var word = words[i];
|
|
197
|
+
if (word.length > single_word_len) {
|
|
198
|
+
return {
|
|
199
|
+
type: 'word_length',
|
|
200
|
+
severity: 'warning',
|
|
201
|
+
word: word,
|
|
202
|
+
word_length: word.length,
|
|
203
|
+
max_word_length: single_word_len
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return null;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* 验证禁止拼接词
|
|
213
|
+
* @param {array} words 单词数组
|
|
214
|
+
* @param {array} forbidden_words 禁止拼接词数组
|
|
215
|
+
* @returns {object|null} 错误信息或null
|
|
216
|
+
*/
|
|
217
|
+
Validator.prototype._validateForbiddenWords = function (words, forbidden_words) {
|
|
218
|
+
if (!forbidden_words || forbidden_words.length === 0) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
for (var i = 0; i < words.length; i++) {
|
|
223
|
+
let word = this.getForbiddenWord(forbidden_words, words[i]);
|
|
224
|
+
if (word) {
|
|
225
|
+
return {
|
|
226
|
+
type: 'forbidden_word',
|
|
227
|
+
severity: 'warning',
|
|
228
|
+
forbidden_word: word
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return null;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 检查单词数组是否包含禁止拼接词
|
|
237
|
+
* @param {array} forbidden_words 禁止拼接词组
|
|
238
|
+
* @param {string} word 单词
|
|
239
|
+
* @returns {boolean} 是否包含禁止拼接词
|
|
240
|
+
*/
|
|
241
|
+
Validator.prototype.getForbiddenWord = function (forbidden_words, word) {
|
|
242
|
+
let word_lower = word.toLowerCase();
|
|
243
|
+
for (var i = 0; i < forbidden_words.length; i++) {
|
|
244
|
+
// 忽略大小写进行比较
|
|
245
|
+
if (forbidden_words[i].toLowerCase() === word_lower) {
|
|
246
|
+
return word;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return null;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* 检查名称是否匹配指定风格
|
|
254
|
+
* @param {string} name 名称
|
|
255
|
+
* @param {string} style 命名风格
|
|
256
|
+
* @returns {boolean} 是否匹配
|
|
257
|
+
*/
|
|
258
|
+
Validator.prototype.isValidStyle = function (name, style) {
|
|
259
|
+
if (!name || name.length === 0) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
var regex = this.config.getRegex(style);
|
|
263
|
+
return regex ? regex.test(name) : false;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
module.exports = { Validator };
|