@sun-asterisk/sunlint 1.1.7 → 1.2.0
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/.sunlint.json +1 -1
- package/CHANGELOG.md +83 -0
- package/README.md +66 -4
- package/config/presets/all.json +125 -0
- package/config/presets/beginner.json +16 -8
- package/config/presets/ci.json +12 -4
- package/config/presets/maintainability.json +38 -0
- package/config/presets/performance.json +32 -0
- package/config/presets/quality.json +103 -0
- package/config/presets/recommended.json +36 -12
- package/config/presets/security.json +88 -0
- package/config/presets/strict.json +15 -5
- package/config/rules/rules-registry-generated.json +6312 -0
- package/config/rules-summary.json +1941 -0
- package/core/adapters/sunlint-rule-adapter.js +452 -0
- package/core/analysis-orchestrator.js +4 -4
- package/core/config-manager.js +28 -5
- package/core/rule-selection-service.js +52 -55
- package/docs/CONFIGURATION.md +111 -3
- package/docs/LANGUAGE-SPECIFIC-RULES.md +308 -0
- package/docs/README.md +3 -0
- package/docs/STANDARDIZED-CATEGORY-FILTERING.md +156 -0
- package/engines/eslint-engine.js +92 -2
- package/engines/heuristic-engine.js +8 -31
- package/origin-rules/common-en.md +1320 -0
- package/origin-rules/dart-en.md +289 -0
- package/origin-rules/java-en.md +60 -0
- package/origin-rules/kotlin-mobile-en.md +453 -0
- package/origin-rules/reactjs-en.md +102 -0
- package/origin-rules/security-en.md +1055 -0
- package/origin-rules/swift-en.md +449 -0
- package/origin-rules/typescript-en.md +136 -0
- package/package.json +6 -5
- package/scripts/copy-rules.js +86 -0
- package/rules/README.md +0 -252
- package/rules/common/C002_no_duplicate_code/analyzer.js +0 -65
- package/rules/common/C002_no_duplicate_code/config.json +0 -23
- package/rules/common/C003_no_vague_abbreviations/analyzer.js +0 -418
- package/rules/common/C003_no_vague_abbreviations/config.json +0 -35
- package/rules/common/C006_function_naming/analyzer.js +0 -349
- package/rules/common/C006_function_naming/config.json +0 -86
- package/rules/common/C010_limit_block_nesting/analyzer.js +0 -389
- package/rules/common/C013_no_dead_code/analyzer.js +0 -206
- package/rules/common/C014_dependency_injection/analyzer.js +0 -338
- package/rules/common/C017_constructor_logic/analyzer.js +0 -314
- package/rules/common/C019_log_level_usage/analyzer.js +0 -362
- package/rules/common/C019_log_level_usage/config.json +0 -121
- package/rules/common/C029_catch_block_logging/analyzer.js +0 -373
- package/rules/common/C029_catch_block_logging/config.json +0 -59
- package/rules/common/C031_validation_separation/analyzer.js +0 -186
- package/rules/common/C041_no_sensitive_hardcode/analyzer.js +0 -292
- package/rules/common/C042_boolean_name_prefix/analyzer.js +0 -300
- package/rules/common/C043_no_console_or_print/analyzer.js +0 -304
- package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +0 -351
- package/rules/common/C075_explicit_return_types/analyzer.js +0 -103
- package/rules/common/C076_single_test_behavior/analyzer.js +0 -121
- package/rules/docs/C002_no_duplicate_code.md +0 -57
- package/rules/docs/C031_validation_separation.md +0 -72
- package/rules/index.js +0 -149
- package/rules/migration/converter.js +0 -385
- package/rules/migration/mapping.json +0 -164
- package/rules/security/S026_json_schema_validation/analyzer.js +0 -251
- package/rules/security/S026_json_schema_validation/config.json +0 -27
- package/rules/security/S027_no_hardcoded_secrets/analyzer.js +0 -263
- package/rules/security/S027_no_hardcoded_secrets/config.json +0 -29
- package/rules/security/S029_csrf_protection/analyzer.js +0 -264
- package/rules/tests/C002_no_duplicate_code.test.js +0 -50
- package/rules/universal/C010/generic.js +0 -0
- package/rules/universal/C010/tree-sitter-analyzer.js +0 -0
- package/rules/utils/ast-utils.js +0 -191
- package/rules/utils/base-analyzer.js +0 -98
- package/rules/utils/pattern-matchers.js +0 -239
- package/rules/utils/rule-helpers.js +0 -264
- package/rules/utils/severity-constants.js +0 -93
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const ts = require('typescript');
|
|
4
|
-
|
|
5
|
-
class C006Analyzer {
|
|
6
|
-
constructor() {
|
|
7
|
-
this.ruleId = 'C006';
|
|
8
|
-
this.ruleName = 'Function Naming Convention';
|
|
9
|
-
this.description = 'Tên hàm phải là động từ/verb-noun pattern';
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async analyze(files, language, config) {
|
|
13
|
-
const violations = [];
|
|
14
|
-
|
|
15
|
-
for (const filePath of files) {
|
|
16
|
-
try {
|
|
17
|
-
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
18
|
-
const fileViolations = await this.analyzeFile(filePath, fileContent, language, config);
|
|
19
|
-
violations.push(...fileViolations);
|
|
20
|
-
} catch (error) {
|
|
21
|
-
console.error(`Error analyzing file ${filePath}:`, error.message);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return violations;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async analyzeFile(filePath, content, language, config) {
|
|
29
|
-
switch (language) {
|
|
30
|
-
case 'typescript':
|
|
31
|
-
case 'javascript':
|
|
32
|
-
return this.analyzeTypeScript(filePath, content, config);
|
|
33
|
-
case 'dart':
|
|
34
|
-
return this.analyzeDart(filePath, content, config);
|
|
35
|
-
case 'kotlin':
|
|
36
|
-
return this.analyzeKotlin(filePath, content, config);
|
|
37
|
-
default:
|
|
38
|
-
return [];
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async analyzeTypeScript(filePath, content, config) {
|
|
43
|
-
const violations = [];
|
|
44
|
-
const lines = content.split('\n');
|
|
45
|
-
|
|
46
|
-
// Parse TypeScript/JavaScript code
|
|
47
|
-
const sourceFile = ts.createSourceFile(
|
|
48
|
-
filePath,
|
|
49
|
-
content,
|
|
50
|
-
ts.ScriptTarget.Latest,
|
|
51
|
-
true
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
const visit = (node) => {
|
|
55
|
-
// Check function declarations (skip declare statements without body)
|
|
56
|
-
if (ts.isFunctionDeclaration(node) && node.name && node.body) {
|
|
57
|
-
const functionName = node.name.text;
|
|
58
|
-
const analysis = this.analyzeFunctionName(functionName);
|
|
59
|
-
|
|
60
|
-
if (analysis.isViolation) {
|
|
61
|
-
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
|
|
62
|
-
const column = sourceFile.getLineAndCharacterOfPosition(node.getStart()).character + 1;
|
|
63
|
-
const lineText = lines[line - 1]?.trim() || '';
|
|
64
|
-
|
|
65
|
-
violations.push({
|
|
66
|
-
ruleId: this.ruleId,
|
|
67
|
-
file: filePath,
|
|
68
|
-
line,
|
|
69
|
-
column,
|
|
70
|
-
message: analysis.reason,
|
|
71
|
-
severity: analysis.severity || 'warning',
|
|
72
|
-
code: lineText,
|
|
73
|
-
type: analysis.type,
|
|
74
|
-
confidence: analysis.confidence || 0.8,
|
|
75
|
-
suggestion: analysis.suggestion
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Check method declarations
|
|
81
|
-
if (ts.isMethodDeclaration(node) && node.name) {
|
|
82
|
-
const methodName = node.name.text;
|
|
83
|
-
const analysis = this.analyzeFunctionName(methodName);
|
|
84
|
-
|
|
85
|
-
if (analysis.isViolation) {
|
|
86
|
-
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
|
|
87
|
-
const column = sourceFile.getLineAndCharacterOfPosition(node.getStart()).character + 1;
|
|
88
|
-
const lineText = lines[line - 1]?.trim() || '';
|
|
89
|
-
|
|
90
|
-
violations.push({
|
|
91
|
-
ruleId: this.ruleId,
|
|
92
|
-
file: filePath,
|
|
93
|
-
line,
|
|
94
|
-
column,
|
|
95
|
-
message: analysis.reason,
|
|
96
|
-
severity: analysis.severity || 'warning',
|
|
97
|
-
code: lineText,
|
|
98
|
-
type: analysis.type,
|
|
99
|
-
confidence: analysis.confidence || 0.8,
|
|
100
|
-
suggestion: analysis.suggestion
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Check arrow functions assigned to variables
|
|
106
|
-
if (ts.isVariableDeclaration(node) && node.name && ts.isIdentifier(node.name) &&
|
|
107
|
-
node.initializer && ts.isArrowFunction(node.initializer)) {
|
|
108
|
-
const functionName = node.name.text;
|
|
109
|
-
const analysis = this.analyzeFunctionName(functionName);
|
|
110
|
-
|
|
111
|
-
if (analysis.isViolation) {
|
|
112
|
-
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
|
|
113
|
-
const column = sourceFile.getLineAndCharacterOfPosition(node.getStart()).character + 1;
|
|
114
|
-
const lineText = lines[line - 1]?.trim() || '';
|
|
115
|
-
|
|
116
|
-
violations.push({
|
|
117
|
-
ruleId: this.ruleId,
|
|
118
|
-
file: filePath,
|
|
119
|
-
line,
|
|
120
|
-
column,
|
|
121
|
-
message: analysis.reason,
|
|
122
|
-
severity: analysis.severity || 'warning',
|
|
123
|
-
code: lineText,
|
|
124
|
-
type: analysis.type,
|
|
125
|
-
confidence: analysis.confidence || 0.8,
|
|
126
|
-
suggestion: analysis.suggestion
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
ts.forEachChild(node, visit);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
visit(sourceFile);
|
|
135
|
-
return violations;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async analyzeDart(filePath, content, config) {
|
|
139
|
-
const violations = [];
|
|
140
|
-
const lines = content.split('\n');
|
|
141
|
-
|
|
142
|
-
// Pattern-based analysis for Dart function declarations
|
|
143
|
-
const functionPattern = /^\s*(\w+\s+)?(\w+)\s*\([^)]*\)\s*\{?/;
|
|
144
|
-
|
|
145
|
-
lines.forEach((line, index) => {
|
|
146
|
-
const lineNumber = index + 1;
|
|
147
|
-
const match = line.match(functionPattern);
|
|
148
|
-
|
|
149
|
-
if (match) {
|
|
150
|
-
const functionName = match[2];
|
|
151
|
-
|
|
152
|
-
// Skip constructors, getters, setters, and built-in methods
|
|
153
|
-
if (this.isSpecialFunction(functionName)) {
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const analysis = this.analyzeFunctionName(functionName);
|
|
158
|
-
|
|
159
|
-
if (analysis.isViolation) {
|
|
160
|
-
violations.push({
|
|
161
|
-
ruleId: this.ruleId,
|
|
162
|
-
file: filePath,
|
|
163
|
-
line: lineNumber,
|
|
164
|
-
column: line.indexOf(functionName) + 1,
|
|
165
|
-
message: analysis.reason,
|
|
166
|
-
severity: analysis.severity || 'warning',
|
|
167
|
-
code: line.trim(),
|
|
168
|
-
type: analysis.type,
|
|
169
|
-
confidence: analysis.confidence || 0.7,
|
|
170
|
-
suggestion: analysis.suggestion
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
return violations;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
async analyzeKotlin(filePath, content, config) {
|
|
180
|
-
const violations = [];
|
|
181
|
-
const lines = content.split('\n');
|
|
182
|
-
|
|
183
|
-
// Pattern-based analysis for Kotlin function declarations
|
|
184
|
-
const functionPattern = /^\s*(?:fun|private\s+fun|public\s+fun|internal\s+fun|override\s+fun)\s+(\w+)\s*\(/;
|
|
185
|
-
|
|
186
|
-
lines.forEach((line, index) => {
|
|
187
|
-
const lineNumber = index + 1;
|
|
188
|
-
const match = line.match(functionPattern);
|
|
189
|
-
|
|
190
|
-
if (match) {
|
|
191
|
-
const functionName = match[1];
|
|
192
|
-
|
|
193
|
-
// Skip constructors and built-in methods
|
|
194
|
-
if (this.isSpecialFunction(functionName)) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const analysis = this.analyzeFunctionName(functionName);
|
|
199
|
-
|
|
200
|
-
if (analysis.isViolation) {
|
|
201
|
-
violations.push({
|
|
202
|
-
ruleId: this.ruleId,
|
|
203
|
-
file: filePath,
|
|
204
|
-
line: lineNumber,
|
|
205
|
-
column: line.indexOf(functionName) + 1,
|
|
206
|
-
message: analysis.reason,
|
|
207
|
-
severity: analysis.severity || 'warning',
|
|
208
|
-
code: line.trim(),
|
|
209
|
-
type: analysis.type,
|
|
210
|
-
confidence: analysis.confidence || 0.7,
|
|
211
|
-
suggestion: analysis.suggestion
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
return violations;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
analyzeFunctionName(functionName) {
|
|
221
|
-
// Skip special functions
|
|
222
|
-
if (this.isSpecialFunction(functionName)) {
|
|
223
|
-
return { isViolation: false };
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Common verbs for function names
|
|
227
|
-
const commonVerbs = [
|
|
228
|
-
'get', 'set', 'is', 'has', 'can', 'should', 'will', 'does',
|
|
229
|
-
'create', 'build', 'make', 'generate', 'construct',
|
|
230
|
-
'update', 'modify', 'change', 'edit', 'alter',
|
|
231
|
-
'delete', 'remove', 'destroy', 'clean', 'clear',
|
|
232
|
-
'load', 'save', 'fetch', 'retrieve', 'find', 'search',
|
|
233
|
-
'validate', 'verify', 'check', 'confirm', 'ensure',
|
|
234
|
-
'calculate', 'compute', 'process', 'handle', 'manage',
|
|
235
|
-
'send', 'receive', 'transmit', 'broadcast', 'emit',
|
|
236
|
-
'parse', 'format', 'transform', 'convert', 'map',
|
|
237
|
-
'filter', 'sort', 'group', 'merge', 'split',
|
|
238
|
-
'connect', 'disconnect', 'open', 'close', 'start', 'stop',
|
|
239
|
-
'show', 'hide', 'display', 'render', 'draw', 'paint',
|
|
240
|
-
'add', 'append', 'insert', 'push', 'pop', 'shift',
|
|
241
|
-
'test', 'debug', 'log', 'trace', 'monitor', 'watch',
|
|
242
|
-
'count', 'execute', 'perform', 'run', 'invoke', 'call',
|
|
243
|
-
'reset', 'initialize', 'setup', 'configure', 'prepare',
|
|
244
|
-
'refresh', 'restore', 'reload', 'retry', 'resume', 'redirect',
|
|
245
|
-
'select', 'toggle', 'switch', 'enable', 'disable', 'activate',
|
|
246
|
-
'expand', 'collapse', 'scroll', 'navigate', 'submit', 'cancel',
|
|
247
|
-
|
|
248
|
-
// Based on user feedback - missing important verbs
|
|
249
|
-
'reopen', 'request', 'use', 'go',
|
|
250
|
-
|
|
251
|
-
// Event handler prefixes
|
|
252
|
-
'on',
|
|
253
|
-
|
|
254
|
-
// Common React/JS patterns that should be allowed as verbs
|
|
255
|
-
'count', // can be both noun and verb - when standalone should be allowed
|
|
256
|
-
'request', // can be both noun and verb - when standalone should be allowed
|
|
257
|
-
'process' // can be both noun and verb - when standalone should be allowed
|
|
258
|
-
];
|
|
259
|
-
|
|
260
|
-
// Check if function name starts with a verb
|
|
261
|
-
const startsWithVerb = commonVerbs.some(verb => {
|
|
262
|
-
const verbPattern = new RegExp(`^${verb}[A-Z]?`, 'i');
|
|
263
|
-
return verbPattern.test(functionName);
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
if (startsWithVerb) {
|
|
267
|
-
return { isViolation: false };
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Check for camelCase pattern that might be verb-noun
|
|
271
|
-
const camelCasePattern = /^[a-z][a-zA-Z0-9]*$/;
|
|
272
|
-
const pascalCasePattern = /^[A-Z][a-zA-Z0-9]*$/;
|
|
273
|
-
|
|
274
|
-
// PascalCase functions (likely React components) - different rules
|
|
275
|
-
if (pascalCasePattern.test(functionName)) {
|
|
276
|
-
// For React components, we can be more lenient but still suggest verb patterns where appropriate
|
|
277
|
-
return {
|
|
278
|
-
isViolation: true,
|
|
279
|
-
reason: 'PascalCase function should be a React component or use verb-noun pattern',
|
|
280
|
-
severity: 'info',
|
|
281
|
-
type: 'react_component_naming',
|
|
282
|
-
confidence: 0.5,
|
|
283
|
-
suggestion: `If this is a React component, consider using descriptive names. If it's a function, use camelCase with verb-noun pattern.`
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (!camelCasePattern.test(functionName)) {
|
|
288
|
-
return {
|
|
289
|
-
isViolation: true,
|
|
290
|
-
reason: 'Function name should follow camelCase and verb-noun pattern',
|
|
291
|
-
severity: 'warning',
|
|
292
|
-
type: 'naming_convention',
|
|
293
|
-
confidence: 0.9,
|
|
294
|
-
suggestion: 'Use camelCase with verb-noun pattern (e.g., getUserData, validateInput)'
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Check for noun-only patterns (likely violations)
|
|
299
|
-
const nounOnlyPatterns = [
|
|
300
|
-
/^[a-z]+$/, // simple lowercase (e.g., 'user', 'data')
|
|
301
|
-
/^[a-z]+[A-Z][a-z]+$/, // simple camelCase noun (e.g., 'userData', 'userInfo')
|
|
302
|
-
];
|
|
303
|
-
|
|
304
|
-
const isNounOnly = nounOnlyPatterns.some(pattern => pattern.test(functionName));
|
|
305
|
-
|
|
306
|
-
if (isNounOnly) {
|
|
307
|
-
return {
|
|
308
|
-
isViolation: true,
|
|
309
|
-
reason: 'Function name appears to be a noun - should start with a verb',
|
|
310
|
-
severity: 'warning',
|
|
311
|
-
type: 'missing_verb',
|
|
312
|
-
confidence: 0.8,
|
|
313
|
-
suggestion: `Consider renaming to use verb-noun pattern (e.g., get${functionName.charAt(0).toUpperCase() + functionName.slice(1)})`
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// If it's a complex name without obvious verb, flag as potential violation
|
|
318
|
-
if (functionName.length > 3 && !functionName.match(/^[a-z]+[A-Z]/)) {
|
|
319
|
-
return {
|
|
320
|
-
isViolation: true,
|
|
321
|
-
reason: 'Function name should follow verb-noun pattern for clarity',
|
|
322
|
-
severity: 'info',
|
|
323
|
-
type: 'unclear_naming',
|
|
324
|
-
confidence: 0.6,
|
|
325
|
-
suggestion: 'Consider using verb-noun pattern for better readability'
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return { isViolation: false };
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
isSpecialFunction(name) {
|
|
333
|
-
const specialFunctions = [
|
|
334
|
-
'constructor', 'toString', 'valueOf', 'toJSON',
|
|
335
|
-
'main', 'init', 'setup', 'teardown', 'build',
|
|
336
|
-
'onCreate', 'onDestroy', 'onStart', 'onStop',
|
|
337
|
-
'onPause', 'onResume', 'onSaveInstanceState',
|
|
338
|
-
'equals', 'hashCode', 'compareTo', 'clone',
|
|
339
|
-
'finalize', 'notify', 'notifyAll', 'wait'
|
|
340
|
-
];
|
|
341
|
-
|
|
342
|
-
return specialFunctions.includes(name) ||
|
|
343
|
-
name.startsWith('_') ||
|
|
344
|
-
name.startsWith('$');
|
|
345
|
-
// Removed: || name.match(/^[A-Z]/); // Allow checking React components
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
module.exports = new C006Analyzer();
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"ruleId": "C006",
|
|
3
|
-
"name": "Function Naming Convention",
|
|
4
|
-
"description": "Tên hàm phải là động từ/verb-noun pattern",
|
|
5
|
-
"category": "naming",
|
|
6
|
-
"severity": "warning",
|
|
7
|
-
"languages": ["typescript", "dart", "kotlin"],
|
|
8
|
-
"version": "1.0.0",
|
|
9
|
-
"status": "activated",
|
|
10
|
-
"tags": ["naming", "convention", "readability"],
|
|
11
|
-
"config": {
|
|
12
|
-
"commonVerbs": [
|
|
13
|
-
"get", "set", "is", "has", "can", "should", "will",
|
|
14
|
-
"create", "build", "make", "generate", "construct",
|
|
15
|
-
"update", "modify", "change", "edit", "alter",
|
|
16
|
-
"delete", "remove", "destroy", "clean", "clear",
|
|
17
|
-
"load", "save", "fetch", "retrieve", "find", "search",
|
|
18
|
-
"validate", "verify", "check", "confirm", "ensure",
|
|
19
|
-
"calculate", "compute", "process", "handle", "manage",
|
|
20
|
-
"send", "receive", "transmit", "broadcast", "emit",
|
|
21
|
-
"parse", "format", "transform", "convert", "map",
|
|
22
|
-
"filter", "sort", "group", "merge", "split",
|
|
23
|
-
"connect", "disconnect", "open", "close", "start", "stop",
|
|
24
|
-
"show", "hide", "display", "render", "draw", "paint",
|
|
25
|
-
"add", "append", "insert", "push", "pop", "shift",
|
|
26
|
-
"test", "debug", "log", "trace", "monitor", "watch"
|
|
27
|
-
],
|
|
28
|
-
"specialFunctions": [
|
|
29
|
-
"constructor", "toString", "valueOf", "toJSON",
|
|
30
|
-
"main", "init", "setup", "teardown", "build",
|
|
31
|
-
"onCreate", "onDestroy", "onStart", "onStop",
|
|
32
|
-
"onPause", "onResume", "onSaveInstanceState",
|
|
33
|
-
"equals", "hashCode", "compareTo", "clone",
|
|
34
|
-
"finalize", "notify", "notifyAll", "wait"
|
|
35
|
-
],
|
|
36
|
-
"patterns": {
|
|
37
|
-
"camelCase": "^[a-z][a-zA-Z0-9]*$",
|
|
38
|
-
"verbNoun": "^(get|set|is|has|can|create|update|delete|load|save|find|validate|process|handle|calculate|send|receive|parse|format|transform|filter|sort|connect|show|hide|add|remove)[A-Z][a-zA-Z0-9]*$"
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
"examples": {
|
|
42
|
-
"violations": [
|
|
43
|
-
{
|
|
44
|
-
"language": "typescript",
|
|
45
|
-
"code": "function userData() { return user.data; }",
|
|
46
|
-
"reason": "Function name is a noun - should start with a verb like 'getUserData'"
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"language": "typescript",
|
|
50
|
-
"code": "function calculation() { return x + y; }",
|
|
51
|
-
"reason": "Should use verb-noun pattern like 'calculateSum' or 'performCalculation'"
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
"language": "dart",
|
|
55
|
-
"code": "String userInfo() { return 'info'; }",
|
|
56
|
-
"reason": "Function name should start with verb like 'getUserInfo'"
|
|
57
|
-
}
|
|
58
|
-
],
|
|
59
|
-
"valid": [
|
|
60
|
-
{
|
|
61
|
-
"language": "typescript",
|
|
62
|
-
"code": "function getUserData() { return user.data; }",
|
|
63
|
-
"reason": "Follows verb-noun pattern"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
"language": "typescript",
|
|
67
|
-
"code": "function isValid() { return true; }",
|
|
68
|
-
"reason": "Starts with verb 'is'"
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
"language": "dart",
|
|
72
|
-
"code": "bool hasPermission() { return true; }",
|
|
73
|
-
"reason": "Starts with verb 'has'"
|
|
74
|
-
}
|
|
75
|
-
]
|
|
76
|
-
},
|
|
77
|
-
"fixes": {
|
|
78
|
-
"autoFixable": false,
|
|
79
|
-
"suggestions": [
|
|
80
|
-
"Start function names with verbs (get, set, is, has, create, update, etc.)",
|
|
81
|
-
"Use verb-noun pattern for clarity (e.g., getUserData, validateInput)",
|
|
82
|
-
"Avoid noun-only function names",
|
|
83
|
-
"Use camelCase convention"
|
|
84
|
-
]
|
|
85
|
-
}
|
|
86
|
-
}
|