@avleon/cli 0.0.45 → 0.0.47
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 +61 -87
- package/dist/commands.js +27 -19
- package/dist/controller.js +25 -21
- package/dist/create.js +116 -102
- package/dist/helpers/path-helper.js +19 -4
- package/dist/service.js +9 -13
- package/package.json +62 -61
- package/readme.md +116 -66
- package/stubs/app/app-controller.stub +13 -0
- package/stubs/app/app-minimal.stub +7 -0
- package/stubs/config.stub +15 -0
- package/stubs/controllers/basic-controller.stub +9 -0
- package/stubs/controllers/orm-rest-controller.stub +45 -0
- package/stubs/controllers/rest-controller.stub +29 -0
- package/stubs/models/basic-model.stub +4 -0
- package/stubs/models/entity-model.stub +18 -0
- package/stubs/serve.stub +10 -0
- package/stubs/services/basic-service.stub +8 -0
- package/stubs/services/orm-rest-service.stub +60 -0
- package/stubs/services/rest-service.stub +34 -0
package/dist/create.js
CHANGED
|
@@ -147,7 +147,8 @@ async function askForFeatures() {
|
|
|
147
147
|
choices: [
|
|
148
148
|
{ name: 'OpenAPI / Swagger docs', value: 'openapi', checked: true },
|
|
149
149
|
{ name: 'CORS support', value: 'cors', checked: false },
|
|
150
|
-
{ name: 'TypeORM
|
|
150
|
+
{ name: 'TypeORM', value: 'typeorm', checked: false },
|
|
151
|
+
{ name: 'Knex', value: 'knex', checked: false },
|
|
151
152
|
{ name: 'Scalar UI (replaces Swagger UI)', value: 'scalar', checked: false },
|
|
152
153
|
],
|
|
153
154
|
},
|
|
@@ -187,83 +188,84 @@ async function writeFile(filePath, content, label) {
|
|
|
187
188
|
}
|
|
188
189
|
// ─── Templates ────────────────────────────────────────────────────────────────
|
|
189
190
|
function homeServiceTemplate() {
|
|
190
|
-
return `
|
|
191
|
-
import { AppService } from '@avleon/core';
|
|
192
|
-
|
|
193
|
-
@AppService
|
|
194
|
-
export class HomeService {
|
|
195
|
-
sayHello() {
|
|
196
|
-
return { message: 'Hello World!' };
|
|
197
|
-
}
|
|
198
|
-
}
|
|
191
|
+
return `
|
|
192
|
+
import { AppService } from '@avleon/core';
|
|
193
|
+
|
|
194
|
+
@AppService
|
|
195
|
+
export class HomeService {
|
|
196
|
+
sayHello() {
|
|
197
|
+
return { message: 'Hello World!' };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
199
200
|
`;
|
|
200
201
|
}
|
|
201
202
|
function homeControllerTemplate() {
|
|
202
|
-
return `
|
|
203
|
-
import { ApiController, Get } from '@avleon/core';
|
|
204
|
-
import { HomeService } from '../services/home.service';
|
|
205
|
-
|
|
206
|
-
@ApiController('/')
|
|
207
|
-
export class HomeController {
|
|
208
|
-
constructor(private readonly homeService: HomeService) {}
|
|
209
|
-
|
|
210
|
-
@Get()
|
|
211
|
-
sayHello() {
|
|
212
|
-
return this.homeService.sayHello();
|
|
213
|
-
}
|
|
214
|
-
}
|
|
203
|
+
return `
|
|
204
|
+
import { ApiController, Get } from '@avleon/core';
|
|
205
|
+
import { HomeService } from '../services/home.service';
|
|
206
|
+
|
|
207
|
+
@ApiController('/')
|
|
208
|
+
export class HomeController {
|
|
209
|
+
constructor(private readonly homeService: HomeService) {}
|
|
210
|
+
|
|
211
|
+
@Get()
|
|
212
|
+
sayHello() {
|
|
213
|
+
return this.homeService.sayHello();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
215
216
|
`;
|
|
216
217
|
}
|
|
217
218
|
function homeControllerTestTemplate() {
|
|
218
|
-
return `
|
|
219
|
-
import { AvleonTest } from '@avleon/core';
|
|
220
|
-
import { HomeController } from './home.controller';
|
|
221
|
-
|
|
222
|
-
describe('HomeController', () => {
|
|
223
|
-
let controller!: HomeController;
|
|
224
|
-
|
|
225
|
-
beforeAll(() => {
|
|
226
|
-
controller = AvleonTest.getController(HomeController);
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it('should be defined', () => {
|
|
230
|
-
expect(controller).toBeDefined();
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it('should have sayHello method', () => {
|
|
234
|
-
expect(typeof controller.sayHello).toBe('function');
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
it('should return hello message', () => {
|
|
238
|
-
expect(controller.sayHello()).toEqual({ message: 'Hello World!' });
|
|
239
|
-
});
|
|
240
|
-
});
|
|
219
|
+
return `
|
|
220
|
+
import { AvleonTest } from '@avleon/core';
|
|
221
|
+
import { HomeController } from './home.controller';
|
|
222
|
+
|
|
223
|
+
describe('HomeController', () => {
|
|
224
|
+
let controller!: HomeController;
|
|
225
|
+
|
|
226
|
+
beforeAll(() => {
|
|
227
|
+
controller = AvleonTest.getController(HomeController);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should be defined', () => {
|
|
231
|
+
expect(controller).toBeDefined();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should have sayHello method', () => {
|
|
235
|
+
expect(typeof controller.sayHello).toBe('function');
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('should return hello message', () => {
|
|
239
|
+
expect(controller.sayHello()).toEqual({ message: 'Hello World!' });
|
|
240
|
+
});
|
|
241
|
+
});
|
|
241
242
|
`;
|
|
242
243
|
}
|
|
243
244
|
function openApiConfigTemplate(fname, useScalar) {
|
|
244
|
-
return `
|
|
245
|
-
import { AppConfig, Environment,
|
|
246
|
-
|
|
247
|
-
@AppConfig
|
|
248
|
-
export class OpenApiConfig
|
|
249
|
-
config(env: Environment) {
|
|
250
|
-
return {
|
|
251
|
-
info: {
|
|
252
|
-
title: '${(0, lodash_1.capitalize)(fname)} API',
|
|
253
|
-
version: '0.0.1',
|
|
254
|
-
description: 'API documentation for ${(0, lodash_1.capitalize)(fname)}',
|
|
255
|
-
},
|
|
256
|
-
${useScalar ? "provider: 'scalar'," : ''}
|
|
257
|
-
routePrefix: '/docs',
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
}
|
|
245
|
+
return `
|
|
246
|
+
import { AppConfig, AvleonConfig, Environment, OpenApiUiOptions } from '@avleon/core';
|
|
247
|
+
|
|
248
|
+
@AppConfig
|
|
249
|
+
export class OpenApiConfig extends AvleonConfig<OpenApiUiOptions> {
|
|
250
|
+
config(env: Environment): OpenApiUiOptions {
|
|
251
|
+
return {
|
|
252
|
+
info: {
|
|
253
|
+
title: '${(0, lodash_1.capitalize)(fname)} API',
|
|
254
|
+
version: '0.0.1',
|
|
255
|
+
description: 'API documentation for ${(0, lodash_1.capitalize)(fname)}',
|
|
256
|
+
},
|
|
257
|
+
${useScalar ? "provider: 'scalar'," : ''}
|
|
258
|
+
routePrefix: '/docs',
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
261
262
|
`;
|
|
262
263
|
}
|
|
263
264
|
function appTemplate(features) {
|
|
264
265
|
const hasOpenApi = features.includes('openapi');
|
|
265
266
|
const hasCors = features.includes('cors');
|
|
266
267
|
const hasTypeorm = features.includes('typeorm');
|
|
268
|
+
const hasKnex = features.includes('knex');
|
|
267
269
|
const imports = [`import { Avleon } from '@avleon/core';`];
|
|
268
270
|
imports.push(`import { HomeController } from './controllers/home.controller';`);
|
|
269
271
|
if (hasOpenApi) {
|
|
@@ -280,8 +282,13 @@ function appTemplate(features) {
|
|
|
280
282
|
body.push('');
|
|
281
283
|
}
|
|
282
284
|
if (hasTypeorm) {
|
|
283
|
-
body.push(`// TODO:
|
|
284
|
-
body.push(`// app.
|
|
285
|
+
body.push(`// TODO: pass your TypeORM DataSourceOptions (or an @AppConfig class)`);
|
|
286
|
+
body.push(`// await app.useTypeORM({ type: 'postgres', url: process.env.DATABASE_URL, entities: [] });`);
|
|
287
|
+
body.push('');
|
|
288
|
+
}
|
|
289
|
+
if (hasKnex) {
|
|
290
|
+
body.push(`// TODO: pass your Knex config (or an @AppConfig class)`);
|
|
291
|
+
body.push(`// await app.useKnex({ client: 'pg', connection: process.env.DATABASE_URL });`);
|
|
285
292
|
body.push('');
|
|
286
293
|
}
|
|
287
294
|
body.push(`app.useControllers([HomeController]);`);
|
|
@@ -290,14 +297,17 @@ function appTemplate(features) {
|
|
|
290
297
|
return `${imports.join('\n')}\n\n${body.join('\n')}\n`;
|
|
291
298
|
}
|
|
292
299
|
function serveTemplate() {
|
|
293
|
-
return `
|
|
294
|
-
import
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
300
|
+
return `
|
|
301
|
+
import { Environment, inject } from '@avleon/core';
|
|
302
|
+
import app from './app';
|
|
303
|
+
|
|
304
|
+
async function start() {
|
|
305
|
+
const env = inject(Environment);
|
|
306
|
+
const port = env.get<number>('PORT') || 4000;
|
|
307
|
+
await app.run(port);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
start();
|
|
301
311
|
`;
|
|
302
312
|
}
|
|
303
313
|
function packageJsonTemplate(fname, features) {
|
|
@@ -318,6 +328,10 @@ function packageJsonTemplate(fname, features) {
|
|
|
318
328
|
deps['typeorm'] = resolveDepVersion('typeorm', '^0.3.20');
|
|
319
329
|
deps['pg'] = resolveDepVersion('pg', '^8.11.0');
|
|
320
330
|
}
|
|
331
|
+
if (features.includes('knex')) {
|
|
332
|
+
deps['knex'] = resolveDepVersion('knex', '^3.1.0');
|
|
333
|
+
deps['pg'] = resolveDepVersion('pg', '^8.11.0');
|
|
334
|
+
}
|
|
321
335
|
if (features.includes('scalar')) {
|
|
322
336
|
deps['@scalar/fastify-api-reference'] = resolveDepVersion('@scalar/fastify-api-reference', '^1.0.0');
|
|
323
337
|
}
|
|
@@ -399,35 +413,35 @@ function envTemplate() {
|
|
|
399
413
|
}
|
|
400
414
|
function readmeTemplate(fname, pm) {
|
|
401
415
|
const runCmd = pm === 'npm' ? 'npm run start:dev' : `${pm} start:dev`;
|
|
402
|
-
return `# ${(0, lodash_1.capitalize)(fname)}
|
|
403
|
-
|
|
404
|
-
Built with [Avleon](https://github.com/xtareq/avleon).
|
|
405
|
-
|
|
406
|
-
## Getting Started
|
|
407
|
-
|
|
408
|
-
\`\`\`bash
|
|
409
|
-
${runCmd}
|
|
410
|
-
\`\`\`
|
|
411
|
-
|
|
412
|
-
## Scripts
|
|
413
|
-
|
|
414
|
-
| Script | Description |
|
|
415
|
-
|--------|-------------|
|
|
416
|
-
| \`start:dev\` | Start development server with hot reload |
|
|
417
|
-
| \`build\` | Compile TypeScript to JavaScript |
|
|
418
|
-
| \`start\` | Start production server |
|
|
419
|
-
| \`test\` | Run unit tests |
|
|
420
|
-
|
|
421
|
-
## Project Structure
|
|
422
|
-
|
|
423
|
-
\`\`\`
|
|
424
|
-
src/
|
|
425
|
-
├── controllers/ # Route controllers
|
|
426
|
-
├── services/ # Business logic
|
|
427
|
-
├── config/ # App configuration
|
|
428
|
-
├── app.ts # App setup
|
|
429
|
-
└── serve.ts # Entry point
|
|
430
|
-
\`\`\`
|
|
416
|
+
return `# ${(0, lodash_1.capitalize)(fname)}
|
|
417
|
+
|
|
418
|
+
Built with [Avleon](https://github.com/xtareq/avleon).
|
|
419
|
+
|
|
420
|
+
## Getting Started
|
|
421
|
+
|
|
422
|
+
\`\`\`bash
|
|
423
|
+
${runCmd}
|
|
424
|
+
\`\`\`
|
|
425
|
+
|
|
426
|
+
## Scripts
|
|
427
|
+
|
|
428
|
+
| Script | Description |
|
|
429
|
+
|--------|-------------|
|
|
430
|
+
| \`start:dev\` | Start development server with hot reload |
|
|
431
|
+
| \`build\` | Compile TypeScript to JavaScript |
|
|
432
|
+
| \`start\` | Start production server |
|
|
433
|
+
| \`test\` | Run unit tests |
|
|
434
|
+
|
|
435
|
+
## Project Structure
|
|
436
|
+
|
|
437
|
+
\`\`\`
|
|
438
|
+
src/
|
|
439
|
+
├── controllers/ # Route controllers
|
|
440
|
+
├── services/ # Business logic
|
|
441
|
+
├── config/ # App configuration
|
|
442
|
+
├── app.ts # App setup
|
|
443
|
+
└── serve.ts # Entry point
|
|
444
|
+
\`\`\`
|
|
431
445
|
`;
|
|
432
446
|
}
|
|
433
447
|
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
@@ -5,9 +5,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.pathHelper = void 0;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the package root (the directory holding `stubs/`) by walking up from
|
|
11
|
+
* this file. Compiled output lives under `dist/`, at a depth that differs per
|
|
12
|
+
* file, so anchoring on a fixed number of `..` segments is not reliable.
|
|
13
|
+
*/
|
|
14
|
+
function packageRoot() {
|
|
15
|
+
let dir = __dirname;
|
|
16
|
+
for (let i = 0; i < 5; i++) {
|
|
17
|
+
if ((0, fs_1.existsSync)(path_1.default.join(dir, 'stubs')))
|
|
18
|
+
return dir;
|
|
19
|
+
const parent = path_1.default.dirname(dir);
|
|
20
|
+
if (parent === dir)
|
|
21
|
+
break;
|
|
22
|
+
dir = parent;
|
|
23
|
+
}
|
|
24
|
+
return path_1.default.join(__dirname, '../..');
|
|
25
|
+
}
|
|
11
26
|
exports.pathHelper = {
|
|
12
27
|
appSoucePath(p) {
|
|
13
28
|
return path_1.default.join(process.cwd(), p ? './src/' + p : './src/');
|
|
@@ -16,6 +31,6 @@ exports.pathHelper = {
|
|
|
16
31
|
return path_1.default.join(process.cwd(), p ? './test/' + p : './test/');
|
|
17
32
|
},
|
|
18
33
|
stubPath(p) {
|
|
19
|
-
return path_1.default.join(
|
|
34
|
+
return path_1.default.join(packageRoot(), 'stubs', p ?? '');
|
|
20
35
|
},
|
|
21
36
|
};
|
package/dist/service.js
CHANGED
|
@@ -20,10 +20,10 @@ function lower(str) {
|
|
|
20
20
|
}
|
|
21
21
|
const servicesStubs = {
|
|
22
22
|
basic: path_helper_1.pathHelper.stubPath('services/basic-service.stub'),
|
|
23
|
-
rest: path_helper_1.pathHelper.stubPath('services/
|
|
23
|
+
rest: path_helper_1.pathHelper.stubPath('services/rest-service.stub'),
|
|
24
24
|
ormRest: path_helper_1.pathHelper.stubPath('services/orm-rest-service.stub')
|
|
25
25
|
};
|
|
26
|
-
async function createService(name, options = { force: false, resource: false, prefix: true, rest: false, model: null, root: null }, p) {
|
|
26
|
+
async function createService(name, options = { force: false, resource: false, prefix: true, rest: false, model: null, root: null, orm: false }, p) {
|
|
27
27
|
if (!name) {
|
|
28
28
|
throw new Error("Service name not found. use --name or npx avleon make:service HomeService");
|
|
29
29
|
}
|
|
@@ -32,17 +32,13 @@ async function createService(name, options = { force: false, resource: false, pr
|
|
|
32
32
|
}
|
|
33
33
|
// determine stub for generate
|
|
34
34
|
let stubPath = servicesStubs.basic;
|
|
35
|
-
if (options.rest) {
|
|
36
|
-
stubPath = servicesStubs.rest;
|
|
37
|
-
if (options.model) {
|
|
38
|
-
stubPath = servicesStubs.ormRest;
|
|
39
|
-
}
|
|
35
|
+
if (options.rest || options.resource) {
|
|
36
|
+
stubPath = options.orm ? servicesStubs.ormRest : servicesStubs.rest;
|
|
40
37
|
}
|
|
41
38
|
const rootPath = options.root ? 'src/' + options.root + '/' : 'src/services/';
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
39
|
+
const outDir = path_1.default.join(rootPath, (0, file_helper_1.getFilePathWithoutName)(name));
|
|
40
|
+
if (!(0, fs_1.existsSync)(outDir)) {
|
|
41
|
+
await promises_1.default.mkdir(outDir, { recursive: true });
|
|
46
42
|
}
|
|
47
43
|
const content = await promises_1.default.readFile(stubPath, 'utf8');
|
|
48
44
|
const names = (0, file_helper_1.resolveNames)(file_helper_1.fh.filenameFromPath(name), 'Service');
|
|
@@ -55,8 +51,8 @@ async function createService(name, options = { force: false, resource: false, pr
|
|
|
55
51
|
.replaceAll('{Model}', capitalize(options.model))
|
|
56
52
|
.replaceAll('{model}', lower(options.model));
|
|
57
53
|
}
|
|
58
|
-
await promises_1.default.writeFile(path_1.default.join(
|
|
59
|
-
console.log("Service created
|
|
54
|
+
await promises_1.default.writeFile(path_1.default.join(outDir, (0, lodash_1.kebabCase)(className) + '.service.ts'), replacedContent, 'utf8');
|
|
55
|
+
console.log("Service created successfully!");
|
|
60
56
|
}
|
|
61
57
|
async function createRestService(name, model) {
|
|
62
58
|
let stubPath = path_helper_1.pathHelper.stubPath('services/rest-service.stub');
|
package/package.json
CHANGED
|
@@ -1,61 +1,62 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@avleon/cli",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "CLI for scaffolding and running Avleon applications",
|
|
5
|
-
"author": "Tareq Hossain",
|
|
6
|
-
"license": "ISC",
|
|
7
|
-
"main": "dist/index.js",
|
|
8
|
-
"types": "dist/index.d.ts",
|
|
9
|
-
"bin": {
|
|
10
|
-
"avleon": "./dist/cli.js"
|
|
11
|
-
},
|
|
12
|
-
"files": [
|
|
13
|
-
"dist",
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"@
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"@
|
|
43
|
-
"@types/
|
|
44
|
-
"@types/
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@avleon/cli",
|
|
3
|
+
"version": "0.0.47",
|
|
4
|
+
"description": "CLI for scaffolding and running Avleon applications",
|
|
5
|
+
"author": "Tareq Hossain",
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"avleon": "./dist/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"stubs",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "rimraf dist && tsc",
|
|
19
|
+
"clean": "rimraf dist",
|
|
20
|
+
"prepublishOnly": "npm run build",
|
|
21
|
+
"watch": "tsc-watch --onSuccess \"echo Build complete\""
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"cli",
|
|
25
|
+
"avleon",
|
|
26
|
+
"backend",
|
|
27
|
+
"typescript"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@avleon/core": "*",
|
|
31
|
+
"@swc/core": "^1.13.5",
|
|
32
|
+
"chokidar": "^4.0.3",
|
|
33
|
+
"chalk": "^5.4.1",
|
|
34
|
+
"cli-table3": "^0.6.5",
|
|
35
|
+
"fs-extra": "^11.2.0",
|
|
36
|
+
"inquirer": "^12.6.0",
|
|
37
|
+
"lodash": "^4.17.21",
|
|
38
|
+
"prettier": "^3.3.3",
|
|
39
|
+
"rimraf": "^6.0.1"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@swc/cli": "^0.7.8",
|
|
43
|
+
"@types/fs-extra": "^11.0.4",
|
|
44
|
+
"@types/lodash": "^4.17.16",
|
|
45
|
+
"@types/node": "^22.9.3",
|
|
46
|
+
"concurrently": "^9.2.1",
|
|
47
|
+
"nodemon": "^3.1.7",
|
|
48
|
+
"tsc-watch": "^6.2.1",
|
|
49
|
+
"tsup": "^8.4.0",
|
|
50
|
+
"typescript": "^5.7.2"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@avleon/core": ">=0.0.38"
|
|
54
|
+
},
|
|
55
|
+
"repository": {
|
|
56
|
+
"type": "git",
|
|
57
|
+
"url": "git+https://github.com/avleonjs/avleon-cli"
|
|
58
|
+
},
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public"
|
|
61
|
+
}
|
|
62
|
+
}
|
package/readme.md
CHANGED
|
@@ -1,66 +1,116 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
>
|
|
5
|
-
>
|
|
6
|
-
>
|
|
7
|
-
>
|
|
8
|
-
>
|
|
9
|
-
>
|
|
10
|
-
>
|
|
11
|
-
> -
|
|
12
|
-
> -
|
|
13
|
-
> -
|
|
14
|
-
>
|
|
15
|
-
>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
npx avleon
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
|
|
1
|
+
### ⚠️ WARNING: NOT FOR PRODUCTION USE
|
|
2
|
+
|
|
3
|
+
> **🚧 This project is in active development.**
|
|
4
|
+
>
|
|
5
|
+
> It is **not stable** and **not ready** for live environments.
|
|
6
|
+
> Use **only for testing, experimentation, or internal evaluation**.
|
|
7
|
+
>
|
|
8
|
+
> #### ❗ Risks of using this in production:
|
|
9
|
+
>
|
|
10
|
+
> - 🔄 Breaking changes may be introduced at any time
|
|
11
|
+
> - 🧪 Features are experimental and may be unstable
|
|
12
|
+
> - 🔐 Security has not been audited
|
|
13
|
+
> - 💥 Potential for data loss or critical errors
|
|
14
|
+
>
|
|
15
|
+
> **Please do not deploy this in production environments.**
|
|
16
|
+
|
|
17
|
+
# Avleon CLI
|
|
18
|
+
|
|
19
|
+
Scaffold and run [Avleon](https://github.com/avleonjs/avleon-core) applications.
|
|
20
|
+
|
|
21
|
+
## Create an Application
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npx @avleon/cli new my_api
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
You are prompted for a package manager and for optional features (OpenAPI,
|
|
28
|
+
CORS, TypeORM, Knex, Scalar UI). The generated project uses `@avleon/core`'s
|
|
29
|
+
`Avleon.createApplication()` and is ready to run:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
cd my_api
|
|
33
|
+
npm run start:dev
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Commands
|
|
37
|
+
|
|
38
|
+
| Command | Alias | Options | Description |
|
|
39
|
+
|---------|-------|---------|-------------|
|
|
40
|
+
| `new` | | `--minimal`, `-m` | Create a new application |
|
|
41
|
+
| `serve` | | | Start the dev server with watch + rebuild |
|
|
42
|
+
| `build` | | | Compile with `tsconfig.build.json` |
|
|
43
|
+
| `make:model` | `m:m` | `-f`, `--orm` | Create a model / TypeORM entity |
|
|
44
|
+
| `make:controller` | `m:c` | `-f`, `-r`, `-m <model>`, `-rt <dir>`, `--orm`, `--base-path` | Create a controller |
|
|
45
|
+
| `make:service` | `m:s` | `-f`, `-r`, `-m <model>`, `-rt <dir>`, `--orm` | Create a service |
|
|
46
|
+
| `make:config` | `m:cnf` | `-f` | Create a config class |
|
|
47
|
+
| `make:middleware` | `m:mlwr` | `-f` | Create a middleware |
|
|
48
|
+
|
|
49
|
+
`-f` / `--force` overwrites an existing file. `-r` / `--resource` generates a
|
|
50
|
+
full REST skeleton.
|
|
51
|
+
|
|
52
|
+
### Controller
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
npx avleon make:controller product
|
|
56
|
+
# shorthand
|
|
57
|
+
npx avleon m:c product
|
|
58
|
+
|
|
59
|
+
# REST controller — also generates the matching service
|
|
60
|
+
npx avleon m:c product -m product -r
|
|
61
|
+
|
|
62
|
+
# REST controller backed by a TypeORM repository
|
|
63
|
+
npx avleon m:c product -m product -r --orm
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
With `-m`, the generated controller delegates to `src/services/<model>.service.ts`,
|
|
67
|
+
which is created alongside it.
|
|
68
|
+
|
|
69
|
+
### Model / Entity
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
# plain class
|
|
73
|
+
npx avleon make:model product
|
|
74
|
+
|
|
75
|
+
# TypeORM entity
|
|
76
|
+
npx avleon m:m product --orm
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Service
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
# basic service
|
|
83
|
+
npx avleon make:service product
|
|
84
|
+
|
|
85
|
+
# resource service backed by an in-memory Collection
|
|
86
|
+
npx avleon make:service product -m product -r
|
|
87
|
+
|
|
88
|
+
# resource service backed by a TypeORM repository
|
|
89
|
+
npx avleon make:service product -m product -r --orm
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Middleware
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
npx avleon make:middleware auth
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Generates a class extending `AvleonMiddleware` with an `invoke(req, res)` method.
|
|
99
|
+
|
|
100
|
+
### Config
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
npx avleon make:config jwt
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Generates a class extending `AvleonConfig`, registered via `@AppConfig`.
|
|
107
|
+
|
|
108
|
+
## Development Server
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
npx avleon serve
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Compiles `src/` with SWC into `dist/`, starts the entry point, and restarts on
|
|
115
|
+
change. The entry file is taken from `avleon.entry` in `package.json`, falling
|
|
116
|
+
back to `main`.
|