@codecanvascollective/scaffold 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/chunk-2A65KFCS.js +76 -0
  4. package/dist/chunk-2A65KFCS.js.map +1 -0
  5. package/dist/file-5IKT7CEX.js +24 -0
  6. package/dist/file-5IKT7CEX.js.map +1 -0
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.js +833 -0
  9. package/dist/index.js.map +1 -0
  10. package/package.json +70 -0
  11. package/src/templates/angular/base/angular.json.hbs +35 -0
  12. package/src/templates/angular/base/package.json.hbs +36 -0
  13. package/src/templates/angular/base/src/app/app.component.ts.hbs +19 -0
  14. package/src/templates/angular/base/src/app/app.config.ts.hbs +5 -0
  15. package/src/templates/angular/base/src/main.ts.hbs +7 -0
  16. package/src/templates/angular/base/tsconfig.json.hbs +26 -0
  17. package/src/templates/express/base/package.json.hbs +32 -0
  18. package/src/templates/express/base/src/index.ts.hbs +20 -0
  19. package/src/templates/express/base/src/middleware/errorHandler.ts.hbs +15 -0
  20. package/src/templates/express/base/src/routes/index.ts.hbs +11 -0
  21. package/src/templates/express/base/tsconfig.json.hbs +18 -0
  22. package/src/templates/express/with-prisma/prisma/schema.prisma.hbs +16 -0
  23. package/src/templates/express/with-prisma/prisma/seed.ts.hbs +27 -0
  24. package/src/templates/express/with-prisma/src/lib/db.ts.hbs +11 -0
  25. package/src/templates/fastapi/base/app/main.py.hbs +13 -0
  26. package/src/templates/fastapi/base/app/models/__init__.py.hbs +1 -0
  27. package/src/templates/fastapi/base/app/routes/__init__.py.hbs +1 -0
  28. package/src/templates/fastapi/base/pyproject.toml.hbs +8 -0
  29. package/src/templates/fastapi/base/requirements.txt.hbs +7 -0
  30. package/src/templates/nextjs/base/next.config.ts.hbs +5 -0
  31. package/src/templates/nextjs/base/package.json.hbs +33 -0
  32. package/src/templates/nextjs/base/src/app/globals.css.hbs +22 -0
  33. package/src/templates/nextjs/base/src/app/layout.tsx.hbs +19 -0
  34. package/src/templates/nextjs/base/src/app/page.tsx.hbs +8 -0
  35. package/src/templates/nextjs/base/tsconfig.json.hbs +25 -0
  36. package/src/templates/nextjs/with-auth/src/app/api/auth/[...nextauth]/route.ts.hbs +6 -0
  37. package/src/templates/nextjs/with-auth/src/lib/auth.ts.hbs +14 -0
  38. package/src/templates/nextjs/with-prisma/prisma/schema.prisma.hbs +16 -0
  39. package/src/templates/nextjs/with-prisma/prisma/seed.ts.hbs +27 -0
  40. package/src/templates/nextjs/with-prisma/src/lib/db.ts.hbs +11 -0
  41. package/src/templates/react/base/index.html.hbs +12 -0
  42. package/src/templates/react/base/package.json.hbs +36 -0
  43. package/src/templates/react/base/src/App.tsx.hbs +10 -0
  44. package/src/templates/react/base/src/index.css.hbs +17 -0
  45. package/src/templates/react/base/src/main.tsx.hbs +10 -0
  46. package/src/templates/react/base/tests/App.test.tsx.hbs +10 -0
  47. package/src/templates/react/base/tsconfig.json.hbs +16 -0
  48. package/src/templates/react/base/vite.config.ts.hbs +13 -0
  49. package/src/templates/react/with-shadcn/components.json.hbs +16 -0
  50. package/src/templates/react/with-shadcn/src/lib/utils.ts.hbs +6 -0
  51. package/src/templates/react/with-tailwind/postcss.config.js.hbs +6 -0
  52. package/src/templates/react/with-tailwind/src/index.css.hbs +3 -0
  53. package/src/templates/react/with-tailwind/tailwind.config.ts.hbs +9 -0
  54. package/src/templates/shared/docker/Dockerfile.hbs +42 -0
  55. package/src/templates/shared/docker/docker-compose.yml.hbs +30 -0
  56. package/src/templates/shared/eslint.config.js.hbs +17 -0
  57. package/src/templates/shared/github-ci.yml.hbs +58 -0
  58. package/src/templates/shared/gitignore.hbs +36 -0
  59. package/src/templates/shared/license.hbs +21 -0
  60. package/src/templates/shared/prettier.config.js.hbs +7 -0
  61. package/src/templates/shared/readme.md.hbs +43 -0
  62. package/src/templates/shared/tsconfig.base.json.hbs +14 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/commands/create.ts","../src/prompts/framework.ts","../src/prompts/features.ts","../src/prompts/config.ts","../src/constants.ts","../src/prompts/index.ts","../src/generators/react.ts","../src/generators/base.ts","../src/utils/logger.ts","../src/utils/validator.ts","../src/generators/nextjs.ts","../src/generators/angular.ts","../src/generators/express.ts","../src/generators/fastapi.ts","../src/generators/fullstack.ts","../src/generators/index.ts","../src/types/config.ts","../src/commands/list.ts","../src/commands/doctor.ts","../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createCommand } from './commands/create.js';\nimport { listCommand } from './commands/list.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { setVerbose } from './utils/logger.js';\n\nexport function createCli(): Command {\n const program = new Command();\n\n program\n .name('scaffold')\n .description('CLI tool for scaffolding modern full-stack projects')\n .version('0.1.0')\n .option('--verbose', 'Enable verbose output')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts();\n if (opts.verbose) {\n setVerbose(true);\n }\n });\n\n program.addCommand(createCommand());\n program.addCommand(listCommand());\n program.addCommand(doctorCommand());\n\n return program;\n}\n","import { Command } from 'commander';\nimport path from 'node:path';\nimport fs from 'fs-extra';\nimport { runPrompts } from '../prompts/index.js';\nimport { createGenerator } from '../generators/index.js';\nimport { validateProjectName, validateDirectory, success, error, newLine, banner } from '../utils/index.js';\nimport type { ProjectConfig } from '../types/index.js';\nimport { DEFAULT_CONFIG } from '../types/index.js';\n\ninterface CreateOptions {\n react?: boolean;\n nextjs?: boolean;\n angular?: boolean;\n express?: boolean;\n fastapi?: boolean;\n yes?: boolean;\n from?: string;\n force?: boolean;\n}\n\nexport function createCommand(): Command {\n const cmd = new Command('create')\n .description('Create a new project')\n .argument('<project-name>', 'Name of the project')\n .option('--react', 'Create a React + Vite project')\n .option('--nextjs', 'Create a Next.js project')\n .option('--angular', 'Create an Angular project')\n .option('--express', 'Create an Express.js project')\n .option('--fastapi', 'Create a FastAPI project')\n .option('-y, --yes', 'Skip prompts and use defaults')\n .option('--from <path>', 'Create from a config file')\n .option('--force', 'Overwrite existing directory')\n .action(async (projectName: string, options: CreateOptions) => {\n try {\n await handleCreate(projectName, options);\n } catch (err) {\n error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nasync function handleCreate(projectName: string, options: CreateOptions): Promise<void> {\n const nameValidation = validateProjectName(projectName);\n if (nameValidation !== true) {\n throw new Error(nameValidation);\n }\n\n const targetDir = path.resolve(process.cwd(), projectName);\n\n if (!options.force) {\n const dirValidation = await validateDirectory(targetDir);\n if (dirValidation !== true) {\n throw new Error(dirValidation);\n }\n }\n\n let config: ProjectConfig;\n\n if (options.from) {\n config = await loadConfigFromFile(options.from, projectName);\n } else if (options.yes || hasFrameworkFlag(options)) {\n config = buildQuickConfig(projectName, options);\n } else {\n config = await runPrompts(projectName);\n }\n\n newLine();\n banner(`Creating project \"${config.name}\"...`);\n newLine();\n\n const generator = createGenerator(config, targetDir);\n await generator.generate();\n\n newLine();\n success(`Project \"${config.name}\" created successfully! 🎉`);\n newLine();\n console.log('Next steps:');\n console.log(` cd ${config.name}`);\n\n if (config.framework === 'fastapi') {\n console.log(' pip install -r requirements.txt');\n console.log(' uvicorn app.main:app --reload');\n } else {\n console.log(` ${config.packageManager} install`);\n console.log(` ${config.packageManager} run dev`);\n }\n\n newLine();\n console.log('Happy coding! 🚀');\n newLine();\n}\n\nfunction hasFrameworkFlag(options: CreateOptions): boolean {\n return !!(options.react || options.nextjs || options.angular || options.express || options.fastapi);\n}\n\nfunction buildQuickConfig(projectName: string, options: CreateOptions): ProjectConfig {\n const config: ProjectConfig = { ...DEFAULT_CONFIG, name: projectName };\n\n if (options.react) {\n config.type = 'frontend';\n config.framework = 'react';\n } else if (options.nextjs) {\n config.type = 'frontend';\n config.framework = 'nextjs';\n } else if (options.angular) {\n config.type = 'frontend';\n config.framework = 'angular';\n } else if (options.express) {\n config.type = 'backend';\n config.framework = 'express';\n } else if (options.fastapi) {\n config.type = 'backend';\n config.framework = 'fastapi';\n }\n\n return config;\n}\n\nasync function loadConfigFromFile(configPath: string, projectName: string): Promise<ProjectConfig> {\n const resolvedPath = path.resolve(process.cwd(), configPath);\n const content = await fs.readJSON(resolvedPath);\n return { ...DEFAULT_CONFIG, ...content, name: projectName };\n}\n","import inquirer from 'inquirer';\nimport type { ProjectType, FrameworkType } from '../types/index.js';\n\nexport async function promptProjectType(): Promise<ProjectType> {\n const { projectType } = await inquirer.prompt([\n {\n type: 'list',\n name: 'projectType',\n message: 'What type of project?',\n choices: [\n { name: 'Frontend (React, Next.js, Angular)', value: 'frontend' },\n { name: 'Backend (Express, FastAPI)', value: 'backend' },\n { name: 'Full-Stack (Frontend + Backend)', value: 'fullstack' },\n ],\n },\n ]);\n\n return projectType;\n}\n\nexport async function promptFramework(projectType: ProjectType): Promise<FrameworkType> {\n if (projectType === 'frontend') {\n const { framework } = await inquirer.prompt([\n {\n type: 'list',\n name: 'framework',\n message: 'Which frontend framework?',\n choices: [\n { name: 'React + Vite', value: 'react' },\n { name: 'Next.js (App Router)', value: 'nextjs' },\n { name: 'Angular 18', value: 'angular' },\n ],\n },\n ]);\n return framework;\n }\n\n if (projectType === 'backend') {\n const { framework } = await inquirer.prompt([\n {\n type: 'list',\n name: 'framework',\n message: 'Which backend framework?',\n choices: [\n { name: 'Express.js', value: 'express' },\n { name: 'FastAPI (Python)', value: 'fastapi' },\n ],\n },\n ]);\n return framework;\n }\n\n // fullstack — prompt for frontend (we'll use express as the backend)\n const { framework } = await inquirer.prompt([\n {\n type: 'list',\n name: 'framework',\n message: 'Which frontend framework?',\n choices: [\n { name: 'React + Vite', value: 'react' },\n { name: 'Next.js', value: 'nextjs' },\n { name: 'Angular 18', value: 'angular' },\n ],\n },\n ]);\n return framework;\n}\n","import inquirer from 'inquirer';\nimport type { FeatureFlags, ProjectType, FrameworkType } from '../types/index.js';\n\ninterface FeatureChoice {\n name: string;\n value: keyof FeatureFlags;\n checked: boolean;\n disabled?: string | false;\n}\n\nexport async function promptFeatures(\n projectType: ProjectType,\n framework: FrameworkType,\n): Promise<FeatureFlags> {\n const isPython = framework === 'fastapi';\n\n const choices: FeatureChoice[] = [\n {\n name: 'TypeScript',\n value: 'typescript',\n checked: true,\n disabled: isPython ? 'N/A for Python' : false,\n },\n { name: 'ESLint + Prettier', value: 'eslint', checked: !isPython, disabled: isPython ? 'N/A for Python' : false },\n { name: 'Tailwind CSS', value: 'tailwind', checked: false },\n { name: 'shadcn/ui components', value: 'shadcn', checked: false },\n { name: isPython ? 'Pytest testing' : 'Vitest testing', value: 'testing', checked: true },\n { name: 'GitHub Actions CI/CD', value: 'githubActions', checked: false },\n { name: 'Docker setup', value: 'docker', checked: false },\n { name: 'Husky pre-commit hooks', value: 'husky', checked: false, disabled: isPython ? 'N/A for Python' : false },\n { name: '.env example file', value: 'envExample', checked: false },\n ];\n\n // Filter out frontend-only features for backend projects\n const filteredChoices =\n projectType === 'backend'\n ? choices.filter((c) => !['tailwind', 'shadcn'].includes(c.value))\n : choices;\n\n const { features } = await inquirer.prompt([\n {\n type: 'checkbox',\n name: 'features',\n message: 'Select features:',\n choices: filteredChoices,\n },\n ]);\n\n const selectedFeatures = features as (keyof FeatureFlags)[];\n\n return {\n typescript: !isPython && selectedFeatures.includes('typescript'),\n eslint: !isPython && selectedFeatures.includes('eslint'),\n prettier: !isPython && selectedFeatures.includes('eslint'),\n tailwind: selectedFeatures.includes('tailwind'),\n shadcn: selectedFeatures.includes('shadcn'),\n testing: selectedFeatures.includes('testing'),\n githubActions: selectedFeatures.includes('githubActions'),\n docker: selectedFeatures.includes('docker'),\n husky: !isPython && selectedFeatures.includes('husky'),\n envExample: selectedFeatures.includes('envExample'),\n };\n}\n","import inquirer from 'inquirer';\nimport type { VariantType, PackageManager, FrameworkType } from '../types/index.js';\nimport { FRAMEWORKS, VARIANT_DISPLAY_NAMES } from '../constants.js';\n\nexport async function promptVariant(framework: FrameworkType): Promise<VariantType> {\n const meta = FRAMEWORKS[framework];\n\n if (meta.variants.length <= 1) {\n return 'base';\n }\n\n const { variant } = await inquirer.prompt([\n {\n type: 'list',\n name: 'variant',\n message: 'Select a template variant:',\n choices: meta.variants.map((v) => ({\n name: VARIANT_DISPLAY_NAMES[v],\n value: v,\n })),\n },\n ]);\n\n return variant;\n}\n\nexport async function promptPackageManager(): Promise<PackageManager> {\n const { packageManager } = await inquirer.prompt([\n {\n type: 'list',\n name: 'packageManager',\n message: 'Package manager?',\n choices: [\n { name: 'npm', value: 'npm' },\n { name: 'yarn', value: 'yarn' },\n { name: 'pnpm', value: 'pnpm' },\n ],\n },\n ]);\n\n return packageManager;\n}\n\nexport async function promptGitInit(): Promise<boolean> {\n const { gitInit } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'gitInit',\n message: 'Initialize git repository?',\n default: true,\n },\n ]);\n\n return gitInit;\n}\n","import type { FrameworkMeta, FrameworkType, VariantType } from './types/index.js';\n\nexport const FRAMEWORKS: Record<FrameworkType, FrameworkMeta> = {\n react: {\n name: 'react',\n displayName: 'React + Vite',\n description: 'React 19 with Vite and TypeScript',\n type: 'frontend',\n variants: ['base', 'with-tailwind', 'with-shadcn'],\n language: 'typescript',\n },\n nextjs: {\n name: 'nextjs',\n displayName: 'Next.js (App Router)',\n description: 'Next.js 15 with App Router and TypeScript',\n type: 'frontend',\n variants: ['base', 'with-auth', 'with-prisma'],\n language: 'typescript',\n },\n angular: {\n name: 'angular',\n displayName: 'Angular 18',\n description: 'Angular 18 standalone with TypeScript',\n type: 'frontend',\n variants: ['base'],\n language: 'typescript',\n },\n express: {\n name: 'express',\n displayName: 'Express.js',\n description: 'Express 5 with TypeScript',\n type: 'backend',\n variants: ['base', 'with-prisma'],\n language: 'typescript',\n },\n fastapi: {\n name: 'fastapi',\n displayName: 'FastAPI',\n description: 'FastAPI with Pydantic and Python',\n type: 'backend',\n variants: ['base'],\n language: 'python',\n },\n};\n\nexport const FRONTEND_FRAMEWORKS: FrameworkType[] = ['react', 'nextjs', 'angular'];\nexport const BACKEND_FRAMEWORKS: FrameworkType[] = ['express', 'fastapi'];\n\nexport const VARIANT_DISPLAY_NAMES: Record<VariantType, string> = {\n base: 'Base (minimal setup)',\n 'with-tailwind': 'With Tailwind CSS',\n 'with-shadcn': 'With shadcn/ui',\n 'with-auth': 'With NextAuth.js',\n 'with-prisma': 'With Prisma ORM',\n};\n","import type { ProjectConfig } from '../types/index.js';\nimport { promptProjectType, promptFramework } from './framework.js';\nimport { promptFeatures } from './features.js';\nimport { promptVariant, promptPackageManager, promptGitInit } from './config.js';\n\nexport async function runPrompts(projectName: string): Promise<ProjectConfig> {\n const type = await promptProjectType();\n const framework = await promptFramework(type);\n const variant = await promptVariant(framework);\n const features = await promptFeatures(type, framework);\n\n const isPython = framework === 'fastapi';\n const packageManager = isPython ? 'npm' : await promptPackageManager();\n const gitInit = await promptGitInit();\n\n return {\n name: projectName,\n type,\n framework,\n variant,\n features,\n packageManager,\n gitInit,\n };\n}\n","import path from 'node:path';\nimport { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class ReactGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring React + Vite + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring React + Vite + TypeScript');\n\n if (this.config.features.testing) {\n success('Configuring Vitest');\n }\n }\n\n private getVariantPath(variant: string): string {\n return path.join(this.templatesDir, 'react', variant);\n }\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport { execSync } from 'node:child_process';\nimport { createDir, renderAndWrite, getTemplatesDir, spinner, success, debug } from '../utils/index.js';\nimport type { ProjectConfig } from '../types/index.js';\nimport type { GeneratorResult } from '../types/generator.js';\n\nexport abstract class BaseGenerator {\n protected config: ProjectConfig;\n protected targetDir: string;\n protected templatesDir: string;\n protected result: GeneratorResult = { filesCreated: [], warnings: [] };\n\n constructor(config: ProjectConfig, targetDir: string) {\n this.config = config;\n this.targetDir = targetDir;\n this.templatesDir = getTemplatesDir();\n }\n\n async generate(): Promise<GeneratorResult> {\n await this.createProjectDir();\n await this.generateBase();\n await this.applyVariant();\n await this.applySharedConfigs();\n await this.applyFeatures();\n await this.initGit();\n return this.result;\n }\n\n protected abstract generateBase(): Promise<void>;\n\n protected async applyVariant(): Promise<void> {\n if (this.config.variant === 'base') return;\n\n const variantDir = this.getVariantTemplateDir();\n if (await fs.pathExists(variantDir)) {\n const s = spinner(`Applying ${this.config.variant} variant`);\n s.start();\n await this.renderDirectory(variantDir, this.targetDir);\n s.stop();\n success(`Applied ${this.config.variant} variant`);\n }\n }\n\n protected async applySharedConfigs(): Promise<void> {\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n if (this.config.features.eslint) {\n const s = spinner('Setting up ESLint + Prettier');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'eslint.config.js.hbs'),\n path.join(this.targetDir, 'eslint.config.js'),\n );\n await this.renderTemplateFile(\n path.join(sharedDir, 'prettier.config.js.hbs'),\n path.join(this.targetDir, '.prettierrc'),\n );\n s.stop();\n success('Setting up ESLint + Prettier');\n }\n\n // Gitignore\n await this.renderTemplateFile(\n path.join(sharedDir, 'gitignore.hbs'),\n path.join(this.targetDir, '.gitignore'),\n );\n\n // README\n const s2 = spinner('Generating README.md');\n s2.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'readme.md.hbs'),\n path.join(this.targetDir, 'README.md'),\n );\n s2.stop();\n success('Generating README.md');\n\n // License\n await this.renderTemplateFile(\n path.join(sharedDir, 'license.hbs'),\n path.join(this.targetDir, 'LICENSE'),\n );\n }\n\n protected async applyFeatures(): Promise<void> {\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n if (this.config.features.githubActions) {\n const s = spinner('Creating GitHub Actions workflow');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'github-ci.yml.hbs'),\n path.join(this.targetDir, '.github', 'workflows', 'ci.yml'),\n );\n s.stop();\n success('Creating GitHub Actions workflow');\n }\n\n if (this.config.features.docker) {\n const s = spinner('Adding Docker configuration');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'docker', 'Dockerfile.hbs'),\n path.join(this.targetDir, 'Dockerfile'),\n );\n await this.renderTemplateFile(\n path.join(sharedDir, 'docker', 'docker-compose.yml.hbs'),\n path.join(this.targetDir, 'docker-compose.yml'),\n );\n s.stop();\n success('Adding Docker configuration');\n }\n }\n\n protected async createProjectDir(): Promise<void> {\n const s = spinner('Creating project structure');\n s.start();\n await createDir(this.targetDir);\n s.stop();\n success('Creating project structure');\n }\n\n protected async initGit(): Promise<void> {\n if (!this.config.gitInit) return;\n\n const s = spinner('Initializing git repository');\n s.start();\n try {\n execSync('git init', { cwd: this.targetDir, stdio: 'pipe' });\n execSync('git add -A', { cwd: this.targetDir, stdio: 'pipe' });\n execSync('git commit -m \"Initial commit from scaffold\"', {\n cwd: this.targetDir,\n stdio: 'pipe',\n });\n s.stop();\n success('Initializing git repository');\n } catch {\n s.stop();\n debug('Git initialization skipped (git not available)');\n }\n }\n\n protected async renderTemplateFile(\n templatePath: string,\n outputPath: string,\n ): Promise<void> {\n const templateData = this.getTemplateData();\n\n if (await fs.pathExists(templatePath)) {\n await renderAndWrite(templatePath, outputPath, templateData);\n this.result.filesCreated.push(outputPath);\n } else {\n debug(`Template not found: ${templatePath}`);\n }\n }\n\n protected async renderDirectory(srcDir: string, destDir: string): Promise<void> {\n const entries = await fs.readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(srcDir, entry.name);\n const destName = entry.name.replace(/\\.hbs$/, '');\n const destPath = path.join(destDir, destName);\n\n if (entry.isDirectory()) {\n await this.renderDirectory(srcPath, destPath);\n } else if (entry.name.endsWith('.hbs')) {\n await this.renderTemplateFile(srcPath, destPath);\n } else {\n await fs.ensureDir(path.dirname(destPath));\n await fs.copy(srcPath, destPath);\n this.result.filesCreated.push(destPath);\n }\n }\n }\n\n protected getTemplateData(): object {\n return {\n ...this.config,\n year: new Date().getFullYear(),\n };\n }\n\n protected getBaseTemplateDir(): string {\n return path.join(this.templatesDir, this.config.framework, 'base');\n }\n\n protected getVariantTemplateDir(): string {\n return path.join(this.templatesDir, this.config.framework, this.config.variant);\n }\n}\n","import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\n\nlet verbose = false;\n\nexport function setVerbose(value: boolean): void {\n verbose = value;\n}\n\nexport function info(message: string): void {\n console.log(chalk.blue('ℹ'), message);\n}\n\nexport function success(message: string): void {\n console.log(chalk.green('✔'), message);\n}\n\nexport function warn(message: string): void {\n console.log(chalk.yellow('⚠'), message);\n}\n\nexport function error(message: string): void {\n console.log(chalk.red('✖'), message);\n}\n\nexport function debug(message: string): void {\n if (verbose) {\n console.log(chalk.gray('⬥'), chalk.gray(message));\n }\n}\n\nexport function spinner(text: string): Ora {\n return ora({ text, color: 'cyan' });\n}\n\nexport function newLine(): void {\n console.log();\n}\n\nexport function banner(text: string): void {\n console.log(chalk.bold.cyan(text));\n}\n","import { directoryExists } from './file.js';\n\nconst VALID_PROJECT_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/;\n\nexport function validateProjectName(name: string): string | true {\n if (!name || name.trim().length === 0) {\n return 'Project name is required.';\n }\n\n if (!VALID_PROJECT_NAME.test(name)) {\n return 'Project name must be a valid npm package name (lowercase, no spaces, can use hyphens and dots).';\n }\n\n if (name.length > 214) {\n return 'Project name must be less than 214 characters.';\n }\n\n return true;\n}\n\nexport async function validateDirectory(dirPath: string): Promise<string | true> {\n if (await directoryExists(dirPath)) {\n return `Directory \"${dirPath}\" already exists. Use --force to overwrite.`;\n }\n return true;\n}\n\nexport function checkNodeVersion(minMajor: number = 20): string | true {\n const version = process.version;\n const major = parseInt(version.slice(1).split('.')[0], 10);\n\n if (major < minMajor) {\n return `Node.js ${minMajor}+ is required. You are using ${version}.`;\n }\n\n return true;\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class NextjsGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring Next.js + App Router + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring Next.js + App Router + TypeScript');\n\n if (this.config.features.testing) {\n success('Configuring Vitest');\n }\n }\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class AngularGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring Angular 18 + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring Angular 18 + TypeScript');\n }\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class ExpressGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring Express 5 + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring Express 5 + TypeScript');\n\n if (this.config.features.testing) {\n success('Configuring Vitest');\n }\n }\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class FastAPIGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring FastAPI + Pydantic');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring FastAPI + Pydantic');\n\n if (this.config.features.testing) {\n success('Configuring Pytest');\n }\n }\n\n protected override async applySharedConfigs(): Promise<void> {\n // Python projects don't use ESLint/Prettier/tsconfig\n const path = await import('node:path');\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n // Still apply gitignore, readme, license\n await this.renderTemplateFile(\n path.join(sharedDir, 'gitignore.hbs'),\n path.join(this.targetDir, '.gitignore'),\n );\n\n const s = spinner('Generating README.md');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'readme.md.hbs'),\n path.join(this.targetDir, 'README.md'),\n );\n s.stop();\n success('Generating README.md');\n\n await this.renderTemplateFile(\n path.join(sharedDir, 'license.hbs'),\n path.join(this.targetDir, 'LICENSE'),\n );\n }\n}\n","import path from 'node:path';\nimport { BaseGenerator } from './base.js';\nimport { ReactGenerator } from './react.js';\nimport { NextjsGenerator } from './nextjs.js';\nimport { AngularGenerator } from './angular.js';\nimport { ExpressGenerator } from './express.js';\nimport { spinner, success, createDir } from '../utils/index.js';\nimport { renderAndWrite, getTemplatesDir } from '../utils/file.js';\nimport type { ProjectConfig } from '../types/index.js';\n\nexport class FullstackGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const s = spinner('Setting up full-stack monorepo');\n s.start();\n\n // Create apps directories\n const webDir = path.join(this.targetDir, 'apps', 'web');\n const apiDir = path.join(this.targetDir, 'apps', 'api');\n await createDir(webDir);\n await createDir(apiDir);\n\n s.stop();\n success('Setting up full-stack monorepo');\n\n // Generate frontend in apps/web\n const frontendConfig: ProjectConfig = {\n ...this.config,\n type: 'frontend',\n gitInit: false,\n };\n\n const FrontendGenerator = this.getFrontendGeneratorClass();\n const frontendGen = new FrontendGenerator(frontendConfig, webDir);\n await frontendGen.generateBase();\n\n // Generate backend in apps/api\n const backendConfig: ProjectConfig = {\n ...this.config,\n type: 'backend',\n framework: 'express',\n gitInit: false,\n };\n\n const backendGen = new ExpressGenerator(backendConfig, apiDir);\n await backendGen.generateBase();\n\n // Write root package.json for workspaces\n const rootPkgPath = path.join(this.targetDir, 'package.json');\n const rootPkg = {\n name: this.config.name,\n private: true,\n workspaces: ['apps/*'],\n scripts: {\n dev: 'npm run --workspaces dev',\n build: 'npm run --workspaces build',\n lint: 'npm run --workspaces lint',\n test: 'npm run --workspaces test',\n },\n };\n const { writeFile } = await import('../utils/file.js');\n await writeFile(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\\n');\n }\n\n private getFrontendGeneratorClass() {\n switch (this.config.framework) {\n case 'nextjs':\n return NextjsGenerator;\n case 'angular':\n return AngularGenerator;\n case 'react':\n default:\n return ReactGenerator;\n }\n }\n}\n","import type { ProjectConfig } from '../types/index.js';\nimport { BaseGenerator } from './base.js';\nimport { ReactGenerator } from './react.js';\nimport { NextjsGenerator } from './nextjs.js';\nimport { AngularGenerator } from './angular.js';\nimport { ExpressGenerator } from './express.js';\nimport { FastAPIGenerator } from './fastapi.js';\nimport { FullstackGenerator } from './fullstack.js';\n\nexport function createGenerator(config: ProjectConfig, targetDir: string): BaseGenerator {\n if (config.type === 'fullstack') {\n return new FullstackGenerator(config, targetDir);\n }\n\n switch (config.framework) {\n case 'react':\n return new ReactGenerator(config, targetDir);\n case 'nextjs':\n return new NextjsGenerator(config, targetDir);\n case 'angular':\n return new AngularGenerator(config, targetDir);\n case 'express':\n return new ExpressGenerator(config, targetDir);\n case 'fastapi':\n return new FastAPIGenerator(config, targetDir);\n default:\n throw new Error(`Unknown framework: ${config.framework}`);\n }\n}\n\nexport { BaseGenerator } from './base.js';\n","export type ProjectType = 'frontend' | 'backend' | 'fullstack';\n\nexport type FrameworkType = 'react' | 'nextjs' | 'angular' | 'express' | 'fastapi';\n\nexport type VariantType =\n | 'base'\n | 'with-tailwind'\n | 'with-shadcn'\n | 'with-auth'\n | 'with-prisma';\n\nexport type PackageManager = 'npm' | 'yarn' | 'pnpm';\n\nexport interface FeatureFlags {\n typescript: boolean;\n eslint: boolean;\n prettier: boolean;\n tailwind: boolean;\n shadcn: boolean;\n testing: boolean;\n githubActions: boolean;\n docker: boolean;\n husky: boolean;\n envExample: boolean;\n}\n\nexport interface ProjectConfig {\n name: string;\n type: ProjectType;\n framework: FrameworkType;\n variant: VariantType;\n features: FeatureFlags;\n packageManager: PackageManager;\n gitInit: boolean;\n}\n\nexport interface FrameworkMeta {\n name: string;\n displayName: string;\n description: string;\n type: ProjectType;\n variants: VariantType[];\n language: 'typescript' | 'python';\n}\n\nexport const DEFAULT_FEATURES: FeatureFlags = {\n typescript: true,\n eslint: true,\n prettier: true,\n tailwind: false,\n shadcn: false,\n testing: true,\n githubActions: false,\n docker: false,\n husky: false,\n envExample: false,\n};\n\nexport const DEFAULT_CONFIG: ProjectConfig = {\n name: '',\n type: 'frontend',\n framework: 'react',\n variant: 'base',\n features: { ...DEFAULT_FEATURES },\n packageManager: 'npm',\n gitInit: true,\n};\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { FRAMEWORKS, VARIANT_DISPLAY_NAMES } from '../constants.js';\nimport type { FrameworkType } from '../types/index.js';\nimport { newLine } from '../utils/logger.js';\n\nexport function listCommand(): Command {\n return new Command('list')\n .description('List all available templates')\n .action(() => {\n newLine();\n console.log(chalk.bold.cyan('Available Templates'));\n console.log(chalk.gray('─'.repeat(60)));\n newLine();\n\n const categories = {\n Frontend: ['react', 'nextjs', 'angular'] as FrameworkType[],\n Backend: ['express', 'fastapi'] as FrameworkType[],\n };\n\n for (const [category, frameworks] of Object.entries(categories)) {\n console.log(chalk.bold.white(` ${category}`));\n newLine();\n\n for (const fw of frameworks) {\n const meta = FRAMEWORKS[fw];\n console.log(` ${chalk.green(meta.displayName.padEnd(25))} ${chalk.gray(meta.description)}`);\n\n for (const variant of meta.variants) {\n const label = VARIANT_DISPLAY_NAMES[variant];\n console.log(` ${chalk.gray('•')} ${label}`);\n }\n newLine();\n }\n }\n\n console.log(chalk.gray('─'.repeat(60)));\n console.log(\n chalk.gray(' Use'),\n chalk.cyan('scaffold create <name> --<framework>'),\n chalk.gray('for quick setup'),\n );\n newLine();\n });\n}\n","import { Command } from 'commander';\nimport { execSync } from 'node:child_process';\nimport chalk from 'chalk';\nimport { newLine } from '../utils/logger.js';\n\ninterface Check {\n name: string;\n command: string;\n versionFlag?: string;\n required: boolean;\n}\n\nconst CHECKS: Check[] = [\n { name: 'Node.js', command: 'node', versionFlag: '--version', required: true },\n { name: 'npm', command: 'npm', versionFlag: '--version', required: false },\n { name: 'yarn', command: 'yarn', versionFlag: '--version', required: false },\n { name: 'pnpm', command: 'pnpm', versionFlag: '--version', required: false },\n { name: 'git', command: 'git', versionFlag: '--version', required: true },\n { name: 'Python', command: 'python3', versionFlag: '--version', required: false },\n];\n\nexport function doctorCommand(): Command {\n return new Command('doctor')\n .description('Check system dependencies')\n .action(() => {\n newLine();\n console.log(chalk.bold.cyan('System Check'));\n console.log(chalk.gray('─'.repeat(40)));\n newLine();\n\n let allGood = true;\n\n for (const check of CHECKS) {\n try {\n const version = execSync(`${check.command} ${check.versionFlag ?? '--version'}`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n const versionStr = version.split('\\n')[0];\n console.log(` ${chalk.green('✔')} ${check.name.padEnd(12)} ${chalk.gray(versionStr)}`);\n } catch {\n if (check.required) {\n console.log(` ${chalk.red('✖')} ${check.name.padEnd(12)} ${chalk.red('not found (required)')}`);\n allGood = false;\n } else {\n console.log(` ${chalk.yellow('–')} ${check.name.padEnd(12)} ${chalk.gray('not found (optional)')}`);\n }\n }\n }\n\n newLine();\n\n if (allGood) {\n console.log(chalk.green(' All required dependencies are installed!'));\n } else {\n console.log(chalk.red(' Some required dependencies are missing.'));\n }\n\n newLine();\n });\n}\n","import { createCli } from './cli.js';\n\nconst program = createCli();\nprogram.parse();\n"],"mappings":"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","names":["Command","path","fs","framework","inquirer","inquirer","inquirer","path","path","path","path","path","writeFile","path","fs","Command","chalk","Command","chalk","Command","execSync","chalk","Command","chalk","execSync","program","Command"]}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@codecanvascollective/scaffold",
3
+ "version": "0.1.0",
4
+ "description": "CLI tool for scaffolding modern full-stack projects",
5
+ "type": "module",
6
+ "bin": {
7
+ "scaffold": "./dist/index.js"
8
+ },
9
+ "engines": {
10
+ "node": ">=20.0.0"
11
+ },
12
+ "scripts": {
13
+ "build": "tsup",
14
+ "dev": "tsup --watch",
15
+ "test": "vitest run",
16
+ "test:watch": "vitest",
17
+ "test:coverage": "vitest run --coverage",
18
+ "lint": "eslint src/",
19
+ "format": "prettier --write .",
20
+ "format:check": "prettier --check .",
21
+ "prepublishOnly": "npm run build && npm test",
22
+ "typecheck": "tsc --noEmit"
23
+ },
24
+ "dependencies": {
25
+ "chalk": "^5.3.0",
26
+ "commander": "^12.1.0",
27
+ "fs-extra": "^11.2.0",
28
+ "handlebars": "^4.7.8",
29
+ "inquirer": "^9.2.0",
30
+ "ora": "^8.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@changesets/cli": "^2.27.0",
34
+ "@types/fs-extra": "^11.0.4",
35
+ "@types/inquirer": "^9.0.7",
36
+ "@types/node": "^20.0.0",
37
+ "eslint": "^9.0.0",
38
+ "prettier": "^3.3.0",
39
+ "tsup": "^8.0.0",
40
+ "typescript": "^5.5.0",
41
+ "typescript-eslint": "^8.0.0",
42
+ "vitest": "^2.0.0"
43
+ },
44
+ "keywords": [
45
+ "scaffold",
46
+ "cli",
47
+ "generator",
48
+ "boilerplate",
49
+ "react",
50
+ "nextjs",
51
+ "angular",
52
+ "express",
53
+ "fastapi",
54
+ "starter-kit",
55
+ "project-generator",
56
+ "codecanvascollective"
57
+ ],
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "https://github.com/CodeCanvasCollective/scaffold"
61
+ },
62
+ "homepage": "https://codecanvascollective.com/scaffold",
63
+ "bugs": "https://github.com/CodeCanvasCollective/scaffold/issues",
64
+ "license": "MIT",
65
+ "author": "CodeCanvas Collective <info@codecanvascollective.com>",
66
+ "files": [
67
+ "dist",
68
+ "src/templates"
69
+ ]
70
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3
+ "version": 1,
4
+ "newProjectRoot": "projects",
5
+ "projects": {
6
+ "{{name}}": {
7
+ "projectType": "application",
8
+ "root": "",
9
+ "sourceRoot": "src",
10
+ "prefix": "app",
11
+ "architect": {
12
+ "build": {
13
+ "builder": "@angular-devkit/build-angular:application",
14
+ "options": {
15
+ "outputPath": "dist/{{name}}",
16
+ "index": "src/index.html",
17
+ "browser": "src/main.ts",
18
+ "tsConfig": "tsconfig.json",
19
+ "styles": ["src/styles.css"],
20
+ "scripts": []
21
+ }
22
+ },
23
+ "serve": {
24
+ "builder": "@angular-devkit/build-angular:dev-server",
25
+ "configurations": {
26
+ "development": {
27
+ "buildTarget": "{{name}}:build:development"
28
+ }
29
+ },
30
+ "defaultConfiguration": "development"
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "{{name}}",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "ng serve",
7
+ "build": "ng build",
8
+ "start": "ng serve"{{#if features.testing}},
9
+ "test": "ng test --watch=false"{{/if}}{{#if features.eslint}},
10
+ "lint": "ng lint"{{/if}}
11
+ },
12
+ "dependencies": {
13
+ "@angular/animations": "^18.0.0",
14
+ "@angular/common": "^18.0.0",
15
+ "@angular/compiler": "^18.0.0",
16
+ "@angular/core": "^18.0.0",
17
+ "@angular/forms": "^18.0.0",
18
+ "@angular/platform-browser": "^18.0.0",
19
+ "@angular/platform-browser-dynamic": "^18.0.0",
20
+ "@angular/router": "^18.0.0",
21
+ "rxjs": "~7.8.0",
22
+ "tslib": "^2.6.0",
23
+ "zone.js": "~0.14.0"
24
+ },
25
+ "devDependencies": {
26
+ "@angular-devkit/build-angular": "^18.0.0",
27
+ "@angular/cli": "^18.0.0",
28
+ "@angular/compiler-cli": "^18.0.0",
29
+ "typescript": "~5.4.0"{{#if features.testing}},
30
+ "karma": "~6.4.0",
31
+ "karma-chrome-launcher": "~3.2.0",
32
+ "karma-coverage": "~2.2.0",
33
+ "karma-jasmine": "~5.1.0",
34
+ "@types/jasmine": "~5.1.0"{{/if}}
35
+ }
36
+ }
@@ -0,0 +1,19 @@
1
+ import { Component } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'app-root',
5
+ standalone: true,
6
+ template: `
7
+ <h1>{{ "{{" }} title {{ "}}" }}</h1>
8
+ <p>Welcome to your new Angular project!</p>
9
+ `,
10
+ styles: [`
11
+ h1 {
12
+ font-size: 3.2em;
13
+ line-height: 1.1;
14
+ }
15
+ `],
16
+ })
17
+ export class AppComponent {
18
+ title = '{{name}}';
19
+ }
@@ -0,0 +1,5 @@
1
+ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
2
+
3
+ export const appConfig: ApplicationConfig = {
4
+ providers: [provideZoneChangeDetection({ eventCoalescing: true })],
5
+ };
@@ -0,0 +1,7 @@
1
+ import { bootstrapApplication } from '@angular/platform-browser';
2
+ import { AppComponent } from './app/app.component';
3
+ import { appConfig } from './app/app.config';
4
+
5
+ bootstrapApplication(AppComponent, appConfig).catch((err) =>
6
+ console.error(err),
7
+ );
@@ -0,0 +1,26 @@
1
+ {
2
+ "compileOnSave": false,
3
+ "compilerOptions": {
4
+ "outDir": "./dist/out-tsc",
5
+ "strict": true,
6
+ "noImplicitOverride": true,
7
+ "noPropertyAccessFromIndexSignature": true,
8
+ "noImplicitReturns": true,
9
+ "noFallthroughCasesInSwitch": true,
10
+ "sourceMap": true,
11
+ "declaration": false,
12
+ "experimentalDecorators": true,
13
+ "moduleResolution": "bundler",
14
+ "importHelpers": true,
15
+ "target": "ES2022",
16
+ "module": "ES2022",
17
+ "lib": ["ES2022", "dom"],
18
+ "useDefineForClassFields": false
19
+ },
20
+ "angularCompilerOptions": {
21
+ "enableI18nLegacyMessageIdFormat": false,
22
+ "strictInjectionParameters": true,
23
+ "strictInputAccessModifiers": true,
24
+ "strictTemplates": true
25
+ }
26
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "{{name}}",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "tsx watch src/index.ts",
8
+ "build": "tsc",
9
+ "start": "node dist/index.js"{{#if features.testing}},
10
+ "test": "vitest run",
11
+ "test:watch": "vitest"{{/if}}{{#if features.eslint}},
12
+ "lint": "eslint src/"{{/if}}
13
+ },
14
+ "dependencies": {
15
+ "express": "^5.0.0",
16
+ "cors": "^2.8.5"
17
+ },
18
+ "devDependencies": {
19
+ "@types/express": "^5.0.0",
20
+ "@types/cors": "^2.8.17",
21
+ "@types/node": "^20.0.0",
22
+ "tsx": "^4.0.0",
23
+ "typescript": "^5.5.0"{{#if features.testing}},
24
+ "vitest": "^2.0.0",
25
+ "supertest": "^7.0.0",
26
+ "@types/supertest": "^6.0.0"{{/if}}{{#if features.eslint}},
27
+ "@eslint/js": "^9.0.0",
28
+ "eslint": "^9.0.0",
29
+ "typescript-eslint": "^8.0.0",
30
+ "prettier": "^3.3.0"{{/if}}
31
+ }
32
+ }
@@ -0,0 +1,20 @@
1
+ import express from 'express';
2
+ import cors from 'cors';
3
+ import { router } from './routes/index.js';
4
+ import { errorHandler } from './middleware/errorHandler.js';
5
+
6
+ const app = express();
7
+ const port = process.env.PORT ?? 3000;
8
+
9
+ app.use(cors());
10
+ app.use(express.json());
11
+
12
+ app.use('/api', router);
13
+
14
+ app.use(errorHandler);
15
+
16
+ app.listen(port, () => {
17
+ console.log(`Server running at http://localhost:${port}`);
18
+ });
19
+
20
+ export default app;
@@ -0,0 +1,15 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+
3
+ export function errorHandler(
4
+ err: Error,
5
+ _req: Request,
6
+ res: Response,
7
+ _next: NextFunction,
8
+ ): void {
9
+ console.error(err.stack);
10
+
11
+ res.status(500).json({
12
+ error: 'Internal Server Error',
13
+ message: process.env.NODE_ENV === 'development' ? err.message : undefined,
14
+ });
15
+ }
@@ -0,0 +1,11 @@
1
+ import { Router } from 'express';
2
+
3
+ export const router = Router();
4
+
5
+ router.get('/health', (_req, res) => {
6
+ res.json({ status: 'ok', timestamp: new Date().toISOString() });
7
+ });
8
+
9
+ router.get('/', (_req, res) => {
10
+ res.json({ message: 'Welcome to {{name}} API' });
11
+ });
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "resolveJsonModule": true,
11
+ "declaration": true,
12
+ "sourceMap": true,
13
+ "outDir": "./dist",
14
+ "rootDir": "./src"
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }
@@ -0,0 +1,16 @@
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ }
4
+
5
+ datasource db {
6
+ provider = "postgresql"
7
+ url = env("DATABASE_URL")
8
+ }
9
+
10
+ model User {
11
+ id String @id @default(cuid())
12
+ email String @unique
13
+ name String?
14
+ createdAt DateTime @default(now())
15
+ updatedAt DateTime @updatedAt
16
+ }
@@ -0,0 +1,27 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+
3
+ const prisma = new PrismaClient();
4
+
5
+ async function main() {
6
+ console.log('Seeding database...');
7
+
8
+ await prisma.user.upsert({
9
+ where: { email: 'admin@example.com' },
10
+ update: {},
11
+ create: {
12
+ email: 'admin@example.com',
13
+ name: 'Admin',
14
+ },
15
+ });
16
+
17
+ console.log('Database seeded.');
18
+ }
19
+
20
+ main()
21
+ .catch((e) => {
22
+ console.error(e);
23
+ process.exit(1);
24
+ })
25
+ .finally(async () => {
26
+ await prisma.$disconnect();
27
+ });
@@ -0,0 +1,11 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+
3
+ const globalForPrisma = globalThis as unknown as {
4
+ prisma: PrismaClient | undefined;
5
+ };
6
+
7
+ export const db = globalForPrisma.prisma ?? new PrismaClient();
8
+
9
+ if (process.env.NODE_ENV !== 'production') {
10
+ globalForPrisma.prisma = db;
11
+ }
@@ -0,0 +1,13 @@
1
+ from fastapi import FastAPI
2
+
3
+ app = FastAPI(title="{{name}}", version="0.1.0")
4
+
5
+
6
+ @app.get("/")
7
+ async def root():
8
+ return {"message": "Welcome to {{name}} API"}
9
+
10
+
11
+ @app.get("/health")
12
+ async def health():
13
+ return {"status": "ok"}
@@ -0,0 +1 @@
1
+ # Models package
@@ -0,0 +1 @@
1
+ # Routes package
@@ -0,0 +1,8 @@
1
+ [project]
2
+ name = "{{name}}"
3
+ version = "0.1.0"
4
+ description = ""
5
+ requires-python = ">=3.11"
6
+
7
+ [tool.pytest.ini_options]
8
+ testpaths = ["tests"]
@@ -0,0 +1,7 @@
1
+ fastapi>=0.115.0
2
+ uvicorn[standard]>=0.30.0
3
+ pydantic>=2.0.0
4
+ {{#if features.testing}}
5
+ pytest>=8.0.0
6
+ httpx>=0.27.0
7
+ {{/if}}
@@ -0,0 +1,5 @@
1
+ import type { NextConfig } from 'next';
2
+
3
+ const nextConfig: NextConfig = {};
4
+
5
+ export default nextConfig;
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "{{name}}",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start"{{#if features.testing}},
9
+ "test": "vitest run",
10
+ "test:watch": "vitest"{{/if}}{{#if features.eslint}},
11
+ "lint": "next lint"{{/if}}
12
+ },
13
+ "dependencies": {
14
+ "next": "^15.0.0",
15
+ "react": "^19.0.0",
16
+ "react-dom": "^19.0.0"
17
+ },
18
+ "devDependencies": {
19
+ "@types/node": "^20.0.0",
20
+ "@types/react": "^19.0.0",
21
+ "@types/react-dom": "^19.0.0",
22
+ "typescript": "^5.5.0"{{#if features.testing}},
23
+ "@testing-library/react": "^16.0.0",
24
+ "@testing-library/jest-dom": "^6.0.0",
25
+ "vitest": "^2.0.0"{{/if}}{{#if features.eslint}},
26
+ "eslint": "^9.0.0",
27
+ "eslint-config-next": "^15.0.0",
28
+ "prettier": "^3.3.0"{{/if}}{{#if features.tailwind}},
29
+ "tailwindcss": "^3.4.0",
30
+ "postcss": "^8.4.0",
31
+ "autoprefixer": "^10.4.0"{{/if}}
32
+ }
33
+ }
@@ -0,0 +1,22 @@
1
+ {{#if features.tailwind}}
2
+ @tailwind base;
3
+ @tailwind components;
4
+ @tailwind utilities;
5
+ {{else}}
6
+ :root {
7
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
8
+ color: #213547;
9
+ background-color: #ffffff;
10
+ }
11
+
12
+ body {
13
+ margin: 0;
14
+ min-height: 100vh;
15
+ padding: 2rem;
16
+ }
17
+
18
+ h1 {
19
+ font-size: 3.2em;
20
+ line-height: 1.1;
21
+ }
22
+ {{/if}}
@@ -0,0 +1,19 @@
1
+ import type { Metadata } from 'next';
2
+ import './globals.css';
3
+
4
+ export const metadata: Metadata = {
5
+ title: '{{name}}',
6
+ description: 'Generated by scaffold',
7
+ };
8
+
9
+ export default function RootLayout({
10
+ children,
11
+ }: {
12
+ children: React.ReactNode;
13
+ }) {
14
+ return (
15
+ <html lang="en">
16
+ <body>{children}</body>
17
+ </html>
18
+ );
19
+ }
@@ -0,0 +1,8 @@
1
+ export default function Home() {
2
+ return (
3
+ <main>
4
+ <h1>{{name}}</h1>
5
+ <p>Welcome to your new Next.js project!</p>
6
+ </main>
7
+ );
8
+ }