ds-sfcoe-ailabs
Version:
AI-powered code review tool with static analysis integration for comprehensive code quality assessment.
138 lines (137 loc) • 5.28 kB
JavaScript
import { JS_PATTERNS, TEST_PATTERNS } from './constants.js';
import { FileUtils } from './fileUtils.js';
/**
* Utility class for analyzing code content and detecting patterns
* Provides methods for JavaScript anti-pattern detection, test framework validation,
* and general code analysis across different file types
*
* @example
* ```typescript
* // Analyze JavaScript content for anti-patterns
* const entries = CodeAnalysisUtils.analyzeJavaScriptContent('app.js', jsContent, new Set());
*
* // Check for old test framework usage
* const hasOldFramework = CodeAnalysisUtils.hasOldTestFramework(apexContent);
*
* // Extract class name from file path
* const className = CodeAnalysisUtils.extractClassName('MyClass.cls');
* ```
*/
export class CodeAnalysisUtils {
/**
* Check if content contains any JavaScript anti-patterns
*
* @param fileName - The name of the file being analyzed
* @param content - The file content to analyze for JavaScript patterns
* @param addedEntries - Set of already processed entry keys to avoid duplicates
* @returns Array of table entries for JavaScript anti-patterns found
* @example
* ```typescript
* const entries = CodeAnalysisUtils.analyzeJavaScriptContent('app.js', 'var x = 1;', new Set());
* console.log(entries.length); // Number of anti-patterns found
* ```
*/
static analyzeJavaScriptContent(fileName, content, addedEntries) {
const entries = [];
const shortFileName = FileUtils.getFileName(fileName);
const className = FileUtils.removeExtension(shortFileName);
for (const patternInfo of JS_PATTERNS) {
if (content.includes(patternInfo.pattern)) {
const entryKey = `${className}-${patternInfo.ruleId}`;
if (!addedEntries.has(entryKey)) {
entries.push({
className: shortFileName,
lineNumber: 1,
ruleType: patternInfo.ruleType,
issue: patternInfo.issue,
suggestedFix: patternInfo.suggestedFix,
});
addedEntries.add(entryKey);
}
}
}
return entries;
}
/**
* Check if file uses old test framework patterns
*
* @param content - The file content to analyze
* @returns True if the file uses old test framework (no new framework patterns found)
* @example
* ```typescript
* const hasOldFramework = CodeAnalysisUtils.hasOldTestFramework('Test.startTest();');
* console.log(hasOldFramework); // true
* ```
*/
static hasOldTestFramework(content) {
return ![
TEST_PATTERNS.SOBJECT_MOCKER,
TEST_PATTERNS.CLASS_MOCKER,
TEST_PATTERNS.GENERATE_MOCK_SOBJECT,
].some((pattern) => content.includes(pattern));
}
/**
* Check if content contains specific pattern
*
* @param content - The content to search in
* @param pattern - The pattern to search for
* @returns True if the pattern is found in the content
* @example
* ```typescript
* const hasPattern = CodeAnalysisUtils.containsPattern('var x = 1;', 'var');
* console.log(hasPattern); // true
* ```
*/
static containsPattern(content, pattern) {
return content.includes(pattern);
}
/**
* Extract class name from file path or content
*
* @param filePath - The file path to extract class name from
* @returns The class name extracted from the file path (without extension)
* @example
* ```typescript
* const className = CodeAnalysisUtils.extractClassName('/path/to/MyClass.cls');
* console.log(className); // 'MyClass'
* ```
*/
static extractClassName(filePath) {
const fileName = FileUtils.getFileName(filePath);
return FileUtils.removeExtension(fileName);
}
/**
* Check if file is a test file based on filename or content
*
* @param filePath - The file path to check
* @param content - Optional file content to check for test annotations
* @returns True if the file is identified as a test file
* @example
* ```typescript
* const isTest = CodeAnalysisUtils.isTestFile('MyTest.cls', '@isTest class MyTest {}');
* console.log(isTest); // true
* ```
*/
static isTestFile(filePath, content) {
return FileUtils.isTestFile(filePath, content);
}
/**
* Create entry key for deduplication
*
* @param fileName - The name of the file
* @param ruleId - The rule identifier
* @param lineNumber - Optional line number where the issue occurs
* @returns A unique key string for deduplication purposes
* @example
* ```typescript
* const key1 = CodeAnalysisUtils.createEntryKey('MyClass.cls', 'no-var');
* // Returns: 'MyClass.cls-no-var'
*
* const key2 = CodeAnalysisUtils.createEntryKey('MyClass.cls', 'no-var', 42);
* // Returns: 'MyClass.cls-no-var-42'
* ```
*/
static createEntryKey(fileName, ruleId, lineNumber) {
return `${fileName}-${ruleId}${lineNumber !== undefined ? `-${lineNumber}` : ''}`;
}
}