UNPKG

ts-node-app

Version:

CLI para geração de componentes em arquiteturas DDD, hexagonal ou Clean Architecture ...

233 lines (205 loc) 7.69 kB
import { prompts, settings } from "./constants.js"; import { Logger, styled } from "./logger.js"; export class Installers { /** * @param {FileManager} fileManager * @param {Prompt} prompt */ constructor(fileManager, prompt) { this.prompt = prompt; this.fileManager = fileManager; this.logger = new Logger(Installers.name); } async init() { const nodeVersion = this.prompt.spawn("node", ["--version"]); this.logger.alert(`Node version: ${nodeVersion}`); if (!this.fileManager.isFile("package.json")) { this.logger.info("Init Node project..."); console.log(); this.prompt.spawn("npm", this.install.init(), { stdio: "inherit" }); } if (await this.prompt.confirm(prompts.tsInstall)) { await this.prompt.delay(355); await this.typescript(nodeVersion); } if (await this.prompt.confirm(prompts.eslintInstall)) { await this.prompt.delay(355); await this.eslint(); } if (await this.prompt.confirm(prompts.defaultConfig)) { await this.prompt.delay(355); await this.defaultConfig(); } this.logger.info("Project initialized successfully!"); } /** * @param {string} nodeVersion */ async applyPackageJson(nodeVersion) { const pkg = this.fileManager.readJsonFile("package.json", { scripts: {}, name: "", main: "", engines: {} }); this.logger.debug("Current package.json:", pkg.data); pkg.set("main", "dist/main.js"); pkg.set("engines", { node: nodeVersion.replace("v", ">=") }); pkg.set("scripts", { ...pkg.data.scripts, ...settings.scripts, }); pkg.save(); this.fileManager.makeFileIfNotExists(".nvmrc", nodeVersion); this.logger.info("Package.json updated successfully!"); // create readme if (!this.fileManager.exists("README.md")) { const readme = this.fileManager.readTextFile(this.fileManager.dirname + "/defaults/readme"); readme.set("{app_name}", pkg.data.name); readme.set("{node_version}", nodeVersion); this.fileManager.writeTextFile("README.md", readme.content); this.logger.info("Readme created successfully!"); } } async defaultConfig() { this.fileManager.makeJsonFileIfNotExists(".prettierrc", settings.prettier); this.fileManager.makeFileIfNotExists(".gitignore", settings.gitignore); this.fileManager.cpFromPackageToRepo("/defaults/jest.config.js", "jest.config.js"); this.fileManager.cpFromPackageToRepo("/defaults/.dockerignore", ".dockerignore"); this.fileManager.cpFromPackageToRepo("/defaults/Dockerfile", "Dockerfile"); this.fileManager.cpFromPackageToRepo("/defaults/docker-compose.yml", "docker-compose.yml"); for (const s of settings.stages) { if (!this.fileManager.isFile(`.env.${s}`)) { this.logger.info(`Creating .env.${s}....`); this.fileManager.writeTextFile(`.env.${s}`, `APPLICATION_NAME=myApp\nNODE_ENV=${s}\n`); } } } async eslint() { this.logger.info("Creating eslint.config.mjs..."); this.prompt.spawn("npm", this.install.dev(settings.eslintLibs), { stdio: "inherit", }); if (!this.fileManager.exists(".vscode")) { this.logger.info("Creating dir '.vscode'..."); this.fileManager.mkdir(".vscode"); } const currentSettings = this.fileManager.readJsonFile("./.vscode/settings.json", {}); this.logger.debug("Current settings.json:", currentSettings.data); this.fileManager.writeJsonFile(".vscode/settings.json", { ...settings.editorSettings, ...currentSettings.data, }); /** * @todo let dinamic copy */ this.fileManager.cpFromPackageToRepo("/defaults/eslint.config.hex.mjs", "eslint.config.mjs"); this.logger.info("Eslint installed successfully!"); } /** * @param {*} nodeVersion */ async typescript(nodeVersion) { const { compilerOptions, tsLibs } = settings; this.logger.info(`Installing ${tsLibs}...`); this.prompt.spawn("npm", this.install.dev(tsLibs), { stdio: "inherit", }); if (!this.fileManager.exists("tsconfig.json")) { this.logger.info("Creating tsconfig.json..."); this.prompt.spawn("npx", ["tsc", "--init"], { stdio: "inherit", }); } const currentTsConfig = this.fileManager.readJsonFile("tsconfig.json", { compilerOptions: {} }); this.logger.debug("Current tsConfig:", currentTsConfig.data); console.log("\n\rAdding tsconfig.json paths...\n"); for (const [key, value] of Object.entries(compilerOptions)) { console.log(`${key}:`, value); } console.log("\n"); currentTsConfig.set("compilerOptions", { ...currentTsConfig.get("compilerOptions"), ...compilerOptions, }); currentTsConfig.save(); await this.applyPackageJson(nodeVersion); this.logger.info("TypeScript installed successfully!"); } /** * * @param {string} framework */ async installFramework(framework) { this.logger.info(`Installing ${framework}...`); const copies = this.copyExampleFiles(); switch (framework) { case "Express": this.prompt.spawn("npm", this.install.dev(["@types/express"]), { stdio: "inherit", }); this.prompt.spawn("npm", this.install.save(["express"]), { stdio: "inherit", }); // clean with presentation if (copies.includes("ExpressApp.ts")) this.fileManager.cpFromPackageToRepo("/defaults/examples/main.wpresentation.ts", "./src/main.ts"); // hexagonal adapter if (copies.includes("ExpressAdapter.ts")) this.fileManager.cpFromPackageToRepo("/defaults/examples/main.wadapter.ts", "./src/main.ts"); // single ddd if (copies.includes("ExpressServer.ts")) this.fileManager.cpFromPackageToRepo("/defaults/examples/main.wddd.ts", "./src/main.ts"); // mvc or clean without presentation if (copies.includes("app.config.ts")) this.fileManager.cpFromPackageToRepo("/defaults/examples/main.wclean.ts", "./src/main.ts"); // e2e test if (!this.fileManager.isFile("./tests/app-e2e.spec.ts")) { this.fileManager.cpFromPackageToRepo("/defaults/examples/app-e2e.spec.ts", "tests/app-e2e.spec.ts", { recursive: true, }); } break; default: this.logger.error("Invalid framework:", framework); break; } } copyExampleFiles() { if (this.fileManager.exists("src")) { const copies = []; const path = this.fileManager.dirname + "/defaults/examples"; const exampleFiles = this.fileManager.readdir(path, { recursive: true, }); for (const dir of this.fileManager.readdir("src", { recursive: true })) { const filename = exampleFiles.find((e) => dir.endsWith(e)); if (!filename) continue; copies.push(filename); this.logger.info(`Copying example file: ${styled("white", "src/" + dir)}`); this.fileManager.cpFromPackageToRepo(`/defaults/examples/${filename}`, `src/${dir}`); } return copies; } } install = { init: () => { const args = ["init", "-y"]; // if (this.prompt.yesToAll) args.push("-y"); return args; }, /** * @param {string[]} libs */ save: (libs) => { return ["install", "--save", ...libs]; // --save is default but it's good to be explicit here }, /** * @param {string[]} libs */ dev: (libs) => { return ["install", "--save-dev", ...libs]; }, }; } /** * @typedef {import("./fileManager.js").FileManager} FileManager * @typedef {import("./prompt.js").Prompt} Prompt */