A CLI for scaffolding ATProto web applications

eh

besaid.zone 803842c0 f1f953db

verified
+38 -9
+38 -9
src/commands/create.ts
··· 11 11 select, 12 12 confirm, 13 13 spinner, 14 + log, 14 15 isCancel, 15 16 cancel as c, 16 17 } from "@clack/prompts"; 17 - import { exec } from "node:child_process"; 18 18 import { 19 19 copyFileSync, 20 20 existsSync, 21 21 mkdirSync, 22 22 readdirSync, 23 + rmSync, 23 24 statSync, 24 25 } from "node:fs"; 25 26 import { join, resolve } from "node:path"; ··· 31 32 dependencies, 32 33 } from "../../package.json" with { type: "json" }; 33 34 import { FRAMEWORKS } from "../constants.js"; 35 + import { exec, execSync } from "node:child_process"; 34 36 35 37 const DEFAULT_PROJECT_NAME = "my-atproto-app"; 36 38 ··· 157 159 variant, 158 160 ); 159 161 160 - exec( 161 - `npx create-vite@${dependencies["create-vite"]} ${projectName} --no-interactive --template ${variant} --overwrite ${shouldOverwrite ? "true" : "false"}`, 162 - ); 162 + const templateCommand = `npm create --loglevel=silent vite@${dependencies["create-vite"]} ${projectName} -- --template ${variant} --no-interactive --overwrite ${shouldOverwrite ? "true" : "false"}`; 163 + 164 + log.info(pc.gray(`Invoking create-vite for template creation...`)); 165 + 166 + execSync(templateCommand); 167 + 168 + removeViteTemplateFiles(root, removableTemplateFiles(variant)); 169 + 170 + for (const file of readdirSync(templateDir)) { 171 + const sourceTemplateFiles = resolve(templateDir, file); 172 + const destinationTemplateFile = resolve(root, file); 173 + copy(sourceTemplateFiles, destinationTemplateFile); 174 + } 163 175 164 176 try { 165 177 s.stop("Project created!"); ··· 191 203 } 192 204 } 193 205 194 - function formatTargetDir(targetDir: string) { 195 - return targetDir 196 - .trim() 197 - .replace(/[<>:"\\|?*]/g, "") 198 - .replace(/\/+$/g, ""); 206 + function removeViteTemplateFiles(dir: string, files: string[]) { 207 + // files will be replaced by atproto specific template files 208 + for (const file of readdirSync(dir)) { 209 + const pathToFile = resolve(dir, file); 210 + const stat = statSync(pathToFile); 211 + if (files.includes(file)) { 212 + if (stat.isDirectory()) { 213 + rmSync(pathToFile, { recursive: true, force: true }); 214 + } else { 215 + rmSync(pathToFile); 216 + } 217 + } 218 + } 219 + } 220 + 221 + export function removableTemplateFiles(templateName: string) { 222 + switch (templateName) { 223 + case "react-ts": 224 + return ["README.md", "eslint.config.js", "public", "src", "package.json"]; 225 + default: 226 + return []; 227 + } 199 228 }