@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.
Files changed (74) hide show
  1. package/.sunlint.json +1 -1
  2. package/CHANGELOG.md +83 -0
  3. package/README.md +66 -4
  4. package/config/presets/all.json +125 -0
  5. package/config/presets/beginner.json +16 -8
  6. package/config/presets/ci.json +12 -4
  7. package/config/presets/maintainability.json +38 -0
  8. package/config/presets/performance.json +32 -0
  9. package/config/presets/quality.json +103 -0
  10. package/config/presets/recommended.json +36 -12
  11. package/config/presets/security.json +88 -0
  12. package/config/presets/strict.json +15 -5
  13. package/config/rules/rules-registry-generated.json +6312 -0
  14. package/config/rules-summary.json +1941 -0
  15. package/core/adapters/sunlint-rule-adapter.js +452 -0
  16. package/core/analysis-orchestrator.js +4 -4
  17. package/core/config-manager.js +28 -5
  18. package/core/rule-selection-service.js +52 -55
  19. package/docs/CONFIGURATION.md +111 -3
  20. package/docs/LANGUAGE-SPECIFIC-RULES.md +308 -0
  21. package/docs/README.md +3 -0
  22. package/docs/STANDARDIZED-CATEGORY-FILTERING.md +156 -0
  23. package/engines/eslint-engine.js +92 -2
  24. package/engines/heuristic-engine.js +8 -31
  25. package/origin-rules/common-en.md +1320 -0
  26. package/origin-rules/dart-en.md +289 -0
  27. package/origin-rules/java-en.md +60 -0
  28. package/origin-rules/kotlin-mobile-en.md +453 -0
  29. package/origin-rules/reactjs-en.md +102 -0
  30. package/origin-rules/security-en.md +1055 -0
  31. package/origin-rules/swift-en.md +449 -0
  32. package/origin-rules/typescript-en.md +136 -0
  33. package/package.json +6 -5
  34. package/scripts/copy-rules.js +86 -0
  35. package/rules/README.md +0 -252
  36. package/rules/common/C002_no_duplicate_code/analyzer.js +0 -65
  37. package/rules/common/C002_no_duplicate_code/config.json +0 -23
  38. package/rules/common/C003_no_vague_abbreviations/analyzer.js +0 -418
  39. package/rules/common/C003_no_vague_abbreviations/config.json +0 -35
  40. package/rules/common/C006_function_naming/analyzer.js +0 -349
  41. package/rules/common/C006_function_naming/config.json +0 -86
  42. package/rules/common/C010_limit_block_nesting/analyzer.js +0 -389
  43. package/rules/common/C013_no_dead_code/analyzer.js +0 -206
  44. package/rules/common/C014_dependency_injection/analyzer.js +0 -338
  45. package/rules/common/C017_constructor_logic/analyzer.js +0 -314
  46. package/rules/common/C019_log_level_usage/analyzer.js +0 -362
  47. package/rules/common/C019_log_level_usage/config.json +0 -121
  48. package/rules/common/C029_catch_block_logging/analyzer.js +0 -373
  49. package/rules/common/C029_catch_block_logging/config.json +0 -59
  50. package/rules/common/C031_validation_separation/analyzer.js +0 -186
  51. package/rules/common/C041_no_sensitive_hardcode/analyzer.js +0 -292
  52. package/rules/common/C042_boolean_name_prefix/analyzer.js +0 -300
  53. package/rules/common/C043_no_console_or_print/analyzer.js +0 -304
  54. package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +0 -351
  55. package/rules/common/C075_explicit_return_types/analyzer.js +0 -103
  56. package/rules/common/C076_single_test_behavior/analyzer.js +0 -121
  57. package/rules/docs/C002_no_duplicate_code.md +0 -57
  58. package/rules/docs/C031_validation_separation.md +0 -72
  59. package/rules/index.js +0 -149
  60. package/rules/migration/converter.js +0 -385
  61. package/rules/migration/mapping.json +0 -164
  62. package/rules/security/S026_json_schema_validation/analyzer.js +0 -251
  63. package/rules/security/S026_json_schema_validation/config.json +0 -27
  64. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +0 -263
  65. package/rules/security/S027_no_hardcoded_secrets/config.json +0 -29
  66. package/rules/security/S029_csrf_protection/analyzer.js +0 -264
  67. package/rules/tests/C002_no_duplicate_code.test.js +0 -50
  68. package/rules/universal/C010/generic.js +0 -0
  69. package/rules/universal/C010/tree-sitter-analyzer.js +0 -0
  70. package/rules/utils/ast-utils.js +0 -191
  71. package/rules/utils/base-analyzer.js +0 -98
  72. package/rules/utils/pattern-matchers.js +0 -239
  73. package/rules/utils/rule-helpers.js +0 -264
  74. 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
- }