rojects/source/server/storage.ts

106 lines
3.8 KiB
TypeScript
Raw Normal View History

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 = `<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>New Page</title></head>
<body><page-content><h1>Hello World!</h1></page-content></body>
</html>`;
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;
}