UNPKG

ds-sfcoe-ailabs

Version:

AI-powered code review tool with static analysis integration for comprehensive code quality assessment.

108 lines (107 loc) 4.04 kB
import path from 'node:path'; import fs from 'fs'; import { Logger } from '../../utils/observability.js'; import { COMMAND_DEFAULTS } from '../../utils/constants.js'; import SCATProvider from './scatProvider.js'; /** * Salesforce Code Analyzer implementation extending SCATProvider * Provides Salesforce-specific static code analysis using the Salesforce CLI scanner */ export default class SFCodeAnalyzer extends SCATProvider { /** * Creates a new Salesforce Code Analyzer instance * * @param scanDirectory - The directory to scan for Salesforce code * @param configFile - Optional configuration file path for the analyzer * @throws Error if scanDirectory is invalid * @example * ```typescript * const analyzer = new SFCodeAnalyzer('/path/to/salesforce/code', 'sf-config.yml'); * ``` */ constructor(scanDirectory, configFile) { const sarifFileName = path.join(scanDirectory, COMMAND_DEFAULTS.DEFAULT_SARIF_FILE_NAME); super(scanDirectory, configFile ?? '', sarifFileName); } /** * Runs the Salesforce Code Analyzer on the specified directory * * @param scanDirectory - Optional override for the scan directory * @returns Promise that resolves to the SARIF analysis results * @throws Error if Salesforce Code Analyzer execution fails or SARIF file cannot be read * @example * ```typescript * const results = await analyzer.run('/custom/scan/path'); * console.log(results.runs); * ``` */ async run(scanDirectory) { const directoryToScan = scanDirectory ?? this.getScanDirectory(); const { execa: execaModule } = await import('execa'); // Create log directory if it doesn't exist await this.ensureLogDirectoryExists(); // Build v5.x command arguments const args = [ 'code-analyzer', 'run', '--workspace', directoryToScan, '--target', directoryToScan, '--output-file', this.getSarifFileName(), '--rule-selector', 'all', ]; // Add config file if provided if (this.getConfigFile()) { args.push('--config-file', this.getConfigFile()); } Logger.debug(`Running SF code analyzer command for Salesforce files: \n sf ${args.join(' ')}`); try { await execaModule('sf', args, { cwd: directoryToScan, stdio: 'inherit', }); } catch (error) { Logger.error('Code Analyzer execution failed:', error); throw error; } return this.getSarifFile(); } /** * Ensures the log directory exists. * Creates the directory if it doesn't exist. * * @returns Promise that resolves when directory is ensured to exist * @throws Warning logged if directory creation fails * @example * ```typescript * await this.ensureLogDirectoryExists(); * ``` */ async ensureLogDirectoryExists() { try { const configFile = this.getConfigFile(); let logDir; if (configFile) { // Get the directory containing the config file const configDir = path.dirname(configFile); // The log folder is 'code-analyzer-logs' relative to the config file directory logDir = path.join(configDir, COMMAND_DEFAULTS.SF_CODE_ANALYZER_LOGS_FOLDER); } else { // Default to creating the log directory in the scan directory logDir = path.join(this.getScanDirectory(), COMMAND_DEFAULTS.SF_CODE_ANALYZER_LOGS_FOLDER); } // Create the directory if it doesn't exist if (!fs.existsSync(logDir)) { fs.mkdirSync(logDir); } } catch (error) { Logger.warn('Warning: Could not create log directory:', error); } } }