Files
Shade/packages/shade-cli/src/commands/init.ts

84 lines
2.4 KiB
TypeScript
Raw Normal View History

import { existsSync, mkdirSync, writeFileSync, readdirSync, statSync, readFileSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import { doctorCommand } from './doctor.js';
const here = dirname(fileURLToPath(import.meta.url));
const TEMPLATES_DIR = join(here, '..', '..', 'templates');
export interface InitOptions {
name?: string;
template?: string;
prekeyServer?: string;
cwd?: string;
runDoctor?: boolean;
}
export async function initCommand(opts: InitOptions = {}): Promise<void> {
const name = opts.name ?? 'my-shade-app';
const template = opts.template ?? 'bun-server';
const cwd = opts.cwd ?? process.cwd();
const target = join(cwd, name);
if (existsSync(target)) {
throw new Error(`Target directory "${target}" already exists`);
}
const templateDir = join(TEMPLATES_DIR, template);
if (!existsSync(templateDir)) {
const available = listTemplates();
throw new Error(
`Template "${template}" not found. Available: ${available.join(', ')}`,
);
}
// Recursive copy with placeholder substitution
mkdirSync(target, { recursive: true });
copyRecursive(templateDir, target, {
__PROJECT_NAME__: name,
__PREKEY_SERVER__: opts.prekeyServer ?? 'http://localhost:3900',
});
console.log(`✓ Created ${name} from template "${template}"`);
console.log('');
console.log(` cd ${name}`);
console.log(' bun install');
console.log(' bun run start');
if (opts.runDoctor) {
console.log('');
await doctorCommand({ cwd: target });
}
}
export function listTemplates(): string[] {
if (!existsSync(TEMPLATES_DIR)) return [];
return readdirSync(TEMPLATES_DIR).filter((name) => {
return statSync(join(TEMPLATES_DIR, name)).isDirectory();
});
}
function copyRecursive(
source: string,
dest: string,
replacements: Record<string, string>,
): void {
mkdirSync(dest, { recursive: true });
for (const entry of readdirSync(source)) {
const srcPath = join(source, entry);
const destPath = join(dest, entry);
const st = statSync(srcPath);
if (st.isDirectory()) {
copyRecursive(srcPath, destPath, replacements);
} else {
const content = readFileSync(srcPath, 'utf-8');
const substituted = Object.entries(replacements).reduce(
(acc, [key, value]) => acc.replaceAll(key, value),
content,
);
writeFileSync(destPath, substituted);
}
}
}