cmte
Version:
Design by Committee™ except it's just you and LLMs
125 lines (115 loc) • 3.49 kB
JavaScript
import fs from 'fs/promises';
import path from 'path';
import { logger } from "./logger.js";
/**
* Ensures a directory exists, creating it if necessary
* @param directoryPath Path to the directory
*/
export async function ensureDir(directoryPath) {
try {
await fs.mkdir(directoryPath, {
recursive: true
});
logger.debug(`Directory ensured: ${directoryPath}`);
} catch (error) {
logger.error(`Failed to create directory: ${directoryPath}`, {
error
});
throw error;
}
}
/**
* Reads a file and returns its contents
* @param filePath Path to the file
* @returns File contents as string
*/
export async function readFile(filePath) {
try {
const content = await fs.readFile(filePath, 'utf8');
logger.debug(`File read: ${filePath}`);
return content;
} catch (error) {
logger.error(`Failed to read file: ${filePath}`, {
error
});
throw new Error(`Unable to read file at ${filePath}: ${error.message}`);
}
}
/**
* Writes content to a file, creating directories if needed
* @param filePath Path to the file
* @param content Content to write
*/
export async function writeFile(filePath, content) {
try {
// Ensure the directory exists
await ensureDir(path.dirname(filePath));
// Write the file
await fs.writeFile(filePath, content, 'utf8');
logger.debug(`File written: ${filePath}`);
} catch (error) {
logger.error(`Failed to write file: ${filePath}`, {
error
});
throw new Error(`Unable to write file at ${filePath}: ${error.message}`);
}
}
/**
* Checks if a file exists
* @param filePath Path to the file
* @returns True if file exists, false otherwise
*/
export async function fileExists(filePath) {
try {
await fs.access(filePath, fs.constants.F_OK);
return true;
} catch {
return false;
}
}
/**
* Lists files in a directory matching a pattern
* @param directoryPath Path to the directory
* @param pattern Optional regex pattern to filter files
* @returns Array of file paths
*/
export async function listFiles(directoryPath, pattern) {
try {
const files = await fs.readdir(directoryPath);
let filePaths = files.map(file => path.join(directoryPath, file));
// Filter by pattern if provided
if (pattern) {
filePaths = filePaths.filter(filePath => pattern.test(filePath));
}
return filePaths;
} catch (error) {
logger.error(`Failed to list files in directory: ${directoryPath}`, {
error
});
throw new Error(`Unable to list files in ${directoryPath}: ${error.message}`);
}
}
/**
* Resolves path strings with placeholders using a context object
* @param pathTemplate Path template or object with path templates
* @param context Context object with values for placeholders
* @returns Resolved path string or object
*/
export function resolvePath(pathTemplate, context) {
// If pathTemplate is an object, recursively resolve its values
if (typeof pathTemplate === 'object' && pathTemplate !== null) {
const result = {};
for (const [key, value] of Object.entries(pathTemplate)) {
result[key] = resolvePath(value, context);
}
return result;
}
// If pathTemplate is a string, resolve placeholders
if (typeof pathTemplate === 'string') {
return pathTemplate.replace(/\{\{([^}]+)\}\}/g, (_, key) => {
return context[key] !== undefined ? context[key] : `{{${key}}}`;
});
}
// Return unchanged for other types
return pathTemplate;
}