UNPKG

@avleon/cli

Version:

> **🚧 This project is in active development.** > > It is **not stable** and **not ready** for live environments. > Use **only for testing, experimentation, or internal evaluation**. > > ####❗ Risks of using this in production: > > - 🔄 Breaking

319 lines (301 loc) 10.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createApplication = createApplication; const fs_extra_1 = __importDefault(require("fs-extra")); const paths_1 = require("./paths"); const prettier = __importStar(require("prettier")); const path_1 = __importDefault(require("path")); const os_1 = __importDefault(require("os")); const inquirer_1 = __importDefault(require("inquirer")); const child_process_1 = require("child_process"); const util_1 = __importDefault(require("util")); const lodash_1 = require("lodash"); const execAsync = util_1.default.promisify(child_process_1.exec); const getShell = () => { if (os_1.default.platform() === 'win32') { return process.env.ComSpec || 'cmd.exe'; // Windows fallback } return process.env.SHELL || '/bin/sh'; // macOS/Linux fallback }; async function askForPackageManager() { const { packageManager } = await inquirer_1.default.prompt([ { type: 'list', name: 'packageManager', message: 'Which package manager do you want to use?', choices: ['npm', 'yarn', 'pnpm'], default: 'npm' } ]); return packageManager; } async function installDependencies(pm, fname) { return new Promise((resolve, reject) => { const child = (0, child_process_1.spawn)(pm, ['install'], { cwd: fname, shell: getShell(), stdio: 'inherit', }); child.on('exit', (code) => { if (code === 0) { console.log('✅ Dependencies installed successfully.'); console.log(`cd ${fname}`); console.log(pm == 'npm' ? `npm run start:dev` : `${pm} start:dev`); resolve(); } else { console.error(`❌ Installation failed with exit code ${code}`); reject(new Error(`Install failed with code ${code}`)); } }); child.on('error', (err) => { console.error('❌ Failed to start install process:', err); reject(err); }); }); } async function createApplication(fname, flags = {}) { let appPaths = (0, paths_1.appPaths)(fname); const pm = await askForPackageManager(); // const dirs = Object.values(appPaths); // for (let i = 0; i < dirs.length; i++) { // await fs.ensureDir(dirs[i]); // } await fs_extra_1.default.ensureDir(appPaths.root + "/src"); await fs_extra_1.default.ensureDir(appPaths.root + "/src/controllers"); await fs_extra_1.default.ensureDir(appPaths.root + "/src/config"); await fs_extra_1.default.ensureDir(appPaths.root + "/src/services"); await fs_extra_1.default.ensureDir(appPaths.root + "/src/models"); await fs_extra_1.default.ensureDir(appPaths.root + "/test"); await fs_extra_1.default.ensureDir(appPaths.root + "/public"); // copy // home controller const homeService = ` import { AppService } from '@avleon/core'; @AppService export class HomeService{ sayHello(){ return "Hello World!"; } } `; const formatHomeService = await prettier.format(homeService, { singleQuote: true, singleAttributePerLine: true, parser: "typescript", }); await fs_extra_1.default.writeFile(path_1.default.join(appPaths.services, "home.service.ts"), formatHomeService); // home controller const homeContrlelr = ` import { ApiController, Get } from '@avleon/core'; import { HomeService } from '../services/home.service'; @ApiController export class HomeController{ constructor( private readonly homeService: HomeService ){} @Get() sayHello(){ return this.homeService.sayHello(); } } `; const formatHomeController = await prettier.format(homeContrlelr, { singleQuote: true, singleAttributePerLine: true, parser: "typescript", }); await fs_extra_1.default.writeFile(path_1.default.join(appPaths.controllers, "home.controller.ts"), formatHomeController); // openapi config file const openapiConfigFile = ` import { AppConfig, Environment, IConfig } from "@avleon/core"; @AppConfig export class OpenApiConfig implements IConfig { config(env: Environment) { return { info: { title: '${(0, lodash_1.capitalize)(fname)}', version: '0.0.1', }, } } } `; const formatConfigFile = await prettier.format(openapiConfigFile, { singleQuote: true, singleAttributePerLine: true, parser: "typescript", }); await fs_extra_1.default.writeFile(path_1.default.join(appPaths.configs, "openapi.config.ts"), formatConfigFile); // main file const mainFunc = ` import { Avleon } from '@avleon/core'; import { OpenApiConfig } from './config/openapi.config'; import { HomeController } from './controllers/home.controller'; const app = Avleon.createApplication(); if(app.isDevelopemtn()){ app.useOpenApi(OpenApiConfig); } app.useControllers([ HomeController ]); app.useStaticFiles(); export default app; `; const formatMainFunc = await prettier.format(mainFunc, { singleQuote: true, singleAttributePerLine: true, parser: "typescript", }); await fs_extra_1.default.writeFile(path_1.default.join(appPaths.src, "app.ts"), formatMainFunc); // create serve.ts const serveFunc = ` import app from "./app"; async function start(){ app.run(); // default run on :4000 } start(); `; const formatServeFunc = await prettier.format(serveFunc, { singleQuote: true, singleAttributePerLine: true, parser: "typescript", }); await fs_extra_1.default.writeFile(path_1.default.join(appPaths.src, "serve.ts"), formatServeFunc); // create package.json const packageJson = ` { "name": "${(0, lodash_1.snakeCase)(fname)}", "version": "0.0.1", "description": "Basic avleon application", "main": "dist/serve.js", "scripts": { "start:dev": "nodemon ./src/serve.ts", "start:debug": "nodemon --watch ./src --ext ts --exec node --inspect=0.0.0.0:9229 -r ts-node/register ./src/serve.ts", "clean": "rimraf ./dist", "build": "npm run clean & tsc --project ./tsconfig.build.json", "start": "node ./dist/serve.js", "test": "jest", "test:watch": "jest --watch", "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "jest --config ./test/e2e-spec.json" }, "keywords": ["avleon","nodejs","typescript"], "license": "ISC", "dependencies": { "@avleon/core": "^0.0.36", "@avleon/cli": "^0.0.42", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "rimraf": "^6.0.1", "reflect-metadata": "^0.2.2" }, "devDependencies": { "@types/jest": "^29.5.14", "@types/node": "^24.0.3", "jest": "^29.7.0", "ts-jest": "^29.2.6", "nodemon": "^3.1.7", "ts-node": "^10.9.2", "typescript": "^5.7.2" }, "jest": { "preset": "ts-jest", "rootDir": "src", "testRegex": ".*/\/\.spec/\/\.ts$", "collectCoverageFrom": [ "**/*.(t|j)s" ], "coverageDirectory": "../coverage", "testEnvironment": "node" } } `; const formattedPackageJson = await prettier.format(packageJson, { parser: "json", }); await fs_extra_1.default.writeFile(path_1.default.join(appPaths.root, "package.json"), formattedPackageJson); const tsconfigJson = await prettier.format(`{ "compilerOptions": { "target": "ES2017", "module": "CommonJS", "moduleResolution": "node", "experimentalDecorators": true, "emitDecoratorMetadata": true, "outDir": "./dist", "esModuleInterop": true, "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] }`, { parser: "json" }); await fs_extra_1.default.writeFile(path_1.default.join(appPaths.root, "tsconfig.json"), tsconfigJson); const tsconfigBuildJson = await prettier.format(`{ "extends": "./tsconfig.json", "exclude": ["node_modules","coverage", "test", "dist", "**/*spec.ts"] } `, { parser: "json" }); await fs_extra_1.default.writeFile(path_1.default.join(appPaths.root, "tsconfig.build.json"), tsconfigBuildJson); // write e2e-test.json const e2eJson = await prettier.format(`{ "moduleFileExtensions": [ "js", "json", "ts" ], "rootDir": ".", "testEnvironment": "node", "testRegex": ".e2e-spec.ts$", "transform": { "^.+/\/\.(t|j)s$": "ts-jest" } }`, { parser: "json" }); await fs_extra_1.default.writeFile(path_1.default.join(appPaths.root, "test/e2e-spec.json"), e2eJson); await fs_extra_1.default.writeFile(path_1.default.join(appPaths.root, ".gitignore"), `node_modules/\ndist/\n.env`); try { console.log(`Running ${pm} install...`); await execAsync(`cd ${fname}`); await installDependencies(pm, fname); } catch (error) { console.error('❌ Installation failed:', error); } console.info("Enjoy :D"); }