@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 +26 -54
- package/dist/controller.js +72 -84
- package/dist/create.js +75 -8
- package/dist/helpers/file-helper.js +30 -0
- package/dist/helpers/path-helper.js +21 -0
- package/dist/paths.js +13 -3
- package/package.json +6 -4
- package/stubs/app/app-controller.stub +11 -0
- package/stubs/app/app-minimal.stub +17 -0
- package/stubs/app/app-withdb.stub +0 -0
- package/stubs/basic-controller.stub +7 -0
- package/stubs/config.stub +11 -0
- package/stubs/controllers/basic-controller.stub +12 -0
- package/stubs/controllers/orm-rest-controller.stub +52 -0
- package/stubs/controllers/rest-controller.stub +34 -0
- package/stubs/model.stub +0 -0
- package/stubs/models/basic-model.stub +6 -0
- package/stubs/models/entity-model.stub +23 -0
- package/stubs/serve.stub +10 -0
- package/stubs/services/basic-service.stub +8 -0
- package/stubs/services/rest-service.stub +73 -0
- package/tsconfig.json +2 -2
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
|
-
|
|
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
|
}
|
package/dist/controller.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
18
|
-
|
|
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
|
|
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
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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.
|
|
61
|
-
|
|
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.
|
|
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} &&
|
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "0.0.29",
|
|
4
4
|
"bin": {
|
|
5
|
-
"
|
|
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,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
|
+
}
|
package/stubs/model.stub
ADDED
|
File without changes
|
|
@@ -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
|
+
}
|
package/stubs/serve.stub
ADDED
|
@@ -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": "
|
|
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
|
}
|