@avleon/cli 0.0.27 → 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
@@ -180,12 +180,17 @@ async function run() {
180
180
  if (args[0] == "make:controller" || args[0] == "m:c") {
181
181
  let resource = false;
182
182
  let rest = false;
183
+ let prefix = true;
184
+ let root = null;
183
185
  if (args.some((x) => x == "-r" || x == "--resource")) {
184
186
  resource = true;
185
187
  }
186
188
  if (args.some((x) => x == "-r" || x == "--rest")) {
187
189
  rest = true;
188
190
  }
191
+ if (args.some((x) => x == "--base-path")) {
192
+ prefix = false;
193
+ }
189
194
  let model = null;
190
195
  if (args.some((x) => x == "-m" || x == "--model")) {
191
196
  const index = args.includes("-m")
@@ -197,7 +202,17 @@ async function run() {
197
202
  const modelName = args[index + 1];
198
203
  model = modelName;
199
204
  }
200
- await (0, controller_1.createController)(args[1], { force, resource, rest, 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 });
201
216
  }
202
217
  }
203
218
  }
@@ -9,113 +9,84 @@ const path_1 = __importDefault(require("path"));
9
9
  const path_helper_1 = require("./helpers/path-helper");
10
10
  const promises_1 = __importDefault(require("node:fs/promises"));
11
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, rest: false, model: null }, p) {
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) {
18
39
  if (!name) {
19
40
  throw new Error("Controller name not found. use --name or npx avleon make:controller HomeController");
20
41
  }
21
- let stubPath = path_helper_1.pathHelper.stubPath('controllers/basic-controller.stub');
42
+ // determine stub for generate
43
+ let stubPath = controllersStubs.basic;
22
44
  if (options.rest) {
23
- stubPath = path_helper_1.pathHelper.stubPath('controllers/rest-controller.stub');
45
+ stubPath = controllersStubs.rest;
46
+ if (options.model) {
47
+ stubPath = controllersStubs.ormRest;
48
+ }
24
49
  }
50
+ // determine root path for create controller file
51
+ const rootPath = options.root ? 'src/' + options.root + '/' : 'src/controllers/';
52
+ // ensure file create directory exits
25
53
  if (name.split("/").length > 1) {
26
- if (!(0, fs_1.existsSync)(path_1.default.join('src/controllers/', name.split("/").splice(-1, 1).join("/")))) {
27
- await promises_1.default.mkdir(path_1.default.join('src/controllers/', name.replace('/' + file_helper_1.fh.filenameFromPath(name), '')), { recursive: true });
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 });
28
56
  }
29
57
  }
58
+ // read stub content from stub file
30
59
  const content = await promises_1.default.readFile(stubPath, 'utf8');
31
60
  const names = (0, file_helper_1.resolveNames)(file_helper_1.fh.filenameFromPath(name), 'Controller');
32
- const replacedContent = content
33
- .replaceAll('{Controller}', names.className)
61
+ const className = names.className.replace("Controller", '');
62
+ if (options.model) {
63
+ await createRestService(className, options.model);
64
+ }
65
+ let replacedContent = content
66
+ .replaceAll('{Controller}', className)
34
67
  .replaceAll('{controller}', names.varName);
