@boundless-oss/atlas
Version:
Atlas - MCP Server for comprehensive startup project management
107 lines (89 loc) • 3.27 kB
text/typescript
import { promises as fs } from 'fs';
export interface FileSystemAdapter {
writeFile(path: string, content: string, encoding: string): Promise<void>;
readFile(path: string, encoding: string): Promise<string>;
mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;
access(path: string): Promise<void>;
readdir(path: string): Promise<string[]>;
}
export class NodeFileSystemAdapter implements FileSystemAdapter {
private fs = fs;
async writeFile(path: string, content: string, encoding: string): Promise<void> {
await this.fs.writeFile(path, content, { encoding: encoding as BufferEncoding });
}
async readFile(path: string, encoding: string): Promise<string> {
return await this.fs.readFile(path, { encoding: encoding as BufferEncoding });
}
async mkdir(path: string, options?: { recursive?: boolean }): Promise<void> {
await this.fs.mkdir(path, options);
}
async access(path: string): Promise<void> {
await this.fs.access(path);
}
async readdir(path: string): Promise<string[]> {
return await this.fs.readdir(path);
}
}
export class InMemoryFileSystemAdapter implements FileSystemAdapter {
private files: Map<string, string> = new Map();
private directories: Set<string> = new Set();
async writeFile(path: string, content: string, encoding: string): Promise<void> {
const dir = path.substring(0, path.lastIndexOf('/'));
if (dir && !this.directories.has(dir)) {
throw new Error(`ENOENT: no such file or directory, open '${path}'`);
}
this.files.set(path, content);
}
async readFile(path: string, encoding: string): Promise<string> {
const content = this.files.get(path);
if (content === undefined) {
throw new Error(`ENOENT: no such file or directory, open '${path}'`);
}
return content;
}
async mkdir(path: string, options?: { recursive?: boolean }): Promise<void> {
if (options?.recursive) {
const parts = path.split('/').filter(p => p);
let currentPath = '';
for (const part of parts) {
currentPath = currentPath ? `${currentPath}/${part}` : `/${part}`;
this.directories.add(currentPath);
}
} else {
this.directories.add(path);
}
}
async access(path: string): Promise<void> {
if (!this.files.has(path) && !this.directories.has(path)) {
throw new Error(`ENOENT: no such file or directory, access '${path}'`);
}
}
async readdir(path: string): Promise<string[]> {
if (!this.directories.has(path)) {
throw new Error(`ENOENT: no such file or directory, scandir '${path}'`);
}
const files: string[] = [];
for (const [filePath] of this.files) {
const dir = filePath.substring(0, filePath.lastIndexOf('/'));
if (dir === path) {
const fileName = filePath.substring(filePath.lastIndexOf('/') + 1);
files.push(fileName);
}
}
return files;
}
// Test helper methods
clear(): void {
this.files.clear();
this.directories.clear();
}
hasFile(path: string): boolean {
return this.files.has(path);
}
hasDirectory(path: string): boolean {
return this.directories.has(path);
}
getFileContent(path: string): string | undefined {
return this.files.get(path);
}
}