UNPKG

bowling-analysis-system

Version:

A comprehensive system for analyzing bowling techniques using video processing and metrics calculation

154 lines (136 loc) 4.22 kB
/** * @fileoverview File service for handling file operations * @module utils/FileService */ const fs = require('fs'); const path = require('path'); const { promisify } = require('util'); // Promisify fs functions const readFileAsync = promisify(fs.readFile); const writeFileAsync = promisify(fs.writeFile); const mkdirAsync = promisify(fs.mkdir); const statAsync = promisify(fs.stat); /** * File service for handling file operations */ class FileService { /** * Read a file * @param {string} filePath - Path to the file * @param {Object} options - Read options * @param {string} [options.encoding='utf8'] - File encoding * @returns {Promise<string|Buffer>} File contents */ async readFile(filePath, options = {}) { const encoding = options.encoding || 'utf8'; return readFileAsync(filePath, { encoding }); } /** * Write to a file * @param {string} filePath - Path to the file * @param {string|Buffer} data - Data to write * @param {Object} options - Write options * @param {string} [options.encoding='utf8'] - File encoding * @param {boolean} [options.createDir=true] - Create directory if it doesn't exist * @returns {Promise<void>} */ async writeFile(filePath, data, options = {}) { const encoding = options.encoding || 'utf8'; const createDir = options.createDir !== false; if (createDir) { const dirPath = path.dirname(filePath); await this.ensureDirectoryExists(dirPath); } return writeFileAsync(filePath, data, { encoding }); } /** * Ensure a directory exists * @param {string} dirPath - Path to the directory * @returns {Promise<void>} */ async ensureDirectoryExists(dirPath) { try { await mkdirAsync(dirPath, { recursive: true }); } catch (error) { if (error.code !== 'EEXIST') { throw error; } } } /** * Check if a file exists * @param {string} filePath - Path to the file * @returns {Promise<boolean>} Whether the file exists */ async fileExists(filePath) { try { const stats = await statAsync(filePath); return stats.isFile(); } catch (error) { if (error.code === 'ENOENT') { return false; } throw error; } } /** * List files matching a pattern * @param {string} pattern - Glob pattern * @param {Object} options - Options * @param {boolean} [options.fullPaths=false] - Return full paths * @returns {Promise<string[]>} Array of file paths */ async listFiles(pattern, options = {}) { // Simple implementation without glob const dir = path.dirname(pattern); const files = fs.readdirSync(dir); // Filter files based on pattern const filePattern = path.basename(pattern).replace(/\*/g, '.*'); const regex = new RegExp(`^${filePattern}$`); const matchedFiles = files.filter(file => regex.test(file)); if (options.fullPaths) { return matchedFiles.map(file => path.resolve(dir, file)); } return matchedFiles; } /** * Resolve a path * @param {string} basePath - Base path * @param {string} relativePath - Relative path * @returns {string} Resolved path */ resolvePath(basePath, relativePath) { return path.resolve(basePath, relativePath); } /** * Get the basename of a path * @param {string} filePath - File path * @param {string} [ext] - Extension to remove * @returns {string} Basename */ getBasename(filePath, ext) { return path.basename(filePath, ext); } /** * Get the directory name of a path * @param {string} filePath - File path * @returns {string} Directory name */ getDirname(filePath) { return path.dirname(filePath); } /** * Get the extension of a path * @param {string} filePath - File path * @returns {string} Extension */ getExtension(filePath) { return path.extname(filePath); } } // Create default instance const defaultFileService = new FileService(); module.exports = { FileService, defaultFileService };