import { NextRequest, NextResponse } from "next/server"; import { exec } from "child_process"; import { promisify } from "util"; import path from "path"; import fs from "fs"; const execAsync = promisify(exec); export async function POST(request: NextRequest) { try { const { command, layoutData } = await request.json(); if (!command || !layoutData) { return NextResponse.json({ success: false, message: "명령어와 레이아웃 데이터가 필요합니다." }, { status: 400 }); } // 프론트엔드 디렉토리 경로 const frontendDir = path.join(process.cwd()); // CLI 명령어 실행 const fullCommand = `cd ${frontendDir} && node scripts/create-layout.js ${command}`; console.log("실행할 명령어:", fullCommand); const { stdout, stderr } = await execAsync(fullCommand); if (stderr && !stderr.includes("warning")) { console.error("CLI 실행 오류:", stderr); return NextResponse.json( { success: false, message: "레이아웃 생성 중 오류가 발생했습니다.", error: stderr, }, { status: 500 }, ); } // 생성된 파일들 확인 const layoutId = layoutData.name.toLowerCase().replace(/[^a-z0-9-]/g, "-"); const layoutDir = path.join(frontendDir, "lib/registry/layouts", layoutId); const generatedFiles: string[] = []; if (fs.existsSync(layoutDir)) { const files = fs.readdirSync(layoutDir); files.forEach((file) => { generatedFiles.push(`layouts/${layoutId}/${file}`); }); } // 자동 등록을 위해 index.ts 업데이트 await updateLayoutIndex(layoutId); return NextResponse.json({ success: true, message: "레이아웃이 성공적으로 생성되었습니다.", files: generatedFiles, output: stdout, }); } catch (error) { console.error("레이아웃 생성 API 오류:", error); return NextResponse.json( { success: false, message: "서버 오류가 발생했습니다.", error: error instanceof Error ? error.message : "Unknown error", }, { status: 500 }, ); } } /** * layouts/index.ts에 새 레이아웃 import 추가 */ async function updateLayoutIndex(layoutId: string) { try { const indexPath = path.join(process.cwd(), "lib/registry/layouts/index.ts"); if (!fs.existsSync(indexPath)) { console.warn("layouts/index.ts 파일을 찾을 수 없습니다."); return; } let content = fs.readFileSync(indexPath, "utf8"); // 새 import 문 추가 const newImport = `import "./${layoutId}/${layoutId.charAt(0).toUpperCase() + layoutId.slice(1)}LayoutRenderer";`; // 이미 import되어 있는지 확인 if (content.includes(newImport)) { console.log("이미 import되어 있습니다."); return; } // 다른 import 문들 찾기 const importRegex = /import "\.\/.+\/\w+LayoutRenderer";/g; const imports = content.match(importRegex) || []; if (imports.length > 0) { // 마지막 import 뒤에 추가 const lastImport = imports[imports.length - 1]; const lastImportIndex = content.lastIndexOf(lastImport); const insertPosition = lastImportIndex + lastImport.length; content = content.slice(0, insertPosition) + "\n" + newImport + content.slice(insertPosition); } else { // import가 없다면 파일 시작 부분에 추가 const newStructureComment = "// 새 구조 레이아웃들 (자동 등록)"; const commentIndex = content.indexOf(newStructureComment); if (commentIndex !== -1) { const insertPosition = content.indexOf("\n", commentIndex) + 1; content = content.slice(0, insertPosition) + newImport + "\n" + content.slice(insertPosition); } } fs.writeFileSync(indexPath, content); console.log(`layouts/index.ts에 ${layoutId} import 추가 완료`); } catch (error) { console.error("index.ts 업데이트 오류:", error); } }