@sun-asterisk/sunlint 1.3.30 → 1.3.32

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.
@@ -45,11 +45,92 @@ class SmartC006Analyzer {
45
45
  // Side effect patterns indicate actions
46
46
  ACTION: [/console\./, /fetch\(/, /\.send\(/, /\.post\(/]
47
47
  };
48
+
49
+ // 📚 COMPREHENSIVE VERB LIST (from C006 rule specification)
50
+ this.acceptedVerbs = [
51
+ // Getters/Queries
52
+ 'get', 'fetch', 'retrieve', 'find', 'search', 'query', 'load',
53
+ // Setters/Modifiers
54
+ 'set', 'update', 'modify', 'change', 'edit', 'alter', 'transform',
55
+ // Creation
56
+ 'create', 'build', 'make', 'generate', 'construct', 'produce',
57
+ // Deletion
58
+ 'delete', 'remove', 'destroy', 'clean', 'clear', 'reset',
59
+ // Validation
60
+ 'validate', 'verify', 'check', 'confirm', 'ensure', 'test', 'compare',
61
+ // Computation
62
+ 'calculate', 'compute', 'parse', 'format', 'convert',
63
+ // Communication
64
+ 'send', 'receive', 'transmit', 'broadcast', 'emit', 'publish',
65
+ // Collections
66
+ 'map', 'filter', 'sort', 'group', 'merge', 'split', 'add', 'append', 'insert',
67
+ 'push', 'pop', 'shift', 'splice', 'unshift', 'slice', 'concat', 'join',
68
+ // State checks (Boolean)
69
+ 'is', 'has', 'can', 'should', 'will', 'does', 'contains', 'includes', 'exists',
70
+ // UI actions
71
+ 'show', 'hide', 'display', 'render', 'draw', 'toggle', 'enable', 'disable',
72
+ 'activate', 'deactivate', 'select', 'deselect', 'focus', 'blur',
73
+ // Lifecycle
74
+ 'connect', 'disconnect', 'open', 'close', 'start', 'stop', 'run', 'refresh',
75
+ 'initialize', 'init', 'setup', 'teardown', 'shutdown', 'restart', 'reload',
76
+ 'restore', 'resume', 'pause', 'suspend',
77
+ // Event Handling
78
+ 'on', 'trigger', 'fire', 'dispatch', 'invoke', 'call', 'emit', 'handle',
79
+ // Monitoring
80
+ 'count', 'measure', 'monitor', 'watch', 'track', 'observe', 'log', 'record',
81
+ // Navigation
82
+ 'navigate', 'redirect', 'route', 'go', 'move', 'scroll',
83
+ // Data Operations
84
+ 'save', 'store', 'persist', 'cache', 'serialize', 'deserialize',
85
+ // Detection/Analysis
86
+ 'detect', 'analyze', 'scan', 'inspect', 'evaluate', 'assess',
87
+ // Computation & Transformation
88
+ 'calculate', 'compute', 'parse', 'format', 'convert',
89
+ 'normalize', 'sanitize', 'encode', 'decode', 'encrypt', 'decrypt',
90
+ 'compress', 'decompress', 'zip', 'unzip', 'tar', 'untar', // ← Add these
91
+ 'stringify', 'objectify',
92
+ // State Management
93
+ 'apply', 'revert', 'undo', 'redo', 'commit', 'rollback',
94
+ // Async Operations
95
+ 'await', 'defer', 'debounce', 'throttle', 'delay',
96
+ // Error Handling
97
+ 'throw', 'catch', 'handle', 'recover', 'retry',
98
+ // Copying/Cloning
99
+ 'copy', 'clone', 'duplicate', 'replicate',
100
+ // Comparison
101
+ 'equals', 'match', 'differ', 'compare',
102
+ // Registration
103
+ 'register', 'unregister', 'subscribe', 'unsubscribe',
104
+ // Import/Export
105
+ 'import', 'export', 'download', 'upload',
106
+ // Expansion/Collapse
107
+ 'expand', 'collapse', 'maximize', 'minimize',
108
+ // Submission
109
+ 'submit', 'cancel', 'abort', 'complete', 'finish',
110
+ // Preparation
111
+ 'prepare', 'ready', 'preload', 'precache',
112
+ // Extraction
113
+ 'extract', 'derive', 'obtain', 'acquire',
114
+ // Replacement
115
+ 'replace', 'swap', 'substitute', 'override',
116
+ // Binding
117
+ 'bind', 'unbind', 'attach', 'detach',
118
+ // Notification
119
+ 'notify', 'alert', 'warn', 'inform',
120
+ // Execution
121
+ 'execute', 'perform', 'process', 'run'
122
+ ];
123
+
124
+ // ⚠️ VAGUE/GENERIC VERBS TO FLAG (should have more specific verbs)
125
+ this.vagueVerbs = [
126
+ 'do', 'handle', 'manage', 'process', 'execute', 'perform',
127
+ 'something', 'stuff', 'thing', 'work', 'data', 'item'
128
+ ];
48
129
  }
49
130
 
50
131
  async analyze(files, language, config) {
51
132
  const violations = [];
52
-
133
+
53
134
  if (config.verbose) {
54
135
  console.log(`🔧 [DEBUG] Starting Smart C006 Analysis on ${files.length} files...`);
55
136
  }
@@ -69,7 +150,7 @@ class SmartC006Analyzer {
69
150
  if (config.verbose) {
70
151
  console.log(`🔧 [DEBUG] Smart C006 Analysis complete: ${violations.length} violations found`);
71
152
  }
72
-
153
+
73
154
  return violations;
74
155
  }
75
156
 
@@ -80,10 +161,10 @@ class SmartC006Analyzer {
80
161
 
81
162
  const violations = [];
82
163
  const lines = content.split('\n');
83
-
164
+
84
165
  // 🏗️ TIER 1: ARCHITECTURAL CONTEXT ANALYSIS
85
166
  const architecturalContext = this.analyzeArchitecturalContext(filePath, content);
86
-
167
+
87
168
  // Parse TypeScript/JavaScript code
88
169
  const sourceFile = ts.createSourceFile(
89
170
  filePath,
@@ -102,13 +183,13 @@ class SmartC006Analyzer {
102
183
  architecturalContext,
103
184
  content
104
185
  );
105
-
186
+
106
187
  if (analysis.isViolation && analysis.confidence >= this.confidenceThresholds.LOW) {
107
188
  const namePosition = sourceFile.getLineAndCharacterOfPosition(node.name.getStart());
108
189
  const line = namePosition.line + 1;
109
190
  const column = namePosition.character + 1;
110
191
  const lineText = lines[line - 1]?.trim() || '';
111
-
192
+
112
193
  violations.push({
113
194
  ruleId: this.ruleId,
114
195
  file: filePath,
@@ -134,13 +215,13 @@ class SmartC006Analyzer {
134
215
  architecturalContext,
135
216
  content
136
217
  );
137
-
218
+
138
219
  if (analysis.isViolation && analysis.confidence >= this.confidenceThresholds.LOW) {
139
220
  const namePosition = sourceFile.getLineAndCharacterOfPosition(node.name.getStart());
140
221
  const line = namePosition.line + 1;
141
222
  const column = namePosition.character + 1;
142
223
  const lineText = lines[line - 1]?.trim() || '';
143
-
224
+
144
225
  violations.push({
145
226
  ruleId: this.ruleId,
146
227
  file: filePath,
@@ -158,7 +239,7 @@ class SmartC006Analyzer {
158
239
  }
159
240
 
160
241
  // Analyze arrow functions assigned to variables
161
- if (ts.isVariableDeclaration(node) && node.name && ts.isIdentifier(node.name) &&
242
+ if (ts.isVariableDeclaration(node) && node.name && ts.isIdentifier(node.name) &&
162
243
  node.initializer && ts.isArrowFunction(node.initializer)) {
163
244
  const analysis = this.smartAnalyzeFunctionName(
164
245
  node.name.text,
@@ -167,13 +248,13 @@ class SmartC006Analyzer {
167
248
  architecturalContext,
168
249
  content
169
250
  );
170
-
251
+
171
252
  if (analysis.isViolation && analysis.confidence >= this.confidenceThresholds.LOW) {
172
253
  const namePosition = sourceFile.getLineAndCharacterOfPosition(node.name.getStart());
173
254
  const line = namePosition.line + 1;
174
255
  const column = namePosition.character + 1;
175
256
  const lineText = lines[line - 1]?.trim() || '';
176
-
257
+
177
258
  violations.push({
178
259
  ruleId: this.ruleId,
179
260
  file: filePath,
@@ -189,7 +270,7 @@ class SmartC006Analyzer {
189
270
  });
190
271
  }
191
272
  }
192
-
273
+
193
274
  ts.forEachChild(node, visit);
194
275
  };
195
276
 
@@ -204,7 +285,7 @@ class SmartC006Analyzer {
204
285
  analyzeArchitecturalContext(filePath, content) {
205
286
  const fileName = path.basename(filePath, path.extname(filePath)).toLowerCase();
206
287
  const fileDir = path.dirname(filePath).toLowerCase();
207
-
288
+
208
289
  // Detect architectural layer
209
290
  let layer = 'UNKNOWN';
210
291
  for (const [layerName, patterns] of Object.entries(this.architecturalLayers)) {
@@ -213,12 +294,12 @@ class SmartC006Analyzer {
213
294
  break;
214
295
  }
215
296
  }
216
-
297
+
217
298
  // Analyze imports for additional context
218
299
  const imports = this.extractImports(content);
219
300
  const isReactComponent = imports.some(imp => imp.includes('react')) || content.includes('JSX.Element');
220
301
  const isTestFile = fileName.includes('test') || fileName.includes('spec');
221
-
302
+
222
303
  return {
223
304
  layer,
224
305
  isReactComponent,
@@ -234,83 +315,96 @@ class SmartC006Analyzer {
234
315
  */
235
316
  analyzeSemanticIntent(functionNode, sourceFile, content) {
236
317
  if (!functionNode.body) return 'UNKNOWN';
237
-
318
+
238
319
  const functionText = content.substring(
239
320
  functionNode.body.getStart(),
240
321
  functionNode.body.getEnd()
241
322
  );
242
-
323
+
243
324
  // Check for different semantic patterns
244
325
  for (const [intent, patterns] of Object.entries(this.semanticPatterns)) {
245
326
  if (patterns.some(pattern => pattern.test(functionText))) {
246
327
  return intent;
247
328
  }
248
329
  }
249
-
330
+
250
331
  return 'UNKNOWN';
251
332
  }
252
333
 
253
334
  /**
254
- * 🎯 TIER 3: INTELLIGENT VERB DETECTION
255
- * Uses multiple strategies to detect verbs
335
+ * 🎯 ENHANCED VERB DETECTION - FIXED VERSION
336
+ * Properly detects verbs including compound verbs
256
337
  */
257
- isVerbLikeName(functionName) {
258
- // Strategy 0: REJECT generic/vague verbs that should be flagged
259
- const genericVerbs = [
260
- 'do', 'handle', 'process', 'manage', 'execute',
261
- 'something', 'stuff', 'thing', 'work', 'data'
262
- ];
263
-
264
- const isGenericVerb = genericVerbs.some(verb => {
265
- const verbPattern = new RegExp(`^${verb}([A-Z].*|$)`, 'i');
266
- return verbPattern.test(functionName);
267
- });
268
-
269
- // Reject names starting with generic verbs
270
- if (isGenericVerb) return false;
271
-
272
- // Strategy 1: Known verb prefixes (expanded beyond static list)
273
- const verbPrefixes = [
274
- 'get', 'set', 'is', 'has', 'can', 'should', 'will', 'does',
275
- 'create', 'build', 'make', 'generate', 'construct', 'produce',
276
- 'update', 'modify', 'change', 'edit', 'alter', 'transform',
277
- 'delete', 'remove', 'destroy', 'clean', 'clear', 'reset',
278
- 'load', 'save', 'fetch', 'retrieve', 'find', 'search', 'query',
279
- 'validate', 'verify', 'check', 'confirm', 'ensure', 'test',
280
- 'calculate', 'compute', 'compare', 'parse', 'format', 'convert',
281
- 'send', 'receive', 'transmit', 'broadcast', 'emit', 'publish',
282
- 'map', 'filter', 'sort', 'group', 'merge', 'split',
283
- 'connect', 'disconnect', 'open', 'close', 'start', 'stop', 'run',
284
- 'show', 'hide', 'display', 'render', 'draw', 'paint', 'animate',
285
- 'add', 'append', 'insert', 'push', 'pop', 'shift', 'splice',
286
- 'count', 'measure', 'monitor', 'watch', 'track', 'observe',
287
- 'refresh', 'restore', 'reload', 'retry', 'resume', 'redirect',
288
- 'select', 'toggle', 'switch', 'enable', 'disable', 'activate',
289
- 'expand', 'collapse', 'scroll', 'navigate', 'submit', 'cancel',
290
- 'on', 'trigger', 'fire', 'dispatch', 'invoke', 'call'
291
- ];
292
-
293
- // Strategy 2: Check if starts with known verb
294
- const startsWithVerb = verbPrefixes.some(verb => {
295
- const verbPattern = new RegExp(`^${verb}[A-Z]?`, 'i');
296
- return verbPattern.test(functionName);
297
- });
298
-
299
- if (startsWithVerb) return true;
300
-
301
- // Strategy 3: Common verb suffixes that indicate actions
302
- const actionSuffixes = ['ize', 'ise', 'fy', 'ate', 'en'];
303
- if (actionSuffixes.some(suffix => functionName.endsWith(suffix))) {
304
- return true;
338
+ extractVerbFromName(functionName) {
339
+ // Convert to lowercase for comparison
340
+ const lowerName = functionName.toLowerCase();
341
+
342
+ // Find the longest matching verb from the accepted verbs list
343
+ let matchedVerb = null;
344
+ let maxLength = 0;
345
+
346
+ for (const verb of this.acceptedVerbs) {
347
+ // Check if function name starts with this verb
348
+ // Must be followed by uppercase letter, end of string, or be exact match
349
+ const verbPattern = new RegExp(`^${verb}([A-Z].*|$)`);
350
+
351
+ if (verbPattern.test(functionName) && verb.length > maxLength) {
352
+ matchedVerb = verb;
353
+ maxLength = verb.length;
354
+ }
305
355
  }
306
-
307
- // Strategy 4: English verb patterns (basic NLP)
308
- const verbPatterns = [
309
- /^(re|un|pre|de|dis)[A-Z]/, // prefixed verbs: revalidate, unload, preprocess
310
- /^[a-z]+ly[A-Z]/, // adverb-verb patterns: quicklyProcess
311
- ];
312
-
313
- return verbPatterns.some(pattern => pattern.test(functionName));
356
+
357
+ return matchedVerb;
358
+ }
359
+
360
+ /**
361
+ * 🎯 CHECK IF NAME FOLLOWS VERB-NOUN PATTERN
362
+ */
363
+ isVerbNounPattern(functionName) {
364
+ // Strategy 1: Extract verb from accepted verbs list
365
+ const verb = this.extractVerbFromName(functionName);
366
+
367
+ if (verb) {
368
+ // Check if it's a vague verb (should be flagged even if technically a verb)
369
+ const isVagueVerb = this.vagueVerbs.some(vague => {
370
+ const vaguePattern = new RegExp(`^${vague}([A-Z].*|$)`, 'i');
371
+ return vaguePattern.test(functionName);
372
+ });
373
+
374
+ if (isVagueVerb) {
375
+ return { isValid: false, verb: null, reason: 'vague_verb' };
376
+ }
377
+
378
+ // Valid verb found
379
+ return { isValid: true, verb, reason: null };
380
+ }
381
+
382
+ // Strategy 2: Check for verb-like patterns (morphology)
383
+ const verbSuffixes = ['ize', 'ise', 'fy', 'ate', 'en', 'ing', 'ed'];
384
+ for (const suffix of verbSuffixes) {
385
+ const suffixPattern = new RegExp(`^[a-z]+${suffix}([A-Z].*|$)`, 'i');
386
+ if (suffixPattern.test(functionName)) {
387
+ return { isValid: true, verb: 'morphological', reason: null };
388
+ }
389
+ }
390
+
391
+ // Strategy 3: Check for verb prefixes (re-, un-, pre-, de-, dis-)
392
+ const verbPrefixes = ['re', 'un', 'pre', 'de', 'dis', 'over', 'under', 'out', 'up'];
393
+ for (const prefix of verbPrefixes) {
394
+ // Must be followed by a known verb or capital letter
395
+ const prefixPattern = new RegExp(`^${prefix}[A-Z]`, 'i');
396
+ if (prefixPattern.test(functionName)) {
397
+ // Check if the part after prefix is a known verb
398
+ const remainder = functionName.substring(prefix.length);
399
+ const remainderVerb = this.extractVerbFromName(remainder);
400
+ if (remainderVerb) {
401
+ return { isValid: true, verb: `${prefix}${remainderVerb}`, reason: null };
402
+ }
403
+ }
404
+ }
405
+
406
+ // No verb pattern found
407
+ return { isValid: false, verb: null, reason: 'no_verb' };
314
408
  }
315
409
 
316
410
  /**
@@ -323,29 +417,29 @@ class SmartC006Analyzer {
323
417
  requiredPatterns: [],
324
418
  suggestions: []
325
419
  };
326
-
420
+
327
421
  // React components have different naming conventions
328
422
  if (architecturalContext.isReactComponent) {
329
423
  rules.allowedPatterns.push(/^[A-Z][a-zA-Z]*$/); // PascalCase components
330
424
  rules.allowedPatterns.push(/^use[A-Z][a-zA-Z]*$/); // React hooks
331
425
  rules.allowedPatterns.push(/^handle[A-Z][a-zA-Z]*$/); // Event handlers
332
426
  }
333
-
427
+
334
428
  // Test files have different patterns
335
429
  if (architecturalContext.isTestFile) {
336
430
  rules.allowedPatterns.push(/^(test|it|describe|should|expect)[A-Z]?/);
337
431
  }
338
-
432
+
339
433
  // Data layer functions often have CRUD patterns
340
434
  if (architecturalContext.layer === 'DATA') {
341
- rules.suggestions.push('Consider CRUD verbs: create, read, update, delete');
435
+ rules.suggestions.push('Consider CRUD verbs: create, read, update, delete, fetch, save');
342
436
  }
343
-
437
+
344
438
  // UI layer functions often have interaction verbs
345
439
  if (architecturalContext.layer === 'UI') {
346
- rules.suggestions.push('Consider UI verbs: show, hide, toggle, render, display');
440
+ rules.suggestions.push('Consider UI verbs: show, hide, toggle, render, display, handle');
347
441
  }
348
-
442
+
349
443
  return rules;
350
444
  }
351
445
 
@@ -358,88 +452,103 @@ class SmartC006Analyzer {
358
452
  if (this.isSpecialFunction(functionName, architecturalContext)) {
359
453
  return { isViolation: false };
360
454
  }
361
-
455
+
362
456
  // Get semantic intent
363
457
  const semanticIntent = this.analyzeSemanticIntent(functionNode, sourceFile, content);
364
-
458
+
365
459
  // Get context-specific rules
366
460
  const contextRules = this.getContextSpecificRules(architecturalContext, semanticIntent);
367
-
461
+
368
462
  // Check if allowed by context-specific patterns
369
463
  if (contextRules.allowedPatterns.some(pattern => pattern.test(functionName))) {
370
464
  return { isViolation: false };
371
465
  }
372
-
466
+
373
467
  // Check if name follows verb-noun pattern
374
- const isVerbLike = this.isVerbLikeName(functionName);
375
-
376
- if (isVerbLike) {
468
+ const verbCheck = this.isVerbNounPattern(functionName);
469
+
470
+ if (verbCheck.isValid) {
377
471
  return { isViolation: false };
378
472
  }
379
-
473
+
380
474
  // 🧮 CONFIDENCE CALCULATION
381
475
  let confidence = 0.5; // Base confidence
382
-
383
- // Boost confidence for clearly generic/vague patterns
384
- const vagueFunctionNames = [
385
- 'doSomething', 'handleStuff', 'processData', 'processInfo',
386
- 'executeWork', 'manageItems', 'doWork', 'handleData',
387
- 'something', 'stuff', 'thing', 'data', 'info', 'item'
388
- ];
389
-
390
- if (vagueFunctionNames.some(vague => functionName.toLowerCase().includes(vague.toLowerCase()))) {
391
- confidence += 0.4; // Strongly boost confidence for obviously vague names
392
- }
393
-
394
- // Boost confidence for clear noun-only patterns
395
- if (/^[a-z]+$/.test(functionName)) {
396
- confidence += 0.3; // Simple lowercase nouns: user, data
397
- }
398
-
399
- if (/^[a-z]+[A-Z][a-z]+$/.test(functionName)) {
400
- confidence += 0.2; // Simple camelCase nouns: userData, userInfo
476
+ let violationType = 'no_verb';
477
+
478
+ if (verbCheck.reason === 'vague_verb') {
479
+ violationType = 'vague_verb';
480
+ confidence = 0.9; // High confidence for vague verbs
481
+ } else if (verbCheck.reason === 'no_verb') {
482
+ violationType = 'no_verb';
483
+
484
+ // Check for obviously wrong patterns
485
+ const commonNounPatterns = [
486
+ /^(user|data|info|item|list|config|settings|options|params|args|props|state|value|result|response|request|error|message|event|callback|handler)([A-Z][a-z]*)*$/i,
487
+ /^[a-z]+$/, // Simple lowercase words
488
+ /^[a-z]+[A-Z][a-z]+$/ // Simple camelCase nouns
489
+ ];
490
+
491
+ if (commonNounPatterns.some(pattern => pattern.test(functionName))) {
492
+ confidence = 0.8; // High confidence for obvious nouns
493
+ }
494
+
495
+ // Boost confidence for clearly generic patterns
496
+ const vagueFunctionNames = [
497
+ 'something', 'stuff', 'thing', 'data', 'info', 'item',
498
+ 'work', 'task', 'job', 'action', 'operation'
499
+ ];
500
+
501
+ if (vagueFunctionNames.some(vague => functionName.toLowerCase().includes(vague.toLowerCase()))) {
502
+ confidence = 0.95; // Very high confidence
503
+ }
401
504
  }
402
-
403
- // Reduce confidence for complex names (might have hidden verbs)
404
- if (functionName.length > 15) {
405
- confidence -= 0.1;
505
+
506
+ // Reduce confidence for complex names (might have hidden patterns)
507
+ if (functionName.length > 20) {
508
+ confidence -= 0.15;
406
509
  }
407
-
510
+
408
511
  // Reduce confidence for utils/helpers (more flexible naming)
409
512
  if (architecturalContext.layer === 'UTILS') {
410
513
  confidence -= 0.2;
411
514
  }
412
-
515
+
413
516
  // Reduce confidence for test files
414
517
  if (architecturalContext.isTestFile) {
415
518
  confidence -= 0.3;
416
519
  }
417
-
520
+
418
521
  // Cap confidence
419
522
  confidence = Math.min(Math.max(confidence, 0.1), 1.0);
420
-
523
+
421
524
  // 💬 INTELLIGENT MESSAGING
422
525
  const context = {
423
526
  layer: architecturalContext.layer,
424
527
  intent: semanticIntent,
425
528
  isReactComponent: architecturalContext.isReactComponent,
426
- isTestFile: architecturalContext.isTestFile
529
+ isTestFile: architecturalContext.isTestFile,
530
+ violationType
427
531
  };
428
-
429
- let reason = `Function '${functionName}' should follow verb-noun naming pattern`;
430
- let suggestion = this.generateSmartSuggestion(functionName, semanticIntent, architecturalContext);
532
+
533
+ let reason = '';
534
+ let suggestion = '';
535
+
536
+ if (violationType === 'vague_verb') {
537
+ reason = `Function '${functionName}' uses vague verb. Use more specific action verbs (see C006 accepted verbs list)`;
538
+ suggestion = this.generateSmartSuggestion(functionName, semanticIntent, architecturalContext, true);
539
+ } else {
540
+ reason = `Function '${functionName}' must start with a verb (verb-noun pattern required by C006)`;
541
+ suggestion = this.generateSmartSuggestion(functionName, semanticIntent, architecturalContext, false);
542
+ }
431
543
 
432
544
  if (architecturalContext.layer !== 'UNKNOWN') {
433
545
  reason += ` (${architecturalContext.layer} layer)`;
434
546
  }
435
547
 
436
- // Add helpful note about accepted verbs
437
- reason += `. Accepted verbs: get, set, create, update, delete, validate, check, compare, etc. See: https://coding-standards.sun-asterisk.vn/rules/rule/C006/`;
438
-
439
548
  return {
440
549
  isViolation: true,
441
550
  reason,
442
- type: 'smart_naming_violation',
551
+ type: `smart_naming_violation_${violationType}`,
443
552
  confidence,
444
553
  suggestion,
445
554
  context
@@ -449,27 +558,51 @@ class SmartC006Analyzer {
449
558
  /**
450
559
  * 💡 SMART SUGGESTION GENERATOR
451
560
  */
452
- generateSmartSuggestion(functionName, semanticIntent, architecturalContext) {
453
- const baseNoun = functionName.charAt(0).toUpperCase() + functionName.slice(1);
454
-
561
+ generateSmartSuggestion(functionName, semanticIntent, architecturalContext, isVagueVerb) {
562
+ // If it's a vague verb, extract the noun part
563
+ let baseNoun = functionName;
564
+
565
+ if (isVagueVerb) {
566
+ // Try to extract the noun part after the vague verb
567
+ for (const vagueVerb of this.vagueVerbs) {
568
+ const pattern = new RegExp(`^${vagueVerb}([A-Z].*)$`, 'i');
569
+ const match = functionName.match(pattern);
570
+ if (match) {
571
+ baseNoun = match[1];
572
+ break;
573
+ }
574
+ }
575
+ }
576
+
577
+ // Ensure first letter is capitalized for camelCase
578
+ baseNoun = baseNoun.charAt(0).toUpperCase() + baseNoun.slice(1);
579
+
580
+ const suggestions = [];
581
+
455
582
  switch (semanticIntent) {
456
583
  case 'GETTER':
457
- return `get${baseNoun}()`;
584
+ suggestions.push(`get${baseNoun}()`, `fetch${baseNoun}()`, `retrieve${baseNoun}()`);
585
+ break;
458
586
  case 'SETTER':
459
- return `set${baseNoun}()`;
587
+ suggestions.push(`set${baseNoun}()`, `update${baseNoun}()`, `save${baseNoun}()`);
588
+ break;
460
589
  case 'CHECKER':
461
- return `is${baseNoun}() or has${baseNoun}()`;
590
+ suggestions.push(`is${baseNoun}()`, `has${baseNoun}()`, `can${baseNoun}()`, `should${baseNoun}()`);
591
+ break;
462
592
  case 'ACTION':
463
- return `process${baseNoun}() or handle${baseNoun}()`;
593
+ suggestions.push(`process${baseNoun}()`, `handle${baseNoun}()`, `execute${baseNoun}()`);
594
+ break;
464
595
  default:
465
596
  if (architecturalContext.layer === 'DATA') {
466
- return `fetch${baseNoun}() or create${baseNoun}()`;
597
+ suggestions.push(`fetch${baseNoun}()`, `create${baseNoun}()`, `save${baseNoun}()`, `load${baseNoun}()`);
598
+ } else if (architecturalContext.layer === 'UI') {
599
+ suggestions.push(`render${baseNoun}()`, `show${baseNoun}()`, `display${baseNoun}()`, `draw${baseNoun}()`);
600
+ } else {
601
+ suggestions.push(`get${baseNoun}()`, `set${baseNoun}()`, `process${baseNoun}()`, `handle${baseNoun}()`);
467
602
  }
468
- if (architecturalContext.layer === 'UI') {
469
- return `render${baseNoun}() or show${baseNoun}()`;
470
- }
471
- return `get${baseNoun}() or process${baseNoun}()`;
472
603
  }
604
+
605
+ return suggestions.slice(0, 3).join(' or ');
473
606
  }
474
607
 
475
608
  /**
@@ -482,29 +615,40 @@ class SmartC006Analyzer {
482
615
  'onCreate', 'onDestroy', 'onStart', 'onStop',
483
616
  'onPause', 'onResume', 'onSaveInstanceState',
484
617
  'equals', 'hashCode', 'compareTo', 'clone',
485
- 'finalize', 'notify', 'notifyAll', 'wait'
618
+ 'finalize', 'notify', 'notifyAll', 'wait', 'bootstrap',
486
619
  ];
487
620
 
621
+ // ignore by patterns
622
+ const patternsToIgnore = [
623
+ /^(setup|config|bootstrap).*/,
624
+ /^_.*/,
625
+ /Factory$/
626
+ ];
627
+
628
+ if (patternsToIgnore.some(pattern => pattern.test(name))) {
629
+ return true;
630
+ }
631
+
488
632
  // Basic special function check
489
633
  if (specialFunctions.includes(name) || name.startsWith('_') || name.startsWith('$')) {
490
634
  return true;
491
635
  }
492
-
636
+
493
637
  // React component names (PascalCase)
494
638
  if (architecturalContext.isReactComponent && /^[A-Z][a-zA-Z]*$/.test(name)) {
495
639
  return true;
496
640
  }
497
-
641
+
498
642
  // React hooks
499
643
  if (name.startsWith('use') && /^use[A-Z]/.test(name)) {
500
644
  return true;
501
645
  }
502
-
646
+
503
647
  // Test function names
504
648
  if (architecturalContext.isTestFile && /^(test|it|describe|should|expect)/.test(name)) {
505
649
  return true;
506
650
  }
507
-
651
+
508
652
  return false;
509
653
  }
510
654
 
@@ -515,11 +659,11 @@ class SmartC006Analyzer {
515
659
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
516
660
  const imports = [];
517
661
  let match;
518
-
662
+
519
663
  while ((match = importRegex.exec(content)) !== null) {
520
664
  imports.push(match[1]);
521
665
  }
522
-
666
+
523
667
  return imports;
524
668
  }
525
669