import fs from 'fs'; import path from 'path'; const STORAGE_DIR = path.join(__dirname, '..', '..', 'build', 'data', 'storage'); if (!fs.existsSync(STORAGE_DIR)) fs.mkdirSync(STORAGE_DIR, { recursive: true }); const INITIAL_HTML = ` New Page

Hello World!

`; export interface FileNode { name: string; path: string; type: 'file' | 'directory'; children?: FileNode[]; } export function createProjectStorage(projectId: string): void { const rootDir = path.join(STORAGE_DIR, projectId, 'root'); fs.mkdirSync(rootDir, { recursive: true }); fs.writeFileSync(path.join(rootDir, 'index.html'), INITIAL_HTML); } function buildTree(absDir: string, rootDir: string): FileNode[] { return fs.readdirSync(absDir).map(name => { const abs = path.join(absDir, name); const rel = path.relative(rootDir, abs).replace(/\\/g, '/'); if (fs.statSync(abs).isDirectory()) { return { name, path: rel, type: 'directory' as const, children: buildTree(abs, rootDir) }; } return { name, path: rel, type: 'file' as const }; }); } export function getFileTree(projectId: string): FileNode[] { const rootDir = path.join(STORAGE_DIR, projectId, 'root'); if (!fs.existsSync(rootDir)) return []; return buildTree(rootDir, rootDir); } function safeResolve(projectId: string, filePath: string): string | null { const rootDir = path.resolve(path.join(STORAGE_DIR, projectId, 'root')); const full = path.resolve(path.join(rootDir, filePath)); if (!full.startsWith(rootDir + path.sep) && full !== rootDir) return null; return full; } export function readProjectFile(projectId: string, filePath: string): string | null { const full = safeResolve(projectId, filePath); if (!full || !fs.existsSync(full)) return null; return fs.readFileSync(full, 'utf8'); } export function writeProjectFile(projectId: string, filePath: string, content: string): boolean { const full = safeResolve(projectId, filePath); if (!full) return false; fs.mkdirSync(path.dirname(full), { recursive: true }); fs.writeFileSync(full, content, 'utf8'); return true; } export function createProjectFile(projectId: string, filePath: string): boolean { const full = safeResolve(projectId, filePath); if (!full || fs.existsSync(full)) return false; fs.mkdirSync(path.dirname(full), { recursive: true }); fs.writeFileSync(full, '', 'utf8'); return true; } export function createProjectDirectory(projectId: string, dirPath: string): boolean { const full = safeResolve(projectId, dirPath); if (!full || fs.existsSync(full)) return false; fs.mkdirSync(full, { recursive: true }); return true; } export function projectPathExists(projectId: string, filePath: string): boolean { const full = safeResolve(projectId, filePath); return !!full && fs.existsSync(full); } export function renameProjectEntry( projectId: string, oldPath: string, newName: string ): boolean { if ( !oldPath || !newName ) return false; if ( newName.includes( '/' ) || newName.includes( '\\' ) ) return false; const full = safeResolve( projectId, oldPath ); if ( !full || !fs.existsSync( full ) ) return false; const rootDir = path.resolve( path.join( STORAGE_DIR, projectId, 'root' ) ); const newFull = path.join( path.dirname( full ), newName ); if ( !newFull.startsWith( rootDir + path.sep ) ) return false; if ( fs.existsSync( newFull ) ) return false; fs.renameSync( full, newFull ); return true; } export function deleteProjectEntry( projectId: string, targetPath: string ): boolean { if ( !targetPath ) return false; const full = safeResolve( projectId, targetPath ); if ( !full || !fs.existsSync( full ) ) return false; fs.rmSync( full, { recursive: true, force: true } ); return true; }