create-vhs
Version:
Create a VHS monorepo with one command.
147 lines • 5.06 kB
JavaScript
import path from "node:path";
import { fileURLToPath } from "node:url";
import chalk from "chalk";
import degit from "degit";
import { execa } from "execa";
import fs from "fs-extra";
import ora from "ora";
import { createGitIgnore, replaceTemplateVariables, updatePackageJson, updateTsConfig, } from "./utils.js";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export async function createProject(projectName, options) {
const projectPath = path.resolve(process.cwd(), projectName);
// Check if directory exists
if (await fs.pathExists(projectPath)) {
throw new Error(`Directory ${projectName} already exists`);
}
const steps = [
{
text: "Creating project directory...",
action: async () => {
await fs.ensureDir(projectPath);
},
successText: "Project directory created",
},
{
text: "Setting up template...",
action: async () => {
await setupTemplate(projectPath, options);
},
successText: "Template setup complete",
},
{
text: "Processing template files...",
action: async () => {
await processTemplateFiles(projectPath, projectName, options);
},
successText: "Template files processed",
},
];
if (!options.skipInstall) {
steps.push({
text: `Installing dependencies with ${options.packageManager}...`,
action: async () => {
await installDependencies(projectPath, options.packageManager);
},
successText: "Dependencies installed",
});
}
steps.push({
text: "Initializing git repository...",
action: async () => {
await initializeGit(projectPath);
},
successText: "Git repository initialized",
});
// Execute steps with spinners
for (const step of steps) {
const spinner = ora(step.text).start();
try {
await step.action();
spinner.succeed(step.successText || step.text);
}
catch (error) {
spinner.fail(step.failText || `Failed: ${step.text}`);
// Cleanup on failure
await fs.remove(projectPath);
throw error;
}
}
}
async function setupTemplate(projectPath, options) {
const templateSource = getTemplateSource(options.template);
if (templateSource.startsWith("http") || templateSource.includes("/")) {
// Remote template (GitHub repo)
const emitter = degit(templateSource, {
cache: false,
force: true,
verbose: true,
});
await emitter.clone(projectPath);
}
else {
// Local template
const templatePath = path.join(__dirname, "..", "templates", templateSource);
if (await fs.pathExists(templatePath)) {
await fs.copy(templatePath, projectPath);
}
else {
throw new Error(`Template not found: ${templateSource}`);
}
}
}
async function processTemplateFiles(projectPath, projectName, options) {
const templateVars = {
PROJECT_NAME: projectName,
PACKAGE_MANAGER: options.packageManager,
TEMPLATE_TYPE: options.template,
};
// Update package.json
await updatePackageJson(projectPath, projectName, options);
await updateTsConfig(projectPath, options);
await createGitIgnore(projectPath, options);
// Process template variables in files
const filesToProcess = [
"README.md",
"package.json",
"apps/*/package.json",
"packages/*/package.json",
];
for (const pattern of filesToProcess) {
await replaceTemplateVariables(projectPath, pattern, templateVars);
}
}
async function installDependencies(projectPath, packageManager) {
const commands = {
bun: ["bun", ["install"]],
npm: ["npm", ["install"]],
yarn: ["yarn", []],
pnpm: ["pnpm", ["install"]],
};
const [cmd, args] = commands[packageManager] || ["bun", ["install"]]; // Default to npm if not found
await execa(cmd, args, {
cwd: projectPath,
stdio: "pipe",
});
}
async function initializeGit(projectPath) {
try {
await execa("git", ["init"], { cwd: projectPath });
await execa("git", ["add", "."], { cwd: projectPath });
await execa("git", ["commit", "-m", "feat: initial commit"], {
cwd: projectPath,
});
}
catch (error) {
// Git initialization is optional
console.warn(chalk.yellow("⚠️ Warning: Could not initialize git repository"));
}
}
function getTemplateSource(template) {
// Map template names to GitHub repos or local paths
const templateMap = {
basic: "https://github.com/0xZ0uk/vhs.git",
pro: "https://github.com/0xZ0uk/vhs.git",
};
return templateMap[template] || template;
}
//# sourceMappingURL=installer.js.map