const fs = require('fs') const path = require('path') function getProjectDir(projectPath) { return projectPath } function getSrcDir(projectPath) { const dir = path.join(projectPath, '.web2app', 'src') fs.mkdirSync(dir, { recursive: true }) return dir } function getConfigPath(projectPath) { return path.join(projectPath, '.web2app', 'project.json') } function getDistDir(projectPath) { const dir = path.join(projectPath, '.web2app', 'dist') fs.mkdirSync(dir, { recursive: true }) return dir } function createProject(projectPath) { if (!fs.existsSync(projectPath)) { fs.mkdirSync(projectPath, { recursive: true }) } const configPath = getConfigPath(projectPath) if (fs.existsSync(configPath)) { throw new Error(`该目录已是 Web2App 项目`) } fs.mkdirSync(path.join(projectPath, '.web2app', 'src'), { recursive: true }) fs.mkdirSync(path.join(projectPath, '.web2app', 'dist'), { recursive: true }) const config = { name: path.basename(projectPath), version: '1.0.0', description: '', author: '', entry: 'index.html', backendEntry: '', windowWidth: 1200, windowHeight: 800, minWidth: 800, minHeight: 600, resizable: true, icon: '', copyright: '', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() } fs.writeFileSync(configPath, JSON.stringify(config, null, 2)) return { projectPath, config } } function loadProject(projectPath) { const configPath = getConfigPath(projectPath) if (!fs.existsSync(configPath)) { throw new Error('不是有效的 Web2App 项目') } const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')) const srcDir = getSrcDir(projectPath) const files = readFileTree(srcDir) return { projectPath, config, files } } function saveProject(projectPath, data) { const configPath = getConfigPath(projectPath) const existing = JSON.parse(fs.readFileSync(configPath, 'utf-8')) const updated = { ...existing, ...data, updatedAt: new Date().toISOString() } fs.writeFileSync(configPath, JSON.stringify(updated, null, 2)) return updated } function importFiles(projectPath, files) { const srcDir = getSrcDir(projectPath) const imported = [] for (const filePath of files) { const stat = fs.statSync(filePath) if (stat.isDirectory()) { const destDir = path.join(srcDir, path.basename(filePath)) copyDirSync(filePath, destDir) imported.push({ source: filePath, dest: destDir }) } else { const destPath = path.join(srcDir, path.basename(filePath)) fs.copyFileSync(filePath, destPath) imported.push({ source: filePath, dest: destPath }) } } return readFileTree(srcDir) } function removeFile(projectPath, relativePath) { const srcDir = getSrcDir(projectPath) const fullPath = path.join(srcDir, relativePath) if (!fs.existsSync(fullPath)) { throw new Error(`文件不存在: ${relativePath}`) } const stat = fs.statSync(fullPath) if (stat.isDirectory()) { fs.rmSync(fullPath, { recursive: true, force: true }) } else { fs.unlinkSync(fullPath) } return readFileTree(srcDir) } function setProjectIcon(projectPath, iconPath) { const srcDir = getSrcDir(projectPath) const ext = path.extname(iconPath) const destName = `app-icon${ext}` const destPath = path.join(srcDir, destName) fs.copyFileSync(iconPath, destPath) const config = JSON.parse(fs.readFileSync(getConfigPath(projectPath), 'utf-8')) config.icon = destName fs.writeFileSync(getConfigPath(projectPath), JSON.stringify(config, null, 2)) return config } function readFileTree(dirPath, basePath = '') { const items = [] if (!fs.existsSync(dirPath)) return items const entries = fs.readdirSync(dirPath, { withFileTypes: true }) for (const entry of entries) { if (entry.name.startsWith('.')) continue const relativePath = basePath ? path.join(basePath, entry.name) : entry.name const fullPath = path.join(dirPath, entry.name) if (entry.isDirectory()) { items.push({ name: entry.name, path: relativePath, type: 'directory', children: readFileTree(fullPath, relativePath) }) } else { items.push({ name: entry.name, path: relativePath, type: 'file', size: fs.statSync(fullPath).size, ext: path.extname(entry.name).toLowerCase() }) } } items.sort((a, b) => { if (a.type !== b.type) return a.type === 'directory' ? -1 : 1 return a.name.localeCompare(b.name) }) return items } function copyDirSync(src, dest) { fs.mkdirSync(dest, { recursive: true }) const entries = fs.readdirSync(src, { withFileTypes: true }) for (const entry of entries) { if (entry.name.startsWith('.')) continue const srcPath = path.join(src, entry.name) const destPath = path.join(dest, entry.name) if (entry.isDirectory()) { copyDirSync(srcPath, destPath) } else { fs.copyFileSync(srcPath, destPath) } } } module.exports = { createProject, loadProject, saveProject, importFiles, removeFile, setProjectIcon, getSrcDir, getDistDir, getConfigPath, getProjectDir }