diff --git a/package.json b/package.json index 867f54a..7fbd2a2 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,8 @@ "husky": "^8.0.3", "prettier": "^2.8.4", "release-it": "^16.1.5", - "rimraf": "^4.1.2", + "rimraf": "^5.0.5", + "shx": "^0.3.4", "ts-node-dev": "^2.0.0", "typescript": "^4.9.5", "vite": "^4.4.9", diff --git a/src/cli.ts b/src/cli.ts index 4e61925..cfaf9eb 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -2,6 +2,7 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; +import { runCommandModule } from "./commands/project.commands"; import { generateProject } from "./generate"; import { infoProject } from "./info"; import { createProject } from "./new"; @@ -13,6 +14,7 @@ console.log(`\n[🐎 Expressots]\n`); yargs(hideBin(process.argv)) .scriptName("expressots") + .command(runCommandModule) .command(createProject()) .command(generateProviders()) .command(generateProject()) diff --git a/src/commands/project.commands.ts b/src/commands/project.commands.ts new file mode 100644 index 0000000..c580743 --- /dev/null +++ b/src/commands/project.commands.ts @@ -0,0 +1,145 @@ +import { spawn } from "child_process"; +import { promises as fs } from "fs"; +import path from "path"; +import { Argv, CommandModule } from "yargs"; +import Compiler from "../utils/compiler"; + +/** + * Load the configuration from the compiler + * @param compiler The compiler to load the configuration from + * @returns The configuration + */ + +const opinionatedConfig: Array = [ + "--transpile-only", + "-r", + "dotenv/config", + "-r", + "tsconfig-paths/register", + "./src/main.ts", +]; + +const nonOpinionatedConfig: Array = [ + "--transpile-only", + "-r", + "dotenv/config", + "./src/main.ts", +]; + +/** + * Helper function to execute a command + * @param command The command to execute + * @param args The arguments to pass to the command + * @param cwd The current working directory to execute the command in + * @returns A promise that resolves when the command completes successfully + */ +function execCmd( + command: string, + args: Array, + cwd: string = process.cwd(), +): Promise { + return new Promise((resolve, reject) => { + const proc = spawn(command, args, { + stdio: "inherit", + shell: true, + cwd, + }); + + proc.on("close", (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`Command failed with code ${code}`)); + } + }); + }); +} + +// Helper to delete the dist directory +const cleanDist = async (): Promise => { + await fs.rm("./dist", { recursive: true, force: true }); +}; + +// Helper to compile TypeScript +const compileTypescript = async () => { + await execCmd("npx", ["tsc", "-p", "tsconfig.build.json"]); +}; + +// Helper to copy files +const copyFiles = async () => { + const { opinionated } = await Compiler.loadConfig(); + let filesToCopy: Array = []; + if (opinionated) { + filesToCopy = [ + "./register-path.js", + "tsconfig.build.json", + "package.json", + ]; + } else { + filesToCopy = ["tsconfig.json", "package.json"]; + } + filesToCopy.forEach((file) => { + fs.copyFile(file, path.join("./dist", path.basename(file))); + }); +}; + +// eslint-disable-next-line @typescript-eslint/ban-types +export const runCommandModule: CommandModule<{}, { command: string }> = { + command: "run ", + describe: "Runs a specified command (dev, build, prod)", + builder: (yargs: Argv) => { + return yargs.positional("command", { + describe: "The command to run", + type: "string", + choices: ["dev", "build", "prod"], + }); + }, + handler: async (argv) => { + const { command } = argv; + // Now call your original runCommand function with the command + // Ensure runCommand is properly defined to handle these commands + await runCommand({ command }); + }, +}; + +const runCommand = async ({ command }: { command: string }): Promise => { + const { opinionated } = await Compiler.loadConfig(); + try { + switch (command) { + case "dev": + // Use execSync or spawn to run ts-node-dev programmatically + execCmd( + "tsnd", + opinionated ? opinionatedConfig : nonOpinionatedConfig, + ); + break; + case "build": + await cleanDist(); + await compileTypescript(); + await copyFiles(); + break; + case "prod": + let config: Array = []; + if (opinionated) { + config = [ + "-r", + "dotenv/config", + "-r", + "./dist/register-path.js", + "./dist/src/main.js", + ]; + } else { + config = ["-r", "dotenv/config", "./dist/main.js"]; + } + // Ensure environment variables are set + execCmd("node", config); + break; + default: + console.log(`Unknown command: ${command}`); + } + } catch (error) { + console.error("Error executing command:", error); + } +}; + +export { runCommand };