UNPKG

sfcoe-ailabs

Version:

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

95 lines (94 loc) 3.76 kB
import path from 'node:path'; import * as fs from 'node:fs'; import { execFileSync } from 'node:child_process'; import { Logger } from '../../observability/index.js'; import { COMMAND_DEFAULTS } from '../../utils/constants.js'; import SCATProvider from './scatProvider.js'; export default class PMDCodeAnalyzer extends SCATProvider { fileList; /** * Creates a new PMD Code Analyzer instance * * @param scanDirectory - The directory to scan for non-Salesforce code * @param configFile - Configuration file path for PMD * @param fileList - Array of specific files to analyze */ constructor(scanDirectory, configFile, fileList) { const sarifFileName = path.join(scanDirectory, COMMAND_DEFAULTS.DEFAULT_SARIF_FILE_NAME); super(scanDirectory, configFile, sarifFileName); this.fileList = fileList; } /** * Runs the PMD analyzer on the specified files * * @param scanDirectory - Optional override for the scan directory * @returns Promise that resolves to the SARIF analysis results */ async run(scanDirectory) { const directoryToScan = scanDirectory ?? this.getScanDirectory(); if (this.fileList.length === 0) { Logger.debug('No files to analyze with PMD'); // Return empty SARIF structure return { version: '2.1.0', runs: [], }; } // Create a temporary file with the list of files to analyze const fileListPath = path.join(directoryToScan, 'pmd-files-only.txt'); try { // Write file list to temporary file fs.writeFileSync(fileListPath, this.fileList.join('\n')); // Use PMD rulesets from config file const rulesets = this.getConfigFile(); // Validate inputs if (!fs.existsSync(fileListPath)) { throw new Error(`File list path does not exist: ${fileListPath}`); } if (!fs.existsSync(rulesets)) { throw new Error(`Rulesets file does not exist: ${rulesets}`); } Logger.debug('Running PMD command for non-Salesforce files: \n ' + `pmd check --file-list "${fileListPath}" --format sarif --rulesets "${rulesets}"`); let result; try { result = execFileSync('pmd', [ 'check', '--file-list', fileListPath, '--format', 'sarif', '--rulesets', rulesets, ], { cwd: directoryToScan, encoding: 'utf8', maxBuffer: 1024 * 1024 * 10, // 10MB buffer }); } catch (error) { // PMD returns exit code 4 when violations are found, which is expected const execError = error; if (execError.status === 4 && execError.stdout) { result = execError.stdout; } else { Logger.error('PMD command failed:', error); throw error; } } // Write the SARIF result to the expected output file fs.writeFileSync(this.getSarifFileName(), result, 'utf-8'); } catch (error) { Logger.error('PMD analysis execution failed:', error); } finally { // Ensure the temporary file is removed even if an error occurs if (fs.existsSync(fileListPath)) { fs.unlinkSync(fileListPath); } } return this.getSarifFile(); } }