|
| 1 | +import * as prompt from "@clack/prompts"; |
| 2 | +import chalk from "chalk"; |
| 3 | +import { Command } from "commander"; |
| 4 | +import { execa } from "execa"; |
| 5 | +import { scaffold } from "./scaffold"; |
| 6 | + |
| 7 | +interface CliFlags { |
| 8 | + git: boolean; |
| 9 | + install: boolean; |
| 10 | + default: boolean; |
| 11 | +} |
| 12 | + |
| 13 | +interface CliResults { |
| 14 | + dir: string; |
| 15 | + flags: CliFlags; |
| 16 | +} |
| 17 | + |
| 18 | +const defaultOpts: CliResults = { |
| 19 | + dir: "proxy-app", |
| 20 | + flags: { |
| 21 | + git: false, |
| 22 | + install: false, |
| 23 | + default: false, |
| 24 | + }, |
| 25 | +}; |
| 26 | + |
| 27 | +async function project() { |
| 28 | + const cliResults = defaultOpts; |
| 29 | + const program = new Command(); |
| 30 | + program.name("Create Proxy"); |
| 31 | + program.description( |
| 32 | + "A CLI to easily get started with creating a Scramjet or Ultraviolet Proxy" |
| 33 | + ); |
| 34 | + program.argument( |
| 35 | + "[dir]", |
| 36 | + "The name of the program, and the directory to create" |
| 37 | + ); |
| 38 | + program.option("--git", "Tell the CLI to create a Git repository", false); |
| 39 | + program.option("--install", "Tell the CLI to install dependencies", false); |
| 40 | + program.option( |
| 41 | + "-y, --default", |
| 42 | + "Skip any questions a bootstrap with default options" |
| 43 | + ); |
| 44 | + program.parse(process.argv); |
| 45 | + const providedName = program.args[0]; |
| 46 | + if (providedName) { |
| 47 | + cliResults.dir = providedName; |
| 48 | + } |
| 49 | + cliResults.flags = program.opts(); |
| 50 | + if (cliResults.flags.default) { |
| 51 | + const defaultOptSpinner = prompt.spinner(); |
| 52 | + defaultOptSpinner.start(); |
| 53 | + defaultOptSpinner.message( |
| 54 | + chalk.yellow("Scaffolding using ALL default options") |
| 55 | + ); |
| 56 | + await scaffold({ |
| 57 | + projectName: providedName ?? "proxy-app", |
| 58 | + scaffoldType: "tsx/jsx", |
| 59 | + tsScaffold: true, |
| 60 | + }); |
| 61 | + defaultOptSpinner.stop(chalk.green.bold("Scaffold complete!")); |
| 62 | + return prompt.note( |
| 63 | + `cd ${providedName ?? "proxy-app"} \nnpm run dev`, |
| 64 | + chalk.bold.magenta("Done creating. Now run:") |
| 65 | + ); |
| 66 | + } |
| 67 | + if (process.env.TERM_PROGRAM?.toLowerCase().includes("mintty")) { |
| 68 | + console.log( |
| 69 | + chalk.yellow( |
| 70 | + "WARNING: It looks like you are using MinTTY which is not interactive. This is most likely because you are using Git Bash. \nIf you are using Git Bash, please use it from another terminal like Windows Terminal. " |
| 71 | + ) |
| 72 | + ); |
| 73 | + throw new Error("Terminal session is Non-Interactive"); |
| 74 | + } |
| 75 | + const inital = await prompt.group( |
| 76 | + { |
| 77 | + ...(!providedName && { |
| 78 | + path: () => |
| 79 | + prompt.text({ |
| 80 | + message: chalk.green( |
| 81 | + "Where would you like to create your project?" |
| 82 | + ), |
| 83 | + placeholder: "project-name", |
| 84 | + }), |
| 85 | + }), |
| 86 | + type: () => |
| 87 | + prompt.select({ |
| 88 | + message: chalk.magenta(`How would you like to set up this proxy?`), |
| 89 | + initialValue: "dedicated", |
| 90 | + maxItems: 2, |
| 91 | + options: [ |
| 92 | + { value: "dedicated", label: "Dedicated Server" }, |
| 93 | + { |
| 94 | + value: "static", |
| 95 | + label: |
| 96 | + "Static (can be deployed anywhere, but requires an external Wisp server)", |
| 97 | + }, |
| 98 | + ], |
| 99 | + }), |
| 100 | + }, |
| 101 | + { |
| 102 | + onCancel: () => { |
| 103 | + prompt.cancel(chalk.bold.red("Operation canceled")); |
| 104 | + process.exit(0); |
| 105 | + }, |
| 106 | + } |
| 107 | + ); |
| 108 | + |
| 109 | + const initGit = await prompt.group( |
| 110 | + { |
| 111 | + ...(!cliResults.flags.git && { |
| 112 | + init: () => |
| 113 | + prompt.confirm({ |
| 114 | + message: chalk.green("Do you want a Git repository initalized?"), |
| 115 | + initialValue: false, |
| 116 | + }), |
| 117 | + }), |
| 118 | + }, |
| 119 | + { |
| 120 | + onCancel: () => { |
| 121 | + prompt.cancel(chalk.bold.red("Operation canceled")); |
| 122 | + process.exit(0); |
| 123 | + }, |
| 124 | + } |
| 125 | + ); |
| 126 | + |
| 127 | + const installDeps = await prompt.group( |
| 128 | + { |
| 129 | + ...(!cliResults.flags.install && { |
| 130 | + install: () => |
| 131 | + prompt.confirm({ |
| 132 | + message: chalk.red("Do you want to install dependencies?"), |
| 133 | + initialValue: false, |
| 134 | + }), |
| 135 | + }), |
| 136 | + }, |
| 137 | + { |
| 138 | + onCancel: () => { |
| 139 | + prompt.cancel(chalk.bold.red("Operation canceled")); |
| 140 | + process.exit(0); |
| 141 | + }, |
| 142 | + } |
| 143 | + ); |
| 144 | + |
| 145 | + let packageManager = "npm"; |
| 146 | + if (installDeps.install === true || cliResults.flags.install === true) { |
| 147 | + const pm = await prompt.group( |
| 148 | + { |
| 149 | + manager: () => |
| 150 | + prompt.select({ |
| 151 | + message: chalk.green("Select your package manager"), |
| 152 | + initialValue: "npm", |
| 153 | + maxItems: 3, |
| 154 | + options: [ |
| 155 | + { value: "npm", label: "npm" }, |
| 156 | + { value: "pnpm", label: "pnpm" }, |
| 157 | + { value: "yarn", label: "yarn" }, |
| 158 | + { value: "bun", label: "bun" }, |
| 159 | + ], |
| 160 | + }), |
| 161 | + }, |
| 162 | + { |
| 163 | + onCancel: () => { |
| 164 | + prompt.cancel(chalk.bold.red("Operation canceled")); |
| 165 | + process.exit(0); |
| 166 | + }, |
| 167 | + } |
| 168 | + ); |
| 169 | + packageManager = pm.manager; |
| 170 | + } |
| 171 | + |
| 172 | + const scaffoldSpinner = prompt.spinner(); |
| 173 | + scaffoldSpinner.start(); |
| 174 | + scaffoldSpinner.message(chalk.yellow("Scaffolding...")); |
| 175 | + await scaffold({ |
| 176 | + projectName: inital.path ?? cliResults.dir, |
| 177 | + scaffoldType: inital.type, |
| 178 | + }); |
| 179 | + scaffoldSpinner.stop(chalk.bold.green("Scaffold complete!")); |
| 180 | + if (initGit.init === true || cliResults.flags.git === true) { |
| 181 | + const gitSpinner = prompt.spinner(); |
| 182 | + gitSpinner.start(); |
| 183 | + gitSpinner.message(chalk.yellow("Initalizing a Git repo")); |
| 184 | + try { |
| 185 | + await execa("git", ["init"], { cwd: inital.path }); |
| 186 | + await execa("git", ["add", "-A"], { cwd: inital.path }); |
| 187 | + await execa( |
| 188 | + "git", |
| 189 | + [ |
| 190 | + "commit", |
| 191 | + "-m", |
| 192 | + "Inital Commit from Create Proxy App", |
| 193 | + '--author="create-proxy-app[bot] <[email protected]>"', |
| 194 | + ], |
| 195 | + { cwd: inital.path } |
| 196 | + ); |
| 197 | + } catch (err: any) {} |
| 198 | + gitSpinner.stop(chalk.bold.green("Git repo successfully intitalized!")); |
| 199 | + } |
| 200 | + if (installDeps.install === true || cliResults.flags.install === true) { |
| 201 | + const pmSpinner = prompt.spinner(); |
| 202 | + pmSpinner.start(); |
| 203 | + pmSpinner.message(chalk.yellow("Installing dependencies...")); |
| 204 | + try { |
| 205 | + await execa(packageManager, ["install"], { cwd: inital.path }); |
| 206 | + } catch (err: any) { |
| 207 | + console.log( |
| 208 | + chalk.yellow.bold( |
| 209 | + `\n${packageManager} has failed to install dependencies. Defaulting to npm` |
| 210 | + ) |
| 211 | + ); |
| 212 | + packageManager = "npm"; |
| 213 | + await execa("npm", ["install"], { cwd: inital.path }); |
| 214 | + } |
| 215 | + pmSpinner.stop(chalk.bold.green("Dependencies installed!")); |
| 216 | + } |
| 217 | + switch (installDeps.install || cliResults.flags.install) { |
| 218 | + case true: |
| 219 | + prompt.note( |
| 220 | + `cd ${inital.path ?? providedName} \n${packageManager} run dev`, |
| 221 | + chalk.bold.magenta("Done creating. Now run:") |
| 222 | + ); |
| 223 | + break; |
| 224 | + case false: |
| 225 | + prompt.note( |
| 226 | + `cd ${ |
| 227 | + inital.path ?? providedName |
| 228 | + } \n${packageManager} install \n${packageManager} run dev`, |
| 229 | + chalk.bold.magenta("Done creating. Now run:") |
| 230 | + ); |
| 231 | + break; |
| 232 | + } |
| 233 | + if (inital.type === "basic") { |
| 234 | + const spinner = prompt.spinner(); |
| 235 | + spinner.start(); |
| 236 | + spinner.message(chalk.yellow("Scaffolding project...")); |
| 237 | + await scaffold({ |
| 238 | + projectName: inital.path ?? providedName, |
| 239 | + scaffoldType: inital.type, |
| 240 | + }); |
| 241 | + spinner.stop(chalk.bold.green("Scaffold complete!")); |
| 242 | + prompt.note( |
| 243 | + `cd ${inital.path} \nAnd get to work!`, |
| 244 | + chalk.bold.magenta("Done. Now Do:") |
| 245 | + ); |
| 246 | + } |
| 247 | +} |
| 248 | + |
| 249 | +async function cli() { |
| 250 | + prompt.intro( |
| 251 | + chalk.magenta("Welcome to Create Proxy App CLI! Let's get started") |
| 252 | + ); |
| 253 | + await project(); |
| 254 | +} |
| 255 | + |
| 256 | +export { cli }; |
0 commit comments