agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
210 lines (204 loc) • 8.32 kB
JavaScript
/**
* @file Robust file operation utilities with comprehensive error handling
* @description Single responsibility: Provide safe file system operations across AgentSqripts
*
* This utility module provides robust file system operations with graceful error handling,
* consistent return patterns, and performance optimizations. It abstracts Node.js file
* system complexity while maintaining reliability for large-scale code analysis operations.
*
* Design rationale:
* - Promise-based API for modern async/await patterns
* - Graceful error handling prevents analysis pipeline failures
* - Consistent return patterns (null for failures, empty arrays, boolean status)
* - UTF-8 encoding standardization for text file operations
*/
const fs = require('fs');
const { promises: fsPromises } = require('fs');
/**
* Read file content with graceful error handling and consistent return pattern
*
* Technical function: Provides safe file reading with null return for failures
*
* Implementation rationale:
* - Async/await pattern enables clean error handling without callback complexity
* - UTF-8 encoding explicitly specified for consistent text handling
* - Null return value enables easy failure detection without exception handling
* - Warning-level logging preserves error information without stopping execution
*
* Error handling strategy:
* - Catches all file system errors (ENOENT, EACCES, EISDIR, etc.)
* - Returns null for consistent failure indication across all error types
* - Warning message provides debugging information without breaking analysis flow
* - Graceful degradation enables analysis to continue with partial data
*
* Performance considerations:
* - Single fsPromises.readFile call minimizes system call overhead
* - UTF-8 encoding specified to avoid default encoding detection overhead
* - No additional file stat calls required for basic read operations
* - Promise-based operation enables efficient concurrent file reading
*
* Alternative approaches considered:
* - Throwing exceptions: Rejected to maintain analysis pipeline stability
* - Synchronous fs.readFileSync: Rejected for blocking behavior
* - Streaming for all files: Rejected as overkill for typical analysis file sizes
*
* @param {string} filePath - Absolute or relative path to file to read
* @returns {Promise<string|null>} File content as UTF-8 string, or null if read fails
* @example
* const content = await readFileSafely('config.js');
* if (content !== null) {
* // Process file content
* } else {
* // Handle missing or inaccessible file
* }
*/
async function readFileSafely(filePath) {
try {
return await fsPromises.readFile(filePath, 'utf-8');
} catch (error) {
console.warn(`Warning: Could not read ${filePath}: ${error.message}`);
return null;
}
}
/**
* Write file content with comprehensive error handling and success indication
*
* Technical function: Provides safe file writing with boolean success indication
*
* Implementation rationale:
* - Boolean return value enables simple success/failure checking
* - UTF-8 encoding ensures consistent text file output
* - Error-level logging for failures (more serious than read failures)
* - Atomic write operation using Node.js fsPromises for reliability
*
* Error handling strategy:
* - Catches all write errors (ENOSPC, EACCES, ENOTDIR, etc.)
* - Boolean return enables immediate success/failure detection
* - Error-level logging appropriate for write failures (data loss risk)
* - No partial write state - operation either succeeds completely or fails
*
* File writing considerations:
* - UTF-8 encoding for consistent text output across platforms
* - Atomic write operation prevents partial file corruption
* - No intermediate temporary files for simplicity
* - Directory creation not included - caller responsible for directory existence
*
* Write operation patterns:
* - Analysis report generation to JSON/text files
* - Configuration file updates after analysis
* - Cache file writing for performance optimization
* - Debug output and logging to files
*
* @param {string} filePath - Target file path for writing content
* @param {string} content - String content to write to file
* @returns {Promise<boolean>} True if write succeeded, false if write failed
* @example
* const success = await writeFileSafely('output.json', JSON.stringify(data));
* if (success) {
* console.log('Report saved successfully');
* } else {
* console.log('Failed to save report');
* }
*/
async function writeFileSafely(filePath, content) {
try {
await fsPromises.writeFile(filePath, content, 'utf-8');
return true;
} catch (error) {
console.error(`Error writing to ${filePath}: ${error.message}`);
return false;
}
}
/**
* Check file system accessibility with simple boolean result
*
* Technical function: Tests file/directory accessibility without additional metadata
*
* Implementation rationale:
* - Uses fs.access() for lightweight accessibility testing
* - Boolean return simplifies conditional logic in callers
* - No error logging (accessibility checks are often exploratory)
* - Catches all exceptions to provide clean boolean interface
*
* Accessibility check use cases:
* - Validating input paths before attempting file operations
* - Checking configuration file existence before reading
* - Verifying output directory accessibility before writing
* - Conditional file processing based on availability
*
* Access check behavior:
* - Tests both read and write accessibility by default
* - Works for both files and directories
* - Respects file system permissions and existence
* - No detailed error information (use for simple existence/permission checks)
*
* Performance optimization:
* - Minimal system call overhead with fs.access
* - No file content reading or metadata fetching
* - Suitable for high-frequency accessibility checks
* - Promise-based for efficient batch checking
*
* @param {string} filePath - File or directory path to check for accessibility
* @returns {Promise<boolean>} True if path is accessible, false otherwise
* @example
* if (await isAccessible('optional-config.js')) {
* const config = await readFileSafely('optional-config.js');
* }
*/
async function isAccessible(filePath) {
try {
await fsPromises.access(filePath);
return true;
} catch {
return false;
}
}
/**
* Get directory entries with comprehensive error handling and metadata
*
* Technical function: Reads directory contents with file type information
*
* Implementation rationale:
* - withFileTypes option provides Dirent objects with type information
* - Empty array return enables consistent iteration regardless of errors
* - Warning-level logging for directory access issues
* - Promise-based operation for efficient directory traversal
*
* Directory reading strategy:
* - Returns Dirent objects with isFile(), isDirectory() methods
* - Empty array return enables safe forEach/map operations
* - No recursive traversal (single directory level only)
* - File type metadata included for filtering operations
*
* Error scenarios handled:
* - ENOENT: Directory does not exist
* - EACCES: Permission denied for directory access
* - ENOTDIR: Path exists but is not a directory
* - EMFILE: Too many open files (system resource exhaustion)
*
* Directory traversal patterns:
* - Project file discovery for analysis
* - Configuration directory scanning
* - Output directory validation and preparation
* - Recursive directory tree building (as building block)
*
* @param {string} dirPath - Directory path to read entries from
* @returns {Promise<Array<fs.Dirent>>} Array of directory entries with type info, empty if error
* @example
* const entries = await getDirectoryEntries('./src');
* const jsFiles = entries.filter(entry => entry.isFile() && entry.name.endsWith('.js'));
*/
async function getDirectoryEntries(dirPath) {
try {
return await fsPromises.readdir(dirPath, { withFileTypes: true });
} catch (error) {
console.warn(`Warning: Cannot access ${dirPath}: ${error.message}`);
return [];
}
}
module.exports = {
readFileSafely,
writeFileSafely,
isAccessible,
getDirectoryEntries
};