35
- console.log('replce', content);
36
- await promises_1.default.writeFile(path_1.default.join('src/controllers/', name + '.controller.ts'), replacedContent, 'utf8');
37
- // const controllerPath = path.join(process.cwd(), "./src/controllers");
38
- // const controllerFolderExists = existsSync(controllerPath);
39
- // if (!controllerFolderExists) {
40
- // await mkdir(controllerPath, {
41
- // recursive: true,
42
- // });
43
- // }
44
- // const controllerName = name.at(0).toUpperCase() + name.slice(1);
45
- // const controllerNameLowerCase = name
46
- // .replace(/Controller/ig, '')
47
- // .match(/[A-Z]?[a-z]+|[0-9]+/g) // added ? to also capture single lowercase words
48
- // ?.join('-')
49
- // .toLowerCase() || name.toLowerCase();
50
- // const controllerNameCap = controllerName.replace(/Controller/ig, '')
51
- // const controllerExists = existsSync(`${controllerPath}/${name.toLowerCase()}.controller.ts`);
52
- // if (controllerExists && !options.force) {
53
- // console.log(
54
- // chalk.bold(chalk.red("controller already exists!")),
55
- // chalk.greenBright("Use -f or --force to overwrite.\r"),
56
- // );
57
- // return;
58
- // }
59
- // if (options.resource && !options.model) {
60
- // console.log(
61
- // chalk.bold(chalk.red("Model must be provide to generate rest controller!")),
62
- // chalk.greenBright("Use -m Model or --model Model to .\r"),
63
- // );
64
- // return;
65
- // }
66
- // const restController = `
67
- // import { ApiController, Collection, Get, Post, Put, Delete, Param, Body } from '@avleon/core';
68
- // import { ${capitalize(options.model)} } from '../models/${capitalize(options.model)}'
69
- // \t
70
- // @ApiController("/${controllerNameLowerCase}s")
71
- // export class ${controllerName}Controller {\n
72
- // constructor(
73
- // private readonly ${options.model.toLowerCase()}Repository = Collection.fromRepository(${capitalize(options.model)})
74
- // ){}
75
- // @Get()
76
- // async findAll(){
77
- // return "okay";
78
- // }\n
79
- // @Get('/:id')
80
- // async findOne(@Param('id') id:number){
81
- // return "okay";
82
- // }\n
83
- // @Post()
84
- // async create(@Body() body:any){
85
- // return true;
86
- // }\n
87
- // @Put('/:id')
88
- // async update(@Param('id') id:number, @Body() body:any){
89
- // return true;
90
- // }\n
91
- // @Delete('/:id')
92
- // async delete(@Param('id') id:number){
93
- // return true;
94
- // }
95
- // }
96
- // `;
97
- // const basicContorller = `import {ApiController, Get} from '@avleon/core'
98
- // \n
99
- // @ApiController("/${controllerNameLowerCase}")
100
- // export class ${controllerName}{
101
- // \n
102
- // @Get()
103
- // index(){
104
- // return []
105
- // }
106
- // }
107
- // `;
108
- // const formatcontroller = await prettier.format(
109
- // options.resource ? restController : basicContorller,
110
- // {
111
- // singleQuote: true,
112
- // singleAttributePerLine: true,
113
- // parser: "typescript",
114
- // },
115
- // );
116
- // await writeFile(
117
- // path.join(process.cwd(), "./src/controllers/" + controllerName.toLowerCase().replace("controller", "") + ".controller" + ".ts"),
118
- // formatcontroller,
119
- // );
68
+ if (options.model) {
69
+ replacedContent = replacedContent
70
+ .replaceAll('{Model}', capitalize(options.model))
71
+ .replaceAll('{model}', lower(options.model));
72
+ }
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');
120
77
  console.log("Controller created succssessfully!");
121
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
+ 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
+ }
44
57
  async function createApplication(fname, flags = {}) {
45
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]);
@@ -96,7 +110,7 @@ serve();
96
110
  const packageJson = `
97
111
  {
98
112
  "name": "${fname}",
99
- "version": "0.0.0",
113
+ "version": "0.0.1",
100
114
  "description": "Basic avleon application",
101
115
  "main": "index.js",
102
116
  "scripts": {
@@ -131,7 +145,7 @@ serve();
131
145
  "jest": {
132
146
  "preset": "ts-jest",
133
147
  "rootDir": "src",
134
- "testRegex": ".*\\.spec\\.ts$",
148
+ "testRegex": ".*/\/\.spec/\/\.ts$",
135
149
  "collectCoverageFrom": [
136
150
  "**/*.(t|j)s"
137
151
  ],
@@ -173,7 +187,7 @@ serve();
173
187
  "testEnvironment": "node",
174
188
  "testRegex": ".e2e-spec.ts$",
175
189
  "transform": {
176
- "^.+\\.(t|j)s$": "ts-jest"
190
+ "^.+/\/\.(t|j)s$": "ts-jest"
177
191
  }
178
192
  }`, { parser: "json" });
179
193
  await fs_extra_1.default.writeFile(win32_1.default.join(appPaths.root, "test/e2e-spec.json"), e2eJson);
@@ -181,8 +195,8 @@ serve();
181
195
  // create basic service
182
196
  // create basic controller
183
197
  console.info("App created successfully. Run the following command to get start.");
