@avleon/cli 0.0.25 → 0.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -42,7 +42,6 @@ exports.run = run;
42
42
  const cli_table3_1 = __importDefault(require("cli-table3"));
43
43
  const path_1 = __importDefault(require("path"));
44
44
  const promises_1 = __importDefault(require("fs/promises"));
45
- const fs_extra_1 = __importDefault(require("fs-extra"));
46
45
  const fs_1 = require("fs");
47
46
  const prettier = __importStar(require("prettier"));
48
47
  const controller_1 = require("./controller");
@@ -140,57 +139,6 @@ import {Entity, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } fro
140
139
  await promises_1.default.writeFile(path_1.default.join(process.cwd(), "./src/models/" + modelName.toLowerCase() + ".ts"), formatModel);
141
140
  console.log("Model created succssessfully!");
142
141
  }
143
- async function createXApplication(fname) {
144
- if ((0, fs_1.existsSync)(process.cwd() + fname)) {
145
- throw new Error("Application already exists");
146
- }
147
- const projectPath = path_1.default.join(process.cwd(), fname);
148
- const templateDir = path_1.default.resolve("D:\\projects\\node\\iqra\\packages\\cli\\src\\stubs");
149
- //await fs.mkdir(projectPath);
150
- //await fsExtra.copy(templateDir, projectPath + '/');
151
- // Define project path
152
- // const projectPath = path.resolve('new_test');
153
- // Clone the repository and move the required folder
154
- const cloneCommand = `
155
- git clone -n --depth=1 --filter=tree:0 https://github.com/xtareq/iqra temp_repo &&
156
- cd temp_repo &&
157
- git sparse-checkout init --no-cone &&
158
- git sparse-checkout set examples/iqra_test &&
159
- git checkout &&
160
- mv examples/iqra_test ${projectPath} &&
161
- cd ..
162
- `;
163
- try {
164
- // Execute the cloning and moving process
165
- console.log("Cloning and setting up the repository...");
166
- (0, child_process_1.exec)(cloneCommand, {});
167
- // Check if the projectPath exists before proceeding
168
- if (!fs_extra_1.default.existsSync(projectPath)) {
169
- throw new Error(`Project path "${projectPath}" was not created.`);
170
- }
171
- // Remove the Git origin from the new project
172
- console.log("Removing Git origin...");
173
- (0, child_process_1.execSync)(`cd ${projectPath} && git remote remove origin`, {
174
- stdio: "inherit",
175
- });
176
- // Clean up the temporary repository
177
- console.log("Cleaning up temporary files...");
178
- fs_extra_1.default.removeSync("./temp_repo");
179
- console.log(`Project created successfully in ${projectPath}`);
180
- }
181
- catch (error) {
182
- console.error("An error occurred:", error);
183
- // Cleanup in case of failure
184
- if (fs_extra_1.default.existsSync("./temp_repo")) {
185
- console.log("Cleaning up temporary repository...");
186
- fs_extra_1.default.removeSync("./temp_repo");
187
- }
188
- if (fs_extra_1.default.existsSync(projectPath)) {
189
- console.log("Cleaning up project path...");
190
- fs_extra_1.default.removeSync(projectPath);
191
- }
192
- }
193
- }
194
142
  async function run() {
195
143
  try {
196
144
  const args = process.argv.slice(2);
@@ -207,12 +155,17 @@ async function run() {
207
155
  }
208
156
  else {
209
157
  let force = false;
158
+ let minimal = false;
210
159
  if (args.some((x) => x == "-f" || x == "--force")) {
211
160
  force = true;
212
161
  }
162
+ if (args.some((x) => x == "--mimimal")) {
163
+ minimal = true;
164
+ }
165
+ const flags = { minimal, force };
213
166
  if (args[0] == "new") {
214
167
  const fname = args[1];
215
- await (0, create_1.createApplication)(fname);
168
+ await (0, create_1.createApplication)(fname, flags);
216
169
  }
217
170
  if (args[0] == "build") {
218
171
  process.env.NODE_ENV = "production";
@@ -226,9 +179,18 @@ async function run() {
226
179
  }
227
180
  if (args[0] == "make:controller" || args[0] == "m:c") {
228
181
  let resource = false;
182
+ let rest = false;
183
+ let prefix = true;
184
+ let root = null;
229
185
  if (args.some((x) => x == "-r" || x == "--resource")) {
230
186
  resource = true;
231
187
  }
188
+ if (args.some((x) => x == "-r" || x == "--rest")) {
189
+ rest = true;
190
+ }
191
+ if (args.some((x) => x == "--base-path")) {
192
+ prefix = false;
193
+ }
232
194
  let model = null;
233
195
  if (args.some((x) => x == "-m" || x == "--model")) {
234
196
  const index = args.includes("-m")
@@ -240,7 +202,17 @@ async function run() {
240
202
  const modelName = args[index + 1];
241
203
  model = modelName;
242
204
  }
243
- await (0, controller_1.createController)(args[1], { force, resource, model });
205
+ if (args.some((x) => x == "-rt" || x == "--root")) {
206
+ const index = args.includes("-rt")
207
+ ? args.indexOf("-rt")
208
+ : args.indexOf("--root");
209
+ if (args[index + 1] == undefined) {
210
+ throw new Error("Root Path not defined");
211
+ }
212
+ const rootPath = args[index + 1];
213
+ root = rootPath;
214
+ }
215
+ await (0, controller_1.createController)(args[1], { force, resource, prefix, rest, model, root });
244
216
  }
245
217
  }
246
218
  }
@@ -4,101 +4,89 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createController = createController;
7
- const chalk_1 = __importDefault(require("chalk"));
8
7
  const fs_1 = require("fs");
9
- const promises_1 = require("fs/promises");
10
8
  const path_1 = __importDefault(require("path"));
11
- const prettier_1 = __importDefault(require("prettier"));
9
+ const path_helper_1 = require("./helpers/path-helper");
10
+ const promises_1 = __importDefault(require("node:fs/promises"));
11
+ const file_helper_1 = require("./helpers/file-helper");
12
+ const lodash_1 = require("lodash");
12
13
  function capitalize(str) {
13
14
  if (!str)
14
15
  return '';
15
16
  return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
16
17
  }
17
- async function createController(name, options = { force: false, resource: false, model: null }, p) {
18
- var _a;
18
+ function lower(str) {
19
+ return str.toLowerCase();
20
+ }
21
+ function exportNamesAndPath(input) {
22
+ const parts = input.split('/');
23
+ const lastPart = parts.pop();
24
+ const filePath = parts.length ? parts.join('/') + '/' : '.';
25
+ // Normalize base name by removing trailing "Controller" (case-insensitive)
26
+ const rawName = lastPart.replace(/controller$/i, '');
27
+ // Create className in PascalCase + Controller
28
+ const className = (0, lodash_1.upperFirst)((0, lodash_1.camelCase)(rawName));
29
+ // Create fileName in kebab-case + .controller.ts
30
+ const fileName = `${(0, lodash_1.kebabCase)(rawName)}.controller.ts`;
31
+ return { className, fileName, filePath };
32
+ }
33
+ const controllersStubs = {
34
+ basic: path_helper_1.pathHelper.stubPath('controllers/basic-controller.stub'),
35
+ rest: path_helper_1.pathHelper.stubPath('controllers/basic-controller.stub'),
36
+ ormRest: path_helper_1.pathHelper.stubPath('controllers/orm-rest-controller.stub')
37
+ };
38
+ async function createController(name, options = { force: false, resource: false, prefix: true, rest: false, model: null, root: null }, p) {
19
39
  if (!name) {
20
- throw new Error("Controller name not found. use --name or node artisan make:controller HomeController");
40
+ throw new Error("Controller name not found. use --name or npx avleon make:controller HomeController");
41
+ }
42
+ // determine stub for generate
43
+ let stubPath = controllersStubs.basic;
44
+ if (options.rest) {
45
+ stubPath = controllersStubs.rest;
46
+ if (options.model) {
47
+ stubPath = controllersStubs.ormRest;
48
+ }
21
49
  }
22
- const controllerPath = path_1.default.join(process.cwd(), "./src/controllers");
23
- const controllerFolderExists = (0, fs_1.existsSync)(controllerPath);
24
- if (!controllerFolderExists) {
25
- await (0, promises_1.mkdir)(controllerPath, {
26
- recursive: true,
27
- });
50
+ // determine root path for create controller file
51
+ const rootPath = options.root ? 'src/' + options.root + '/' : 'src/controllers/';
52
+ // ensure file create directory exits
53
+ if (name.split("/").length > 1) {
54
+ if (!(0, fs_1.existsSync)(path_1.default.join(rootPath, name.split("/").splice(-1, 1).join("/")))) {
55
+ await promises_1.default.mkdir(path_1.default.join(rootPath, name.replace('/' + file_helper_1.fh.filenameFromPath(name), '')), { recursive: true });
56
+ }
28
57
  }
29
- const controllerName = name.at(0).toUpperCase() + name.slice(1);
30
- const controllerNameLowerCase = ((_a = name
31
- .replace(/Controller/ig, '')
32
- .match(/[A-Z]?[a-z]+|[0-9]+/g) // added ? to also capture single lowercase words
33
- ) === null || _a === void 0 ? void 0 : _a.join('-').toLowerCase()) || name.toLowerCase();
34
- const controllerNameCap = controllerName.replace(/Controller/ig, '');
35
- const controllerExists = (0, fs_1.existsSync)(`${controllerPath}/${name.toLowerCase()}.controller.ts`);
36
- if (controllerExists && !options.force) {
37
- console.log(chalk_1.default.bold(chalk_1.default.red("controller already exists!")), chalk_1.default.greenBright("Use -f or --force to overwrite.\r"));
38
- return;
58
+ // read stub content from stub file
59
+ const content = await promises_1.default.readFile(stubPath, 'utf8');
60
+ const names = (0, file_helper_1.resolveNames)(file_helper_1.fh.filenameFromPath(name), 'Controller');
61
+ const className = names.className.replace("Controller", '');
62
+ if (options.model) {
63
+ await createRestService(className, options.model);
39
64
  }
40
- if (options.resource && !options.model) {
41
- console.log(chalk_1.default.bold(chalk_1.default.red("Model must be provide to generate rest controller!")), chalk_1.default.greenBright("Use -m Model or --model Model to .\r"));
42
- return;
65
+ let replacedContent = content
66
+ .replaceAll('{Controller}', className)
67
+ .replaceAll('{controller}', names.varName);
68
+ if (options.model) {
69
+ replacedContent = replacedContent
70
+ .replaceAll('{Model}', capitalize(options.model))
71
+ .replaceAll('{model}', lower(options.model));
43
72
  }
44
- // if (options.model) {
45
- // const file = require(
46
- // path.join(process.cwd(), "./src/models/" + options.model.toUpperCase() + ".ts")
47
- // ).default;
48
- // if (file) {
49
- // Object.getOwnPropertyNames(file);
50
- // }
51
- // }
52
- const restController = `
53
- import { ApiController, Collection, Get, Post, Put, Delete, Param, Body } from '@avleon/core';
54
- import { ${capitalize(options.model)} } from '../models/${capitalize(options.model)}'
55
- \t
56
- @ApiController("/${controllerNameLowerCase}s")
57
- export class ${controllerName}Controller {\n
58
-
59
- constructor(
60
- private readonly ${options.model.toLowerCase()}Repository = Collection.fromRepository(${capitalize(options.model)})
61
- ){}
62
-
63
- @Get()
64
- async findAll(){
65
- return "okay";
66
- }\n
67
- @Get('/:id')
68
- async findOne(@Param('id') id:number){
69
- return "okay";
70
- }\n
71
- @Post()
72
- async create(@Body() body:any){
73
- return true;
74
- }\n
75
- @Put('/:id')
76
- async update(@Param('id') id:number, @Body() body:any){
77
- return true;
78
- }\n
79
- @Delete('/:id')
80
- async delete(@Param('id') id:number){
81
- return true;
82
- }
83
-
84
- }
85
- `;
86
- const basicContorller = `import {ApiController, Get} from '@avleon/core'
87
- \n
88
- @ApiController("/${controllerNameLowerCase}")
89
- export class ${controllerName}{
90
- \n
91
- @Get()
92
- index(){
93
- return []
94
- }
95
- }
96
- `;
97
- const formatcontroller = await prettier_1.default.format(options.resource ? restController : basicContorller, {
98
- singleQuote: true,
99
- singleAttributePerLine: true,
100
- parser: "typescript",
101
- });
102
- await (0, promises_1.writeFile)(path_1.default.join(process.cwd(), "./src/controllers/" + controllerName.toLowerCase().replace("controller", "") + ".controller" + ".ts"), formatcontroller);
73
+ if (!options.prefix) {
74
+ replacedContent = replacedContent.replace(/@ApiController\s*\(([^)]*)\)/g, '@ApiController');
75
+ }
76
+ await promises_1.default.writeFile(path_1.default.join(rootPath, (0, file_helper_1.getFilePathWithoutName)(name) + "/" + (0, lodash_1.kebabCase)(className) + '.controller.ts'), replacedContent, 'utf8');
103
77
  console.log("Controller created succssessfully!");
104
78
  }
79
+ async function createRestService(name, model) {
80
+ let stubPath = path_helper_1.pathHelper.stubPath('services/rest-service.stub');
81
+ const content = await promises_1.default.readFile(stubPath, 'utf8');
82
+ const names = (0, file_helper_1.resolveNames)(file_helper_1.fh.filenameFromPath(name), 'Controller');
83
+ let replacedContent = content
84
+ .replaceAll('{Service}', name);
85
+ if (model) {
86
+ replacedContent = replacedContent
87
+ .replaceAll('{Model}', capitalize(model))
88
+ .replaceAll('{model}', lower(model));
89
+ }
90
+ await promises_1.default.writeFile(path_1.default.join('src/services/', (0, lodash_1.kebabCase)(name) + '.service.ts'), replacedContent, 'utf8');
91
+ console.log("Service created succssessfully!");
92
+ }
package/dist/create.js CHANGED
@@ -41,8 +41,22 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
41
41
  const paths_1 = require("./paths");
42
42
  const prettier = __importStar(require("prettier"));
43
43
  const win32_1 = __importDefault(require("path/win32"));
44
- async function createApplication(fname) {
45
- const appPaths = (0, paths_1.appPaths)(fname);
44
+ const inquirer_1 = __importDefault(require("inquirer"));
45
+ async function askForPackageManager() {
46
+ const { packageManager } = await inquirer_1.default.prompt([
47
+ {
48
+ type: 'list',
49
+ name: 'packageManager',
50
+ message: 'Which package manager do you want to use?',
51
+ choices: ['npm', 'yarn', 'pnpm'],
52
+ default: 'npm'
53
+ }
54
+ ]);
55
+ return packageManager;
56
+ }
57
+ async function createApplication(fname, flags = {}) {
58
+ let appPaths = (0, paths_1.appPaths)(fname);
59
+ const pm = await askForPackageManager();
46
60
  const dirs = Object.values(appPaths);
47
61
  for (let i = 0; i < dirs.length; i++) {
48
62
  await fs_extra_1.default.ensureDir(dirs[i]);
@@ -54,12 +68,21 @@ async function createApplication(fname) {
54
68
  import {
55
69
  Avleon
56
70
  } from "@avleon/core";
71
+ import {HomeController} from './controllers/home.controller';
57
72
 
58
73
 
59
74
  const app = Avleon.createApplication();
60
- app.mapGet('/', ()=> "Welcome");
61
- app.run();
75
+ app.useOpenApi({
76
+ info:{
77
+ title: '${fname} Api',
78
+ version: '0.0.1'
79
+ }
80
+ });
62
81
 
82
+ app.useControllers([HomeController]);
83
+ app.useStaticFiles();
84
+
85
+ export default app;
63
86
  `;
64
87
  const formatMainFunc = await prettier.format(mainFunc, {
65
88
  singleQuote: true,
@@ -67,15 +90,31 @@ app.run();
67
90
  parser: "typescript",
68
91
  });
69
92
  await fs_extra_1.default.writeFile(win32_1.default.join(appPaths.src, "app.ts"), formatMainFunc);
93
+ // create serve.ts
94
+ const serveFunc = `
95
+ import app from "./app";
96
+
97
+ async function serve(){
98
+ app.run();
99
+ }
100
+
101
+ serve();
102
+ `;
103
+ const formatServeFunc = await prettier.format(serveFunc, {
104
+ singleQuote: true,
105
+ singleAttributePerLine: true,
106
+ parser: "typescript",
107
+ });
108
+ await fs_extra_1.default.writeFile(win32_1.default.join(appPaths.src, "serve.ts"), formatServeFunc);
70
109
  // create package.json
71
110
  const packageJson = `
72
111
  {
73
112
  "name": "${fname}",
74
- "version": "0.0.0",
113
+ "version": "0.0.1",
75
114
  "description": "Basic avleon application",
76
115
  "main": "index.js",
77
116
  "scripts": {
78
- "start:dev": "nodemon src/serve.ts",
117
+ "start:dev": "nodemon /src/serve.ts",
79
118
  "start:debug": "nodemon --watch src --ext ts --exec node --inspect=0.0.0.0:9229 -r ts-node/register src/serve.ts",
80
119
  "clean": "rimraf ./dist",
81
120
  "build": "npm run clean & tsc --project ./tsconfig.build.json",
@@ -96,9 +135,22 @@ app.run();
96
135
  "reflect-metadata": "^0.2.2"
97
136
  },
98
137
  "devDependencies": {
138
+ "@types/jest": "^29.5.14",
139
+ "jest": "^29.7.0",
140
+ "ts-jest": "^29.2.6",
99
141
  "nodemon": "^3.1.7",
100
142
  "ts-node": "^10.9.2",
101
143
  "typescript": "^5.7.2"
144
+ },
145
+ "jest": {
146
+ "preset": "ts-jest",
147
+ "rootDir": "src",
148
+ "testRegex": ".*/\/\.spec/\/\.ts$",
149
+ "collectCoverageFrom": [
150
+ "**/*.(t|j)s"
151
+ ],
152
+ "coverageDirectory": "../coverage",
153
+ "testEnvironment": "node"
102
154
  }
103
155
 
104
156
  }
@@ -124,12 +176,27 @@ app.run();
124
176
  "exclude": ["node_modules", "dist"]
125
177
  }`, { parser: "json" });
126
178
  await fs_extra_1.default.writeFile(win32_1.default.join(appPaths.root, "tsconfig.json"), tsconfigJson);
179
+ // write e2e-test.json
180
+ const e2eJson = await prettier.format(`{
181
+ "moduleFileExtensions": [
182
+ "js",
183
+ "json",
184
+ "ts"
185
+ ],
186
+ "rootDir": ".",
187
+ "testEnvironment": "node",
188
+ "testRegex": ".e2e-spec.ts$",
189
+ "transform": {
190
+ "^.+/\/\.(t|j)s$": "ts-jest"
191
+ }
192
+ }`, { parser: "json" });
193
+ await fs_extra_1.default.writeFile(win32_1.default.join(appPaths.root, "test/e2e-spec.json"), e2eJson);
127
194
  await fs_extra_1.default.writeFile(win32_1.default.join(appPaths.root, ".gitignore"), `node_modules/\ndist/\n.env`);
128
195
  // create basic service
129
196
  // create basic controller
130
197
  console.info("App created successfully. Run the following command to get start.");
131
- console.log(`cd ${fname} && pnpm install`);
132
- console.log(`npm run start:dev`);
198
+ console.log(`cd ${fname} && ${pm} install`);
199
+ console.log(pm == 'npm' ? `npm run start:dev` : `${pm} start:dev`);
133
200
  //execSync(`cd ${fname} && pnpm install && pnpm add @avleon/core`, { stdio: 'inherit' })
134
201
  console.info("Enjoy :D");
135
202
  }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fh = void 0;
4
+ exports.getLastPart = getLastPart;
5
+ exports.getFilePathWithoutName = getFilePathWithoutName;
6
+ exports.resolveNames = resolveNames;
7
+ const filenameFromPath = (fpath) => fpath.split('/')[fpath.split('/').length - 1];
8
+ function getLastPart(str, separator) {
9
+ if (!str.includes(separator))
10
+ return str;
11
+ const parts = str.split(separator);
12
+ return parts.at(-1);
13
+ }
14
+ function getFilePathWithoutName(fpath) {
15
+ const parts = fpath.split("/");
16
+ if (parts.length < 2) {
17
+ return "";
18
+ }
19
+ parts.splice(parts.length - 1, 1);
20
+ return parts.join("/");
21
+ }
22
+ function resolveNames(name, exclude) {
23
+ const parsedName = name.replace(exclude, '');
24
+ return {
25
+ className: parsedName.charAt(0).toUpperCase() + name.slice(1),
26
+ fileName: parsedName.toLowerCase(),
27
+ varName: parsedName.toLowerCase(),
28
+ };
29
+ }
30
+ exports.fh = { filenameFromPath };
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.pathHelper = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ // export const __filename = fileURLToPath(process.argv[1])
9
+ // export const __dirname = path.dirname(__filename)
10
+ /* */
11
+ exports.pathHelper = {
12
+ appSoucePath(p) {
13
+ return path_1.default.join(process.cwd(), p ? './src/' + p : './src/');
14
+ },
15
+ appTestPath(p) {
16
+ return path_1.default.join(process.cwd(), p ? './test/' + p : './test/');
17
+ },
18
+ stubPath(p) {
19
+ return path_1.default.join(__dirname, p ? '../../stubs/' + p : '../../stubs/');
20
+ },
21
+ };
package/dist/paths.js CHANGED
@@ -3,19 +3,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.appPaths = void 0;
6
+ exports.appPaths = exports.appPathsMinimal = void 0;
7
7
  const node_path_1 = __importDefault(require("node:path"));
8
+ const appPathsMinimal = (rootPath) => {
9
+ const root = rootPath ? rootPath : node_path_1.default.join(process.cwd(), "./");
10
+ return {
11
+ root: root,
12
+ src: node_path_1.default.join(root, "src"),
13
+ public: node_path_1.default.join(root, "public"),
14
+ test: node_path_1.default.join(root, "test"),
15
+ };
16
+ };
17
+ exports.appPathsMinimal = appPathsMinimal;
8
18
  const appPaths = (rootPath) => {
9
19
  const root = rootPath ? rootPath : node_path_1.default.join(process.cwd(), "./");
10
20
  return {
11
21
  root: root,
12
22
  src: node_path_1.default.join(root, "src"),
23
+ public: node_path_1.default.join(root, "public"),
13
24
  test: node_path_1.default.join(root, "test"),
14
25
  controllers: node_path_1.default.join(root, "src/controllers"),
15
26
  models: node_path_1.default.join(root, "src/models"),
16
27
  services: node_path_1.default.join(root, "src/services"),
17
- requests: node_path_1.default.join(root, "src/requests"),
18
- responses: node_path_1.default.join(root, "src/responses"),
28
+ dtos: node_path_1.default.join(root, "src/dtos"),
19
29
  configs: node_path_1.default.join(root, "src/configs")
20
30
  };
21
31
  };
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@avleon/cli",
3
- "version": "0.0.25",
3
+ "version": "0.0.29",
4
4
  "bin": {
5
- "avleon": "./dist/cli.js"
5
+ "av": "./dist/cli.js"
6
6
  },
7
7
  "description": "",
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
10
10
  "scripts": {
11
- "build": "tsc",
11
+ "build": "rimraf dist & tsc",
12
12
  "clean": "rm -rf ./dist",
13
13
  "watch": "tsc-watch"
14
14
  },
@@ -31,8 +31,10 @@
31
31
  "chalk": "^5.4.1",
32
32
  "cli-table3": "^0.6.5",
33
33
  "fs-extra": "^11.2.0",
34
+ "inquirer": "^12.6.0",
34
35
  "lodash": "^4.17.21",
35
- "prettier": "^3.3.3"
36
+ "prettier": "^3.3.3",
37
+ "rimraf": "^6.0.1"
36
38
  },
37
39
  "repository": {
38
40
  "type": "git",
@@ -0,0 +1,11 @@
1
+ import { Builder, AppConfig } from '@avleon/core';
2
+ import { HomeController } from './controllers/home.controller';
3
+
4
+ const builder = Builder.createAppBuilder();
5
+
6
+ const app = builder.build();
7
+ app.useOpenApi((config:AppConfig)=> config.openApi);
8
+ app.useControllers([HomeController]);
9
+
10
+
11
+ app.run();
@@ -0,0 +1,17 @@
1
+ import { Builder, AppConfig } from '@avleon/core';
2
+ const builder = Builder.createAppBuilder();
3
+
4
+ builder.services.addOpenApi();
5
+ builder.services.addServices();
6
+ builder.services.addAuthentication();
7
+ builder.servicse.addControllers();
8
+ const app = builder.build();
9
+
10
+
11
+
12
+ if(app.isDevelopment()){
13
+ app.useOpenApi((config:AppConfig)=> config.openApi);
14
+ }
15
+
16
+ app.mapGet('/', () => "Hello World!");
17
+ export default app;
File without changes
@@ -0,0 +1,7 @@
1
+ import { Get, HttpResponse } from '@avleon/core';
2
+ export class {{name}}{
3
+ constructor(
4
+ private readonly {}
5
+ ){}
6
+ }
7
+
@@ -0,0 +1,11 @@
1
+ @Config
2
+ export class OpenApiConfig {
3
+ config() {
4
+ return {
5
+ title: 'My API',
6
+ version: '1.0.0',
7
+ description: 'API documentation',
8
+ path: '/api-docs',
9
+ };
10
+ }
11
+ }
@@ -0,0 +1,12 @@
1
+ import { ApiController, Get, HttpResponse } from '@avleon/core';
2
+
3
+
4
+ @ApiController('/{controller}s')
5
+ export class {Controller}Controller{
6
+
7
+ @Get()
8
+ index(){
9
+ return "{controller} ok";
10
+ }
11
+
12
+ }
@@ -0,0 +1,52 @@
1
+ import { ApiController, Get, Post, Delete, Param, Query, Body, HttpExceptions } from '@avleon/core';
2
+ import { {Model}Service } from '../services/{model}.service';
3
+
4
+ @ApiController('/{controller}s')
5
+ export class {Controller}Controller{
6
+
7
+ constructor(
8
+ private readonly {model}Service: {Model}Service
9
+ ){}
10
+
11
+ @Get()
12
+ async index(@Query() query?:any){
13
+ if(query && query.page){
14
+ const result = await this.{model}Service.paginate(query.page);
15
+ return result;
16
+ }
17
+ const result = await this.{model}Service.findAll();
18
+ return result;
19
+ }
20
+
21
+ @Get('/:id')
22
+ async findOne(@Param('id') id:number){
23
+ const is{Model} = await this.{model}Service.findByPk(id);
24
+ if(!is{Model}) throw HttpExceptions.notFound("{Model} not found.");
25
+ return is{Model};
26
+ }
27
+
28
+ @Post()
29
+ async create(@Body() body:any){
30
+ const isSave = await this.{model}Service.create(body);
31
+ return isSave;
32
+ }
33
+
34
+ @Post('/:id')
35
+ async update(@Param('id') id:number, updateBody:any){
36
+ const is{Model} = await this.{model}Service.findByPk(id);
37
+ if(!is{Model}) throw HttpExceptions.notFound("{Model} not found.");
38
+ const isUpdated = await this.{model}Service.update(id,updateBody);
39
+ if(!isUpdated) throw HttpExceptions.internalError("Can't update {Model}");
40
+ return "Updated Successfully";
41
+ }
42
+
43
+ @Delete('/:id')
44
+ async delete(@Param('id') id:number){
45
+ const is{Model} = await this.{model}Service.findByPk(id);
46
+ if(!is{Model}) throw HttpExceptions.notFound("{Model} not found.");
47
+ const isDeleted = await this.{model}Service.delete(id);
48
+ if(!isDeleted) throw HttpExceptions.internalError("Can't delete");
49
+ return "Deleted Successfully";
50
+ }
51
+
52
+ }
@@ -0,0 +1,34 @@
1
+ import { ApiController, Get, Post, Delete, Param, Query, Body, HttpExceptions } from '@avleon/core';
2
+
3
+ @ApiController('/{controller}s')
4
+ export class {Controller}Controller{
5
+
6
+
7
+
8
+ @Get()
9
+ async index(@Query() query?:any){
10
+ throw new Error("Method not implemented.");
11
+ }
12
+
13
+ @Get('/:id')
14
+ async findOne(@Param('id') id:number){
15
+ throw new Error("Method not implemented.");
16
+ }
17
+
18
+ @Post()
19
+ async create(@Body() body:any){
20
+ throw new Error("Method not implemented.");
21
+ }
22
+
23
+ @Post('/:id')
24
+ async update(@Param('id') id:number, updateBody:any){
25
+
26
+ throw new Error("Method not implemented.");
27
+ }
28
+
29
+ @Delete('/:id')
30
+ async delete(@Param('id') id:number){
31
+ throw new Error("Method not implemented.");
32
+ }
33
+
34
+ }
File without changes
@@ -0,0 +1,6 @@
1
+
2
+
3
+ export class {Model}{
4
+ id: number;
5
+ name: string;
6
+ }
@@ -0,0 +1,23 @@
1
+
2
+ import {Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn} from 'typeorm';
3
+
4
+ @Entity({name:"{Model}"})
5
+ export class {Model}{
6
+
7
+ @PrimaryGeneratedColumn()
8
+ id:number;
9
+
10
+
11
+ // your fields
12
+
13
+ // @Column()
14
+ // name:string
15
+
16
+
17
+ @CreateDateColumn()
18
+ createdAt: Date;
19
+
20
+
21
+ @UpdateDateColumn()
22
+ updatedAt: Date;
23
+ }
@@ -0,0 +1,10 @@
1
+ import { Environment, inject } from "@avleon/core";
2
+ import app from "./app";
3
+
4
+ async function serve() {
5
+ const env = inject(Environment);
6
+ const port = env.get<number>("PORT") || 4000;
7
+ await app.run(port);
8
+ }
9
+
10
+ serve();
@@ -0,0 +1,8 @@
1
+
2
+ @AppService
3
+ export class {Service} {
4
+
5
+ sayHello(){
6
+ return "Hello World!";
7
+ }
8
+ }
@@ -0,0 +1,73 @@
1
+ import { AppService, InjectRepository } from '@avleon/core';
2
+ import { Repository } from 'typeorm';
3
+ import { {Model} } from '../models/{model}.model';
4
+
5
+
6
+ @AppService
7
+ export class {Service}Service{
8
+
9
+ constructor(
10
+ @InjectRepository({Model})
11
+ private readonly {model}Repository:Repository<{Model}>
12
+ ){}
13
+
14
+ async findAll(options:any={}){
15
+ return this.{model}Repository.find(options);
16
+ }
17
+
18
+ async paginate(current:number = 1, options:any={}){
19
+ const take = 10;
20
+ const skip = current > 1 ? ( current -1 ) * 10 : 0;
21
+ const total = await this.{model}Repository.count(options);
22
+ const totalPage = Math.ceil(total / take);
23
+ const next = current < totalPage ? current + 1 : null;
24
+ const prev = current > 1 ? current - 1 : null;
25
+ const data = await this.{model}Repository.find({
26
+ ...options,
27
+ take,
28
+ skip
29
+ })
30
+
31
+ return {
32
+ total,
33
+ totalPage,
34
+ current,
35
+ next,
36
+ prev,
37
+ data
38
+ };
39
+ }
40
+
41
+ async findByPk(id:number){
42
+ return this.{model}Repository.findOne({id});
43
+ }
44
+
45
+ async findBy(options:any){
46
+ return this.{model}Repository.findBy(options);
47
+ }
48
+
49
+ async findOneBy(options:any){
50
+ return this.{model}Repository.findOneBy(options);
51
+ }
52
+
53
+
54
+ async findOne(id:number){
55
+ return this.{model}Repository.findOne({where:{id}}) ;
56
+ }
57
+
58
+ async create(createBody:any){
59
+ const newItem = this.{model}Repository.create();
60
+ return await this.{model}Repository.save();
61
+ }
62
+
63
+ async update(id:number, updateBody:any){
64
+ const isUpdate = await this.{model}Repository.update({id}, updateBody);
65
+ return isUpdate.affected > 0;
66
+ }
67
+
68
+ async delete(id:number){
69
+ const isDeleted = await this.{model}Repository.delete({id});
70
+ return isDeleted.affected > 0;
71
+ }
72
+
73
+ }
package/tsconfig.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "ES2017",
3
+ "target": "ES2021",
4
4
  "module": "CommonJS",
5
5
  "moduleResolution": "node",
6
6
  "outDir": "./dist",
@@ -10,6 +10,6 @@
10
10
  "forceConsistentCasingInFileNames": true,
11
11
  "skipLibCheck": true
12
12
  },
13
- "include": ["src/**/*"],
13
+ "include": ["src/**/*", "src/stubs"],
14
14
  "exclude": ["node_modules", "dist"]
15
15
  }