import { existsSync, mkdirSync, writeFileSync } from "fs"; import { join } from "path"; import { generateEnvExample, generateGitignore, generateReadme, generateScripts, generateTsConfig, } from "./project-config"; import type { ProjectConfig, ScaffoldOptions } from "./types"; export function generateFiles(config: ProjectConfig, options: ScaffoldOptions): void { const { outputDir, name, template } = config; // Create output directory if (!existsSync(outputDir)) { mkdirSync(outputDir, { recursive: true }); } // Generate package.json const packageJson = { name, version: '0.1.0', private: true, scripts: generateScripts(template, options), dependencies: config.dependencies.reduce((acc, dep) => { acc[dep] = 'latest'; return acc; }, {} as Record), devDependencies: config.devDependencies.reduce((acc, dep) => { acc[dep] = 'latest'; return acc; }, {} as Record), }; writeFileSync( join(outputDir, 'package.json'), JSON.stringify(packageJson, null, 2) ); // Generate tsconfig.json if (options.typescript) { const tsConfig = generateTsConfig(template); writeFileSync( join(outputDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2) ); } // Generate .gitignore const gitignore = generateGitignore(template); writeFileSync(join(outputDir, '.gitignore'), gitignore); // Generate .env.example const envExample = generateEnvExample(options); writeFileSync(join(outputDir, '.env.example'), envExample); // Generate README.md const readme = generateReadme(config, options); writeFileSync(join(outputDir, 'README.md'), readme); // Generate template-specific files generateTemplateFiles(config, options); console.log(`\nāœ… Project scaffolded successfully!`); console.log(`šŸ“ Location: ${outputDir}`); console.log(`\nNext steps:`); console.log(` cd ${name}`); if (!options.install) { console.log(` ${options.pm} install`); } console.log(` ${options.pm} ${options.pm === 'npm' ? 'run ' : ''}dev`); } function generateTemplateFiles(config: ProjectConfig, options: ScaffoldOptions): void { const { outputDir, template } = config; const srcDir = join(outputDir, 'src'); // Create src directory if (!existsSync(srcDir)) { mkdirSync(srcDir, { recursive: true }); } // Generate template-specific files if (template === 'next') { generateNextJsFiles(srcDir, options); } else if (template === 'react') { generateReactFiles(srcDir, options); } else if (template === 'express' || template === 'rest-api') { generateExpressFiles(srcDir, options); } else if (template === 'cli') { generateCliFiles(srcDir, options); } // Add more template generators as needed } function generateNextJsFiles(srcDir: string, options: ScaffoldOptions): void { const appDir = join(srcDir, 'app'); mkdirSync(appDir, { recursive: true }); // layout.tsx writeFileSync( join(appDir, 'layout.tsx'), `import type { Metadata } from 'next' import './globals.css' export const metadata: Metadata = { title: 'My App', description: 'Generated by scaffold-project', } export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( {children} ) } ` ); // page.tsx writeFileSync( join(appDir, 'page.tsx'), `export default function Home() { return (

Welcome to Your App

Start building something amazing!

) } ` ); // globals.css writeFileSync( join(appDir, 'globals.css'), `@tailwind base; @tailwind components; @tailwind utilities; :root { --foreground-rgb: 0, 0, 0; --background-start-rgb: 214, 219, 220; --background-end-rgb: 255, 255, 255; } @media (prefers-color-scheme: dark) { :root { --foreground-rgb: 255, 255, 255; --background-start-rgb: 0, 0, 0; --background-end-rgb: 0, 0, 0; } } body { color: rgb(var(--foreground-rgb)); background: linear-gradient( to bottom, transparent, rgb(var(--background-end-rgb)) ) rgb(var(--background-start-rgb)); } ` ); // lib/utils.ts const libDir = join(srcDir, 'lib'); mkdirSync(libDir, { recursive: true }); writeFileSync( join(libDir, 'utils.ts'), `import { type ClassValue, clsx } from 'clsx' import { twMerge } from 'tailwind-merge' export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } ` ); } function generateReactFiles(srcDir: string, options: ScaffoldOptions): void { // main.tsx writeFileSync( join(srcDir, 'main.tsx'), `import React from 'react' import ReactDOM from 'react-dom/client' import App from './App' import './index.css' ReactDOM.createRoot(document.getElementById('root')!).render( , ) ` ); // App.tsx writeFileSync( join(srcDir, 'App.tsx'), `function App() { return (

Welcome to Your App

Start building something amazing!

) } export default App ` ); // index.css writeFileSync( join(srcDir, 'index.css'), `@tailwind base; @tailwind components; @tailwind utilities; ` ); } function generateExpressFiles(srcDir: string, options: ScaffoldOptions): void { // index.ts writeFileSync( join(srcDir, 'index.ts'), `import express from 'express' import cors from 'cors' import dotenv from 'dotenv' dotenv.config() const app = express() const port = process.env.PORT || 3000 app.use(cors()) app.use(express.json()) app.get('/', (req, res) => { res.json({ message: 'API is running' }) }) app.get('/health', (req, res) => { res.json({ status: 'ok' }) }) app.listen(port, () => { console.log(\`Server running on http://localhost:\${port}\`) }) ` ); } function generateCliFiles(srcDir: string, options: ScaffoldOptions): void { // index.ts writeFileSync( join(srcDir, 'index.ts'), `#!/usr/bin/env node import { Command } from 'commander' const program = new Command() program .name('my-cli') .description('CLI tool generated by scaffold-project') .version('1.0.0') program .command('hello') .description('Say hello') .argument('', 'Name to greet') .action((name) => { console.log(\`Hello, \${name}!\`) }) program.parse() ` ); } // ============================================================================