node-ts-scaffold
Version:
CLI tool to scaffold TypeScript projects with ESLint and Prettier
154 lines (136 loc) • 5.67 kB
text/typescript
// src/index.ts - Main CLI entry point
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
import { exec } from 'child_process';
import prompts from 'prompts';
import chalk from 'chalk';
import ora from 'ora';
import { createPackageJson, createTsConfig, createEslintConfig, createPrettierConfig, createGitignore, createSrcIndex, createTestFile, createVitestConfig } from './template.js'
// Get current directory
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
async function executeCommand(command: string, cwd: string): Promise<void> {
return new Promise((resolve, reject) => {
exec(command, { cwd }, (error, stdout, stderr) => {
if (error) {
console.error(chalk.red(`Error: ${error.message}`));
reject(error);
return;
}
if (stderr) {
console.error(chalk.yellow(`Warning: ${stderr}`));
}
resolve();
});
});
}
async function ensureDirectoryExists(dirPath: string): Promise<void> {
try {
await fs.mkdir(dirPath, { recursive: true });
} catch (error) {
console.error(chalk.red(`Failed to create directory: ${dirPath}`));
throw error;
}
}
async function createFile(filePath: string, content: string): Promise<void> {
try {
await fs.writeFile(filePath, content);
} catch (error) {
console.error(chalk.red(`Failed to write file: ${filePath}`));
throw error;
}
}
async function scaffold(): Promise<void> {
try {
// Get project details
const response = await prompts([
{
type: 'text',
name: 'projectName',
message: 'What is the name of your project?',
initial: 'my-typescript-project'
},
{
type: 'text',
name: 'description',
message: 'Enter a brief description:',
initial: 'A TypeScript project'
},
{
type: 'text',
name: 'author',
message: 'Enter author name:',
initial: ''
},
{
type: 'confirm',
name: 'installDeps',
message: 'Install dependencies after scaffolding?',
initial: true
}
]);
if (!response.projectName) {
console.error(chalk.red('Project name is required.'));
process.exit(1);
}
const { projectName, description, author, installDeps } = response;
const projectPath = path.join(process.cwd(), projectName);
// Check if directory already exists
try {
await fs.access(projectPath);
console.error(chalk.red(`Directory ${projectName} already exists.`));
process.exit(1);
} catch (error) {
// Directory doesn't exist, which is what we want
}
// Create project directory
const spinner = ora('Creating project scaffold...').start();
await ensureDirectoryExists(projectPath);
await ensureDirectoryExists(path.join(projectPath, 'src'));
await ensureDirectoryExists(path.join(projectPath, 'test'));
await ensureDirectoryExists(path.join(projectPath, 'build'));
// Create config files
await createFile(
path.join(projectPath, 'package.json'),
createPackageJson({ name: projectName, description, author })
);
await createFile(path.join(projectPath, 'tsconfig.json'), createTsConfig());
await createFile(path.join(projectPath, 'eslint.config.js'), createEslintConfig());
await createFile(path.join(projectPath, '.prettierrc'), createPrettierConfig());
await createFile(path.join(projectPath, '.gitignore'), createGitignore());
await createFile(path.join(projectPath, 'vitest.config.ts'), createVitestConfig());
// Create source files
await createFile(path.join(projectPath, 'src', 'index.ts'), createSrcIndex());
await createFile(path.join(projectPath, 'test', 'index.test.ts'), createTestFile());
spinner.succeed(chalk.green(`Project scaffold created at ${projectName}/`));
// Install dependencies if requested
if (installDeps) {
spinner.text = 'Installing dependencies...';
spinner.start();
try {
await executeCommand('npm install', projectPath);
spinner.succeed(chalk.green('Dependencies installed successfully!'));
} catch (error) {
spinner.fail(chalk.red('Failed to install dependencies.'));
console.error(chalk.red('You can install them manually by running `npm install` in the project directory.'));
}
}
// Final instructions
console.log(chalk.cyan('\nSetup complete! 🎉'));
console.log(chalk.white(`\nNext steps:`));
console.log(chalk.white(` 1. cd ${projectName}`));
if (!installDeps) {
console.log(chalk.white(` 2. npm install`));
}
console.log(chalk.white(` 3. npm run dev # To start development`));
console.log(chalk.white(` 4. npm test # To run tests`));
console.log(chalk.white(` 5. npm run build # To build the project`));
} catch (error) {
console.error(chalk.red('Failed to scaffold project:'), error);
process.exit(1);
}
}
// Run the scaffolding process
scaffold();