ds-sfcoe-ailabs
Version:
AI-powered code review tool with static analysis integration for comprehensive code quality assessment.
130 lines (129 loc) • 4.39 kB
JavaScript
import * as path from 'node:path';
import { TEST_PATTERNS, LAST_EXTENSION_REGEX } from './constants.js';
/**
* File utility functions for common operations
*/
export class FileUtils {
/**
* Extract filename from a file path
*
* @param filePath - The file path to extract the filename from
* @returns The filename (including extension) or the original path if no path separators
* @example
* ```typescript
* const fileName = FileUtils.getFileName('/path/to/file.js');
* console.log(fileName); // 'file.js'
* ```
*/
static getFileName(filePath) {
return filePath.split('/').pop() ?? filePath;
}
/**
* Get file extension from a file path
*
* @param filePath - The file path to extract the extension from
* @returns The file extension in lowercase (including the dot)
* @example
* ```typescript
* const extension = FileUtils.getFileExtension('file.js');
* console.log(extension); // '.js'
* ```
*/
static getFileExtension(filePath) {
return path.extname(filePath).toLowerCase();
}
/**
* Check if a file is a JavaScript/TypeScript file
*
* @param filePath - The file path to check
* @returns True if the file is a JavaScript/TypeScript file
* @example
* ```typescript
* const isJs = FileUtils.isJavaScriptFile('app.js');
* console.log(isJs); // true
* ```
*/
static isJavaScriptFile(filePath) {
const extension = this.getFileExtension(filePath);
return /\.(js|ts|mjs|cjs)$/i.test(extension);
}
/**
* Check if a file is an Apex file
*
* @param filePath - The file path to check
* @returns True if the file is an Apex class or trigger file
* @example
* ```typescript
* const isApex = FileUtils.isApexFile('MyClass.cls');
* console.log(isApex); // true
* ```
*/
static isApexFile(filePath) {
const extension = this.getFileExtension(filePath);
return extension === '.cls' || extension === '.trigger';
}
/**
* Check if a file is a test file based on filename or content
*
* @param filePath - The file path to check
* @param content - Optional file content to analyze for test annotations
* @returns True if the file is identified as a test file
* @example
* ```typescript
* const isTest = FileUtils.isTestFile('MyTest.cls', 'public class MyTest { @isTest void test() {} }');
* console.log(isTest); // true
* ```
*/
static isTestFile(filePath, content) {
const fileName = this.getFileName(filePath);
const isTestFileName = fileName
.toLowerCase()
.includes(TEST_PATTERNS.TEST_FILE_PATTERN);
const hasTestAnnotation = content?.includes(TEST_PATTERNS.APEX_TEST_ANNOTATION) ?? false;
return isTestFileName || hasTestAnnotation;
}
/**
* Normalize file path for consistent comparison
*
* @param filePath - The file path to normalize
* @returns The normalized file path with forward slashes
* @example
* ```typescript
* const normalized = FileUtils.normalizePath('src\\file.js');
* console.log(normalized); // 'src/file.js'
* ```
*/
static normalizePath(filePath) {
return path.normalize(filePath);
}
/**
* Create a unique entry key for deduplication
*
* @param fileName - The name of the file
* @param ruleId - The rule identifier
* @param lineNumber - The line number where the issue occurs
* @returns A unique string key for the entry
* @example
* ```typescript
* const key = FileUtils.createEntryKey('file.js', 'no-unused-vars', 42);
* console.log(key); // 'file.js-no-unused-vars-42'
* ```
*/
static createEntryKey(fileName, ruleId, lineNumber) {
return `${fileName}-${ruleId}-${lineNumber}`;
}
/**
* Remove file extension from filename
*
* @param fileName - The filename to process
* @returns The filename without its extension
* @example
* ```typescript
* const nameWithoutExt = FileUtils.removeExtension('file.js');
* console.log(nameWithoutExt); // 'file'
* ```
*/
static removeExtension(fileName) {
return fileName.replace(LAST_EXTENSION_REGEX, '');
}
}