UNPKG

typescript-express-starter

Version:
508 lines (491 loc) 17.2 kB
import chalk from 'chalk'; import editJsonFile from 'edit-json-file'; import fs from 'fs'; import path from 'path'; /** * 지원하는 패키지 매니저 목록 * 사용자가 선택할 수 있는 npm, pnpm, yarn 옵션 제공 * @type {Array<{label: string, value: string}>} */ export const PACKAGE_MANAGER = [ { label: 'npm', value: 'npm' }, { label: 'pnpm', value: 'pnpm' }, { label: 'yarn', value: 'yarn' }, ]; /** * 사용 가능한 TypeScript Express 프로젝트 템플릿 목록 * 각 템플릿은 특정 ORM/ODM과 데이터베이스 조합을 제공 * @type {Array<TemplateConfig>} * - name: 사용자 인터페이스에 표시되는 템플릿 이름 * - value: 내부적으로 사용되는 고유 식별자 (폴더명과 일치) * - desc: 사용자에게 보여지는 템플릿 설명 * - active: 템플릿 활성화 여부 (비활성 시 CLI에서 숨김) * - tags: 템플릿 특성을 나타내는 태그 배열 (검색, 필터링용) * - version: 템플릿 버전 (SemVer 형식) * - maintainer: 템플릿 유지보수 담당팀 * - lastUpdated: 마지막 업데이트 날짜 (YYYY-MM-DD 형식) * - devtoolsCompatibility: DevTools와의 호환성 비율 또는 상태 * - verificationStatus: 템플릿 검증 완료 상태 (complete|pending|failed) * - complexity: 사용 복잡도 수준 (beginner|intermediate|advanced) * - maturity: 템플릿 성숙도 (stable|beta|alpha|experimental) * - performanceRating: 성능 등급 (A|B|C|D) * - recommendedFor: 추천 사용 사례 목록 * - learningCurve: 학습 난이도 (easy|moderate|steep) * - enterpriseReady: 엔터프라이즈 환경 준비 완료 여부 */ export const TEMPLATES_VALUES = [ { name: 'Express TypeScript', value: 'default', desc: 'Basic Express + TypeScript starter', active: true, tags: ['express', 'typescript', 'starter', 'verified'], version: 'v2.0.0', maintainer: 'core', lastUpdated: '2026-02-23', devtoolsCompatibility: '100%', verificationStatus: 'complete', complexity: 'beginner', maturity: 'stable', performanceRating: 'A', recommendedFor: ['스타터', '프로토타입', '소규모 프로젝트'], learningCurve: 'easy', enterpriseReady: true, }, { /** Drizzle ORM + PostgreSQL 템플릿 */ name: 'Drizzle + PostgreSQL', value: 'drizzle-postgresql', desc: 'Modern SQL toolkit with type safety + full devtools', active: true, tags: ['orm', 'drizzle', 'postgresql', 'verified', 'enhanced'], version: 'v1.1.0', maintainer: 'core', lastUpdated: '2026-03-11', devtoolsCompatibility: '100%', verificationStatus: 'complete', complexity: 'intermediate', maturity: 'stable', performanceRating: 'A+', recommendedFor: ['중규모 프로젝트', '타입 안전성 중요', '성능 최적화', '코드 품질'], learningCurve: 'moderate', enterpriseReady: true, }, { /** Prisma ORM + PostgreSQL 템플릿 */ name: 'Prisma + PostgreSQL', value: 'prisma-postgresql', desc: 'Next-generation ORM for rapid development', active: false, tags: ['orm', 'prisma', 'postgresql', 'verified'], version: 'v7.4.1', maintainer: 'db-team', lastUpdated: '2026-02-23', devtoolsCompatibility: '100%', verificationStatus: 'complete', complexity: 'beginner', maturity: 'stable', performanceRating: 'A', recommendedFor: ['빠른 프로토타이핑', '대규모 프로젝트', '개발자 경험'], learningCurve: 'easy', enterpriseReady: true, }, /** * ==== [개발 중인 템플릿들 - DevTools 호환성 테스트 대기 중] ==== * 아래 템플릿들은 현재 개발 중이며 DevTools 호환성 테스트를 진행 중입니다. */ { /** Mongoose ODM + MongoDB 템플릿 (개발 중) */ name: 'Mongoose + MongoDB', value: 'mongoose-mongodb', desc: 'Traditional MongoDB ODM', active: false, tags: ['mongodb', 'odm', 'database', 'testing'], version: 'v7.x', maintainer: 'nosql-team', lastUpdated: '2026-02-23', devtoolsCompatibility: 'testing', verificationStatus: 'pending', complexity: 'intermediate', maturity: 'beta', performanceRating: 'B', recommendedFor: ['NoSQL 프로젝트', '문서 기반 데이터'], learningCurve: 'moderate', enterpriseReady: false, }, { /** Typegoose ODM + MongoDB 템플릿 (개발 중) */ name: 'Typegoose + MongoDB', value: 'typegoose-mongodb', desc: 'TypeScript-friendly MongoDB ODM', active: false, tags: ['mongodb', 'typegoose', 'odm', 'testing'], version: 'v11.x', maintainer: 'nosql-team', lastUpdated: '2026-02-23', devtoolsCompatibility: 'testing', verificationStatus: 'pending', complexity: 'intermediate', maturity: 'beta', performanceRating: 'B', recommendedFor: ['타입 안전한 NoSQL', '중규모 MongoDB 프로젝트'], learningCurve: 'moderate', enterpriseReady: false, }, { /** TypeORM + PostgreSQL 템플릿 (개발 중) */ name: 'TypeORM + PostgreSQL', value: 'typeorm-postgresql', desc: 'Decorator-based ORM', active: false, tags: ['orm', 'typeorm', 'postgresql', 'testing'], version: 'v0.3.x', maintainer: 'orm-team', lastUpdated: '2026-02-23', devtoolsCompatibility: 'testing', verificationStatus: 'pending', complexity: 'advanced', maturity: 'beta', performanceRating: 'B', recommendedFor: ['복잡한 데이터 모델', '엔터프라이즈 규모'], learningCurve: 'steep', enterpriseReady: false, }, { /** MikroORM + PostgreSQL 템플릿 (개발 중) */ name: 'MikroORM + PostgreSQL', value: 'mikro-orm-postgresql', desc: 'Data mapper pattern ORM', active: false, tags: ['orm', 'mikroorm', 'postgresql', 'testing'], version: 'v6.x', maintainer: 'orm-team', lastUpdated: '2026-02-23', devtoolsCompatibility: 'testing', verificationStatus: 'pending', complexity: 'advanced', maturity: 'beta', performanceRating: 'A', recommendedFor: ['고성능 요구사항', '복잡한 쿼리 최적화'], learningCurve: 'steep', enterpriseReady: false, }, { /** Sequelize ORM + PostgreSQL 템플릿 (개발 중) */ name: 'Sequelize + PostgreSQL', value: 'sequelize-postgresql', desc: 'Traditional SQL ORM', active: false, tags: ['orm', 'sequelize', 'postgresql', 'testing'], version: 'v6.x', maintainer: 'orm-team', lastUpdated: '2026-02-23', devtoolsCompatibility: 'testing', verificationStatus: 'pending', complexity: 'intermediate', maturity: 'beta', performanceRating: 'C', recommendedFor: ['기존 프로젝트 마이그레이션', 'SQL 친숙한 팀'], learningCurve: 'moderate', enterpriseReady: false, }, { /** Knex.js Query Builder + PostgreSQL 템플릿 (개발 중) */ name: 'Knex + PostgreSQL', value: 'knex-postgresql', desc: 'Flexible SQL query builder', active: false, tags: ['query-builder', 'knex', 'postgresql', 'testing'], version: 'v3.x', maintainer: 'db-team', lastUpdated: '2026-02-23', devtoolsCompatibility: 'testing', verificationStatus: 'pending', complexity: 'intermediate', maturity: 'beta', performanceRating: 'A', recommendedFor: ['SQL 직접 제어', '마이그레이션 중요'], learningCurve: 'moderate', enterpriseReady: false, }, { /** node-postgres (pg) + PostgreSQL 템플릿 (개발 중) */ name: 'Node-Postgres + PostgreSQL', value: 'node-postgres-postgresql', desc: 'Pure SQL with pg library', active: false, tags: ['postgresql', 'sql', 'raw', 'testing'], version: 'v8.x', maintainer: 'db-team', lastUpdated: '2026-02-23', devtoolsCompatibility: 'testing', verificationStatus: 'pending', complexity: 'advanced', maturity: 'beta', performanceRating: 'A', recommendedFor: ['최고 성능', 'SQL 전문가', '세밀한 제어'], learningCurve: 'steep', enterpriseReady: false, }, ]; /** * 사용 가능한 개발 도구 (DevTools) 목록 * 각 도구는 특정 카테고리에 속하며 템플릿과 조합하여 사용됨 * @type {Array<DevtoolConfig>} * - name: 사용자 인터페이스에 표시되는 도구 이름 * - value: 내부적으로 사용되는 고유 식별자 (폴더명과 일치) * - category: 도구 카테고리 (Linter, Compiler, Testing 등) * - files: 템플릿에 복사될 설정 파일 목록 * - pkgs: 일반 npm 의존성 패키지 목록 * - devPkgs: 개발용(devDependencies) npm 패키지 목록 * - scripts: package.json scripts에 추가될 명령어 매핑 * - desc: 도구 설명 * - postInstall: 패키지 설치 후 실행되는 후처리 함수 (선택적) */ export const DEVTOOLS_VALUES = [ /** == [Linter 카테고리] == */ { /** Biome - All-in-one 포맷터 겸 린터 */ name: 'Biome', value: 'biome', category: 'Linter', files: ['.biome.json', '.biomeignore'], pkgs: [], devPkgs: ['@biomejs/biome@2.4.6'], scripts: { lint: 'biome lint .', check: 'biome check .', format: 'biome format . --write', }, desc: 'All-in-one formatter and linter', }, { /** ESLint + Prettier 조합 린터 */ name: 'ESLint & Prettier', value: 'eslint', category: 'Linter', files: ['.prettierrc', 'eslint.config.cjs'], pkgs: [], devPkgs: [ 'eslint@^9.33.0', 'eslint-config-prettier@^10.1.1', 'globals@^15.10.0', 'prettier@3.6.2', 'typescript-eslint@8.57.0', ], scripts: { lint: 'eslint --ext .ts src/', 'lint:fix': 'npm run lint -- --fix', format: 'prettier --check .', 'format:fix': 'prettier --write .', }, desc: 'Separate formatter and linter setup', }, { /** Oxlint - Rust 기반 고성능 린터 */ name: 'Oxlint', value: 'oxlint', category: 'Linter', files: ['.oxlintrc.json', '.prettierrc'], pkgs: [], devPkgs: ['oxlint@^1.14.0', '@oxlint/migrate@^1.14.0', 'prettier@3.6.2'], scripts: { lint: 'oxlint .', 'lint:fix': 'oxlint . --fix', format: 'prettier --check .', 'format:fix': 'prettier --write .', }, desc: 'Ultra-fast Rust linter for JS/TS', }, /** == [Compiler 카테고리] == */ { /** tsup - esbuild 기반 빠른 번들러 */ name: 'tsup', value: 'tsup', category: 'Compiler', files: ['tsup.config.ts'], pkgs: [], devPkgs: ['tsup@8.5.0', '@swc/core@1.9.3'], scripts: { 'start:tsup': 'node -r tsconfig-paths/register dist/server.js', 'build:tsup': 'tsup --config tsup.config.ts', }, desc: 'Fast bundler for TypeScript', postInstall: (destDir) => { // tsup 선택 시 메인 build 명령어를 tsup으로 변경 const pkgPath = path.join(destDir, 'package.json'); const file = editJsonFile(pkgPath, { autosave: true }); // 기존 tsc 명령어를 보존하고 새로운 메인 build로 설정 const currentBuild = file.get('scripts.build') || 'tsc && tsc-alias'; file.set('scripts.build', 'tsup --config tsup.config.ts'); file.set('scripts.build:tsc', currentBuild); file.set('scripts.build:watch', 'tsup --watch'); file.save(); console.log(chalk.gray(' ❖ Main build command set to: tsup')); console.log(chalk.gray(' ❖ TypeScript fallback available: pnpm build:tsc')); }, }, { /** SWC - Rust 기반 TypeScript 컴파일러 */ name: 'SWC', value: 'swc', category: 'Compiler', files: ['.swcrc'], pkgs: [], devPkgs: ['@swc/cli@0.8.0', '@swc/core@1.9.3'], scripts: { 'start:swc': 'node dist/server.js', 'build:swc': 'swc src -d dist --strip-leading-paths --copy-files --delete-dir-on-start', }, desc: 'Rust-based TypeScript compiler', postInstall: (destDir) => { // SWC 선택 시 메인 build 명령어를 SWC로 변경 const pkgPath = path.join(destDir, 'package.json'); const file = editJsonFile(pkgPath, { autosave: true }); // 기존 tsc 명령어를 보존하고 새로운 메인 build로 설정 const currentBuild = file.get('scripts.build') || 'tsc && tsc-alias'; file.set( 'scripts.build', 'swc src -d dist --strip-leading-paths --copy-files --delete-dir-on-start', ); file.set('scripts.build:tsc', currentBuild); file.set('scripts.build:watch', 'swc src -d dist --watch'); file.save(); console.log(chalk.gray(' ❖ Main build command set to: SWC')); console.log(chalk.gray(' ❖ TypeScript fallback available: pnpm build:tsc')); }, }, /** == [Testing 카테고리] == */ { /** Jest - 업계 표준 테스트 프레임워크 */ name: 'Jest', value: 'jest', category: 'Testing', files: ['jest.config.ts', 'jest.unit.config.cjs', 'src/test', '.watchmanconfig'], pkgs: [], devPkgs: [ '@types/supertest@6.0.3', 'supertest@7.1.4', '@types/jest@30.0.0', 'jest@30.0.5', 'ts-jest@29.4.1', 'ts-node@10.9.2', ], scripts: { test: 'jest --config jest.config.ts --verbose --runInBand --no-coverage', 'test:e2e': 'jest --config jest.config.ts --testPathPatterns=e2e --verbose --runInBand', 'test:unit': 'jest --config jest.config.ts --testPathPatterns=unit --verbose --runInBand', }, postInstall: (projectPath) => { // Jest types를 tsconfig.json에 추가 const tsconfigPath = path.join(projectPath, 'tsconfig.json'); if (fs.existsSync(tsconfigPath)) { const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf8')); if (!tsconfig.compilerOptions.types) { tsconfig.compilerOptions.types = ['node']; } if (!tsconfig.compilerOptions.types.includes('jest')) { tsconfig.compilerOptions.types.push('jest'); } if (!tsconfig.exclude) { tsconfig.exclude = []; } if (!tsconfig.exclude.includes('**/unit_disabled/**')) { tsconfig.exclude.push('**/unit_disabled/**'); } fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2), 'utf8'); console.log('✅ Jest types and exclude patterns added to tsconfig.json'); } }, desc: 'Industry-standard test runner for Node.js', }, { /** Vitest - Vite 기반 현대적 테스트 러너 */ name: 'Vitest', value: 'vitest', category: 'Testing', files: ['vitest.config.ts', 'src/test'], pkgs: [], devPkgs: [ '@types/supertest@6.0.3', 'supertest@7.1.4', 'vite-tsconfig-paths@5.1.4', 'vitest@3.2.4', ], scripts: { test: 'vitest --run', 'test:watch': 'vitest', 'test:unit': 'vitest src/test/unit --run', 'test:e2e': 'vitest src/test/e2e --run', 'test:ci': 'vitest run --coverage', 'test:ci:unit': 'vitest run src/test/unit --coverage', 'test:ci:e2e': 'vitest run src/test/e2e --coverage', }, desc: 'Fast Vite-powered unit/e2e test framework', }, // == [API development] == // // { // name: 'Swagger', // value: 'swagger', // category: 'API development', // files: ['swagger.yaml'], // pkgs: ['swagger-jsdoc@^6.2.8', 'swagger-ui-express@^5.0.1'], // devPkgs: ['@types/swagger-jsdoc@^6.0.4', '@types/swagger-ui-express@^4.1.8'], // scripts: {}, // desc: 'Simplify your API development with our open-source and professional tools', // }, // == [Infrastructure] == // { name: 'Docker', value: 'docker', category: 'Infrastructure', files: [], // generateDockerFiles() 함수로 동적 처리 pkgs: [], devPkgs: [], scripts: { 'docker:dev': 'docker-compose -f docker-compose.yml up --build', 'docker:down': 'docker-compose down', 'docker:reset': 'docker-compose down -v && docker-compose up --build', 'docker:prod': 'docker build -f Dockerfile.prod -t ${npm_package_name}:latest .', }, desc: 'Containerized development and production environment', postInstall: null, // Docker 설정은 starter.js에서 별도 처리 }, // == [Git Tools] == // // { // name: 'Husky', // value: 'husky', // category: 'Git Tools', // files: ['.husky'], // pkgs: [], // devPkgs: ['husky'], // scripts: { prepare: 'husky install' }, // requires: [], // desc: 'Git hooks for automation', // }, // == [Deployment] == // // { // name: 'PM2', // value: 'pm2', // category: 'Deployment', // files: ['ecosystem.config.js'], // pkgs: ['pm2'], // devPkgs: [], // scripts: { // 'deploy:prod': 'pm2 start ecosystem.config.js --only prod', // 'deploy:dev': 'pm2 start ecosystem.config.js --only dev', // }, // desc: 'Process manager for Node.js', // }, // == [CI/CD] == // // { // name: 'GitHub Actions', // value: 'github', // category: 'CI/CD', // files: ['.github/workflows/ci.yml'], // pkgs: [], // devPkgs: [], // scripts: {}, // desc: 'CI/CD workflow automation', // }, ];