Spaces:
Sleeping
Sleeping
| import * as fs from "fs"; | |
| import * as path from "path"; | |
| import { GeneratedFile } from "./file-parser"; | |
| const TEMPLATE_DIR = path.join(process.cwd(), "templates", "nextjs-base"); | |
| function copyTemplate(destDir: string) { | |
| fs.mkdirSync(destDir, { recursive: true }); | |
| fs.cpSync(TEMPLATE_DIR, destDir, { recursive: true }); | |
| } | |
| // Framer Motion (and React hooks) only work in Client Components. | |
| // If the model forgot the "use client" directive, add it automatically | |
| // rather than relying on prompt compliance alone. | |
| function needsClientDirective(content: string): boolean { | |
| return ( | |
| /from\s+["']framer-motion["']/.test(content) || | |
| /\buse(State|Effect|Ref|Context|Reducer|Callback|Memo)\b/.test(content) | |
| ); | |
| } | |
| function ensureClientDirective(content: string): string { | |
| const trimmed = content.trimStart(); | |
| if (trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'")) { | |
| return content; | |
| } | |
| return needsClientDirective(content) ? '"use client";\n\n' + content : content; | |
| } | |
| export function writeProjectFiles( | |
| files: GeneratedFile[], | |
| projectSlug: string | |
| ): { projectDir: string; written: string[] } { | |
| const safeSlug = projectSlug.replace(/[^a-z0-9-]/gi, "-").toLowerCase().slice(0, 40); | |
| const projectDir = path.join( | |
| process.cwd(), | |
| "generated_projects", | |
| `${safeSlug}-${Date.now()}` | |
| ); | |
| copyTemplate(projectDir); | |
| const written: string[] = []; | |
| for (const file of files) { | |
| const fullPath = path.join(projectDir, file.path); | |
| fs.mkdirSync(path.dirname(fullPath), { recursive: true }); | |
| const content = file.path.endsWith(".tsx") ? ensureClientDirective(file.content) : file.content; | |
| fs.writeFileSync(fullPath, content, "utf-8"); | |
| written.push(file.path); | |
| } | |
| return { projectDir, written }; | |
| } | |