184
- console.log(`cd ${fname} && pnpm install`);
185
- 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`);
186
200
  //execSync(`cd ${fname} && pnpm install && pnpm add @avleon/core`, { stdio: 'inherit' })
187
201
  console.info("Enjoy :D");
188
202
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.fh = void 0;
4
4
  exports.getLastPart = getLastPart;
5
+ exports.getFilePathWithoutName = getFilePathWithoutName;
5
6
  exports.resolveNames = resolveNames;
6
7
  const filenameFromPath = (fpath) => fpath.split('/')[fpath.split('/').length - 1];
7
8
  function getLastPart(str, separator) {
@@ -10,6 +11,14 @@ function getLastPart(str, separator) {
10
11
  const parts = str.split(separator);
11
12
  return parts.at(-1);
12
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
+ }
13
22
  function resolveNames(name, exclude) {
14
23
  const parsedName = name.replace(exclude, '');
15
24
  return {
package/dist/paths.js CHANGED
@@ -25,8 +25,7 @@ const appPaths = (rootPath) => {
25
25
  controllers: node_path_1.default.join(root, "src/controllers"),
26
26
  models: node_path_1.default.join(root, "src/models"),
27
27
  services: node_path_1.default.join(root, "src/services"),
28
- requests: node_path_1.default.join(root, "src/requests"),
29
- responses: node_path_1.default.join(root, "src/responses"),
28
+ dtos: node_path_1.default.join(root, "src/dtos"),
30
29
  configs: node_path_1.default.join(root, "src/configs")
31
30
  };
32
31
  };
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "@avleon/cli",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "bin": {
5
- "avleon": "./dist/cli.js",
6
- "av":"./dist/cli.js"
5
+ "av": "./dist/cli.js"
7
6
  },
8
7
  "description": "",
9
8
  "main": "dist/index.js",
@@ -32,6 +31,7 @@
32
31
  "chalk": "^5.4.1",
33
32
  "cli-table3": "^0.6.5",
34
33
  "fs-extra": "^11.2.0",
34
+ "inquirer": "^12.6.0",
35
35
  "lodash": "^4.17.21",
36
36
  "prettier": "^3.3.3",
37
37
  "rimraf": "^6.0.1"
@@ -2,7 +2,7 @@ import { ApiController, Get, HttpResponse } from '@avleon/core';
2
2
 
3
3
 
4
4
  @ApiController('/{controller}s')
5
- export class {Controller}{
5
+ export class {Controller}Controller{
6
6
 
7
7
  @Get()
8
8
  index(){
@@ -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
+ }
@@ -1,32 +1,34 @@
1
- import { ApiController, Get, Post, Update, Delete, Param, Body, HttpResponse } from '@avleon/core';
2
-
1
+ import { ApiController, Get, Post, Delete, Param, Query, Body, HttpExceptions } from '@avleon/core';
3
2
 
4
3
  @ApiController('/{controller}s')
5
- export class {Controller}{
4
+ export class {Controller}Controller{
5
+
6
+
6
7
 
7
8
  @Get()
8
- index(){
9
- return HttpResponse.Ok("{Controller}");
9
+ async index(@Query() query?:any){
10
+ throw new Error("Method not implemented.");
10
11
  }
11
12
 
12
13
  @Get('/:id')
13
- findOne(@Param('id') id:{pktype}){
14
- return HttpResponse.Ok(`Item found with id:${id}`);
14
+ async findOne(@Param('id') id:number){
15
+ throw new Error("Method not implemented.");
15
16
  }
16
17
 
17
18
  @Post()
18
- create(@Body() body:{bodyType}){
19
- return HttpResponse.Ok("Created");
19
+ async create(@Body() body:any){
20
+ throw new Error("Method not implemented.");
20
21
  }
21
22
 
22
- @Update('/:id')
23
- update(@Param('id') id:{pktype}, updateBody:{updateBodyType}){
24
- return HttpResponse.Ok(`Item updated with id:${id}`)
23
+ @Post('/:id')
24
+ async update(@Param('id') id:number, updateBody:any){
25
+
26
+ throw new Error("Method not implemented.");
25
27
  }
26
28
 
27
29
  @Delete('/:id')
28
- delete(@Param('id') id:{pktype}){
29
- return HttpResponse.Ok(`Item delted with id:${id}`)
30
+ async delete(@Param('id') id:number){
31
+ throw new Error("Method not implemented.");
30
32
  }
31
33
 
32
34
  }
@@ -1,34 +1,73 @@
1
- import { AppService, Collection } from '@avleon/core';
1
+ import { AppService, InjectRepository } from '@avleon/core';
2
+ import { Repository } from 'typeorm';
3
+ import { {Model} } from '../models/{model}.model';
4
+
2
5
 
3
6
  @AppService
4
- export class {Service}{
7
+ export class {Service}Service{
5
8
 
6
9
  constructor(
7
- private readonly {modelRepository}:Collection.fromRepository({Model})
8
- )
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
+ }
9
40
 
10
- findAll(options?:any){
11
- if(options && options.page){
12
- return this.{modelRepository}.paginate(options.page)
13
- }
14
- return this.{modelRepository}.find();
41
+ async findByPk(id:number){
42
+ return this.{model}Repository.findOne({id});
15
43
  }
16
44
 
17
- findOne(id:{pktype}){
18
- return this.{modelRepository}.findOne({where:{id}}) ;
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}}) ;
19
56
  }
20
57
 
21
- create(createBody:{createBodyType}){
22
- const newItem = this.{modelRepository}.create();
23
- return await this.{modelRepository}.save();
58
+ async create(createBody:any){
59
+ const newItem = this.{model}Repository.create();
60
+ return await this.{model}Repository.save();
24
61
  }
25
62
 
26
- update(id:{pktype}, updateBody:{updateBodyType}){
27
- return this.{modelRepository}.update({id}, updateBody);
63
+ async update(id:number, updateBody:any){
64
+ const isUpdate = await this.{model}Repository.update({id}, updateBody);
65
+ return isUpdate.affected > 0;
28
66
  }
29
67
 
30
- delete(id:{pktype}){
31
- return this.modelRepository.delete({id});
68
+ async delete(id:number){
69
+ const isDeleted = await this.{model}Repository.delete({id});
70
+ return isDeleted.affected > 0;
32
71
  }
33
72
 
34
73
  }