@avleon/cli 0.0.47 → 0.4.0
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/LICENSE +21 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +10 -0
- package/dist/commands/build.d.ts +11 -0
- package/dist/commands/build.js +65 -0
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.js +96 -0
- package/dist/commands/new.d.ts +19 -0
- package/dist/commands/new.js +306 -0
- package/dist/commands/route-list.d.ts +19 -0
- package/dist/commands/route-list.js +160 -0
- package/dist/commands/serve.d.ts +17 -0
- package/dist/commands/serve.js +238 -0
- package/dist/commands/start.d.ts +10 -0
- package/dist/commands/start.js +43 -0
- package/dist/compiler.d.ts +24 -0
- package/dist/compiler.js +83 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +16 -0
- package/dist/generators/make.d.ts +24 -0
- package/dist/generators/make.js +157 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +40 -15
- package/dist/program.d.ts +22 -0
- package/dist/program.js +178 -0
- package/dist/utils/entry.d.ts +15 -0
- package/dist/utils/entry.js +55 -0
- package/dist/utils/env-types.d.ts +8 -0
- package/dist/utils/env-types.js +19 -0
- package/dist/utils/log.d.ts +25 -0
- package/dist/utils/log.js +39 -0
- package/dist/utils/names.d.ts +27 -0
- package/dist/utils/names.js +58 -0
- package/dist/utils/process.d.ts +18 -0
- package/dist/utils/process.js +84 -0
- package/dist/utils/project.d.ts +17 -0
- package/dist/utils/project.js +91 -0
- package/dist/utils/stubs.d.ts +15 -0
- package/dist/utils/stubs.js +52 -0
- package/dist/utils/tsconfig.d.ts +13 -0
- package/dist/utils/tsconfig.js +102 -0
- package/package.json +28 -27
- package/readme.md +50 -11
- package/stubs/config/config.stub +9 -0
- package/stubs/controllers/basic-controller.stub +3 -3
- package/stubs/controllers/resource-controller.stub +45 -0
- package/stubs/controllers/rest-controller.stub +2 -2
- package/stubs/dtos/dto.stub +11 -0
- package/stubs/middlewares/middleware.stub +9 -0
- package/stubs/models/basic-model.stub +2 -2
- package/stubs/models/entity-model.stub +6 -8
- package/stubs/{app → project}/app-minimal.stub +1 -1
- package/stubs/{app/app-controller.stub → project/app.stub} +2 -7
- package/stubs/project/env.stub +3 -0
- package/stubs/project/gitignore.stub +5 -0
- package/stubs/project/home.controller.spec.stub +19 -0
- package/stubs/project/home.controller.stub +12 -0
- package/stubs/project/home.service.stub +8 -0
- package/stubs/{config.stub → project/openapi.config.stub} +4 -4
- package/stubs/project/readme.stub +26 -0
- package/stubs/{serve.stub → project/serve.stub} +1 -1
- package/stubs/project/tsconfig.build.stub +4 -0
- package/stubs/project/tsconfig.stub +18 -0
- package/stubs/project/vitest-e2e.config.stub +10 -0
- package/stubs/project/vitest.config.stub +17 -0
- package/stubs/services/basic-service.stub +1 -1
- package/stubs/services/orm-rest-service.stub +15 -14
- package/stubs/services/rest-service.stub +9 -9
- package/dist/av-cli.js +0 -60
- package/dist/avcli.js +0 -26
- package/dist/cli.interface.js +0 -2
- package/dist/cli.js +0 -332
- package/dist/commands.js +0 -63
- package/dist/controller.js +0 -96
- package/dist/create.js +0 -512
- package/dist/helpers/file-helper.js +0 -30
- package/dist/helpers/path-helper.js +0 -36
- package/dist/paths.js +0 -32
- package/dist/scripts/serve.js +0 -290
- package/dist/serve.js +0 -311
- package/dist/service.js +0 -69
- package/stubs/controllers/orm-rest-controller.stub +0 -45
package/dist/create.js
DELETED
|
@@ -1,512 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.createApplication = createApplication;
|
|
40
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
41
|
-
const paths_1 = require("./paths");
|
|
42
|
-
const prettier = __importStar(require("prettier"));
|
|
43
|
-
const path_1 = __importDefault(require("path"));
|
|
44
|
-
const os_1 = __importDefault(require("os"));
|
|
45
|
-
const inquirer_1 = __importDefault(require("inquirer"));
|
|
46
|
-
const child_process_1 = require("child_process");
|
|
47
|
-
const lodash_1 = require("lodash");
|
|
48
|
-
// ─── Colors ───────────────────────────────────────────────────────────────────
|
|
49
|
-
const C = {
|
|
50
|
-
reset: '\x1b[0m',
|
|
51
|
-
dim: '\x1b[90m',
|
|
52
|
-
bold: '\x1b[1m',
|
|
53
|
-
cyan: '\x1b[36m',
|
|
54
|
-
green: '\x1b[32m',
|
|
55
|
-
yellow: '\x1b[33m',
|
|
56
|
-
red: '\x1b[31m',
|
|
57
|
-
white: '\x1b[37m',
|
|
58
|
-
};
|
|
59
|
-
const icon = {
|
|
60
|
-
success: `${C.green}✔${C.reset}`,
|
|
61
|
-
error: `${C.red}✖${C.reset}`,
|
|
62
|
-
warn: `${C.yellow}⚠${C.reset}`,
|
|
63
|
-
arrow: `${C.dim}→${C.reset}`,
|
|
64
|
-
};
|
|
65
|
-
function step(label, detail) {
|
|
66
|
-
const pad = label.padEnd(30, ' ');
|
|
67
|
-
console.log(` ${icon.arrow} ${C.white}${pad}${C.reset}${detail ? C.dim + detail + C.reset : ''}`);
|
|
68
|
-
}
|
|
69
|
-
function success(msg) {
|
|
70
|
-
console.log(` ${icon.success} ${C.green}${msg}${C.reset}`);
|
|
71
|
-
}
|
|
72
|
-
function fail(msg) {
|
|
73
|
-
console.log(` ${icon.error} ${C.red}${msg}${C.reset}`);
|
|
74
|
-
}
|
|
75
|
-
function section(title) {
|
|
76
|
-
console.log(`\n${C.bold}${C.cyan} ${title}${C.reset}`);
|
|
77
|
-
console.log(` ${'─'.repeat(40)}`);
|
|
78
|
-
}
|
|
79
|
-
// ─── Version resolver ─────────────────────────────────────────────────────────
|
|
80
|
-
function resolveDepVersion(pkgName, fallback = 'latest') {
|
|
81
|
-
try {
|
|
82
|
-
const pkgJsonPath = require.resolve(`${pkgName}/package.json`);
|
|
83
|
-
const pkg = JSON.parse(fs_extra_1.default.readFileSync(pkgJsonPath, 'utf8'));
|
|
84
|
-
return `^${pkg.version}`;
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
return fallback;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
function getAvleonVersions() {
|
|
91
|
-
try {
|
|
92
|
-
// Read CLI's own package.json (this file lives inside @avleon/cli)
|
|
93
|
-
const cliPkgPath = path_1.default.resolve(__dirname, '../../package.json');
|
|
94
|
-
const cliPkg = JSON.parse(fs_extra_1.default.readFileSync(cliPkgPath, 'utf8'));
|
|
95
|
-
// Core version — resolve from installed node_modules
|
|
96
|
-
const corePkgPath = require.resolve('@avleon/core/package.json');
|
|
97
|
-
const corePkg = JSON.parse(fs_extra_1.default.readFileSync(corePkgPath, 'utf8'));
|
|
98
|
-
return {
|
|
99
|
-
core: `^${corePkg.version}`,
|
|
100
|
-
cli: `^${cliPkg.version}`,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
return { core: 'latest', cli: 'latest' };
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// ─── Banner ───────────────────────────────────────────────────────────────────
|
|
108
|
-
function banner(fname) {
|
|
109
|
-
const { core } = getAvleonVersions();
|
|
110
|
-
console.clear();
|
|
111
|
-
console.log();
|
|
112
|
-
console.log(`${C.bold}${C.cyan} ╔═══════════════════════════════════════╗${C.reset}`);
|
|
113
|
-
console.log(`${C.bold}${C.cyan} ║ AVLEON APPLICATION CLI ║${C.reset}`);
|
|
114
|
-
console.log(`${C.bold}${C.cyan} ╚═══════════════════════════════════════╝${C.reset}`);
|
|
115
|
-
console.log();
|
|
116
|
-
console.log(` ${C.dim}Creating project :${C.reset} ${C.bold}${C.white}${fname}${C.reset}`);
|
|
117
|
-
console.log(` ${C.dim}Avleon version :${C.reset} ${C.bold}${C.cyan}${core}${C.reset}`);
|
|
118
|
-
console.log();
|
|
119
|
-
}
|
|
120
|
-
// ─── Shell ────────────────────────────────────────────────────────────────────
|
|
121
|
-
const getShell = () => os_1.default.platform() === 'win32'
|
|
122
|
-
? process.env.ComSpec || 'cmd.exe'
|
|
123
|
-
: process.env.SHELL || '/bin/sh';
|
|
124
|
-
// ─── Prompts ──────────────────────────────────────────────────────────────────
|
|
125
|
-
async function askForPackageManager() {
|
|
126
|
-
const { packageManager } = await inquirer_1.default.prompt([
|
|
127
|
-
{
|
|
128
|
-
type: 'list',
|
|
129
|
-
name: 'packageManager',
|
|
130
|
-
message: 'Package manager:',
|
|
131
|
-
choices: [
|
|
132
|
-
{ name: 'npm', value: 'npm' },
|
|
133
|
-
{ name: 'yarn', value: 'yarn' },
|
|
134
|
-
{ name: 'pnpm (recommended)', value: 'pnpm' },
|
|
135
|
-
],
|
|
136
|
-
default: 'npm',
|
|
137
|
-
},
|
|
138
|
-
]);
|
|
139
|
-
return packageManager;
|
|
140
|
-
}
|
|
141
|
-
async function askForFeatures() {
|
|
142
|
-
const { features } = await inquirer_1.default.prompt([
|
|
143
|
-
{
|
|
144
|
-
type: 'checkbox',
|
|
145
|
-
name: 'features',
|
|
146
|
-
message: 'Select features to include:',
|
|
147
|
-
choices: [
|
|
148
|
-
{ name: 'OpenAPI / Swagger docs', value: 'openapi', checked: true },
|
|
149
|
-
{ name: 'CORS support', value: 'cors', checked: false },
|
|
150
|
-
{ name: 'TypeORM', value: 'typeorm', checked: false },
|
|
151
|
-
{ name: 'Knex', value: 'knex', checked: false },
|
|
152
|
-
{ name: 'Scalar UI (replaces Swagger UI)', value: 'scalar', checked: false },
|
|
153
|
-
],
|
|
154
|
-
},
|
|
155
|
-
]);
|
|
156
|
-
return features;
|
|
157
|
-
}
|
|
158
|
-
// ─── Installer ────────────────────────────────────────────────────────────────
|
|
159
|
-
async function installDependencies(pm, cwd) {
|
|
160
|
-
return new Promise((resolve, reject) => {
|
|
161
|
-
const child = (0, child_process_1.spawn)(pm, ['install'], {
|
|
162
|
-
cwd,
|
|
163
|
-
shell: getShell(),
|
|
164
|
-
stdio: 'inherit',
|
|
165
|
-
});
|
|
166
|
-
child.on('exit', (code) => {
|
|
167
|
-
code === 0
|
|
168
|
-
? resolve()
|
|
169
|
-
: reject(new Error(`Install failed with exit code ${code}`));
|
|
170
|
-
});
|
|
171
|
-
child.on('error', reject);
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
// ─── Format helper ────────────────────────────────────────────────────────────
|
|
175
|
-
async function fmt(source, parser = 'typescript') {
|
|
176
|
-
return prettier.format(source, {
|
|
177
|
-
singleQuote: true,
|
|
178
|
-
singleAttributePerLine: true,
|
|
179
|
-
parser,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
// ─── File writer ──────────────────────────────────────────────────────────────
|
|
183
|
-
async function writeFile(filePath, content, label) {
|
|
184
|
-
await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
|
|
185
|
-
await fs_extra_1.default.writeFile(filePath, content);
|
|
186
|
-
if (label)
|
|
187
|
-
step(label, path_1.default.relative(process.cwd(), filePath));
|
|
188
|
-
}
|
|
189
|
-
// ─── Templates ────────────────────────────────────────────────────────────────
|
|
190
|
-
function homeServiceTemplate() {
|
|
191
|
-
return `
|
|
192
|
-
import { AppService } from '@avleon/core';
|
|
193
|
-
|
|
194
|
-
@AppService
|
|
195
|
-
export class HomeService {
|
|
196
|
-
sayHello() {
|
|
197
|
-
return { message: 'Hello World!' };
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
`;
|
|
201
|
-
}
|
|
202
|
-
function homeControllerTemplate() {
|
|
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
|
-
}
|
|
216
|
-
`;
|
|
217
|
-
}
|
|
218
|
-
function homeControllerTestTemplate() {
|
|
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
|
-
});
|
|
242
|
-
`;
|
|
243
|
-
}
|
|
244
|
-
function openApiConfigTemplate(fname, useScalar) {
|
|
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
|
-
}
|
|
262
|
-
`;
|
|
263
|
-
}
|
|
264
|
-
function appTemplate(features) {
|
|
265
|
-
const hasOpenApi = features.includes('openapi');
|
|
266
|
-
const hasCors = features.includes('cors');
|
|
267
|
-
const hasTypeorm = features.includes('typeorm');
|
|
268
|
-
const hasKnex = features.includes('knex');
|
|
269
|
-
const imports = [`import { Avleon } from '@avleon/core';`];
|
|
270
|
-
imports.push(`import { HomeController } from './controllers/home.controller';`);
|
|
271
|
-
if (hasOpenApi) {
|
|
272
|
-
imports.push(`import { OpenApiConfig } from './config/openapi.config';`);
|
|
273
|
-
}
|
|
274
|
-
const body = [`const app = Avleon.createApplication();`, ''];
|
|
275
|
-
if (hasCors) {
|
|
276
|
-
body.push(`app.useCors({ origin: '*' });`);
|
|
277
|
-
}
|
|
278
|
-
if (hasOpenApi) {
|
|
279
|
-
body.push(`if (app.isDevelopment()) {`);
|
|
280
|
-
body.push(` app.useOpenApi(OpenApiConfig);`);
|
|
281
|
-
body.push(`}`);
|
|
282
|
-
body.push('');
|
|
283
|
-
}
|
|
284
|
-
if (hasTypeorm) {
|
|
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 });`);
|
|
292
|
-
body.push('');
|
|
293
|
-
}
|
|
294
|
-
body.push(`app.useControllers([HomeController]);`);
|
|
295
|
-
body.push('');
|
|
296
|
-
body.push(`export default app;`);
|
|
297
|
-
return `${imports.join('\n')}\n\n${body.join('\n')}\n`;
|
|
298
|
-
}
|
|
299
|
-
function serveTemplate() {
|
|
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();
|
|
311
|
-
`;
|
|
312
|
-
}
|
|
313
|
-
function packageJsonTemplate(fname, features) {
|
|
314
|
-
// ✅ Always resolve current installed versions at generation time
|
|
315
|
-
const { core, cli } = getAvleonVersions();
|
|
316
|
-
const deps = {
|
|
317
|
-
'@avleon/core': core,
|
|
318
|
-
'@avleon/cli': cli,
|
|
319
|
-
'class-transformer': resolveDepVersion('class-transformer', '^0.5.1'),
|
|
320
|
-
'class-validator': resolveDepVersion('class-validator', '^0.14.1'),
|
|
321
|
-
'rimraf': resolveDepVersion('rimraf', '^6.0.1'),
|
|
322
|
-
'reflect-metadata': resolveDepVersion('reflect-metadata', '^0.2.2'),
|
|
323
|
-
};
|
|
324
|
-
if (features.includes('cors')) {
|
|
325
|
-
deps['@fastify/cors'] = resolveDepVersion('@fastify/cors', '^10.0.0');
|
|
326
|
-
}
|
|
327
|
-
if (features.includes('typeorm')) {
|
|
328
|
-
deps['typeorm'] = resolveDepVersion('typeorm', '^0.3.20');
|
|
329
|
-
deps['pg'] = resolveDepVersion('pg', '^8.11.0');
|
|
330
|
-
}
|
|
331
|
-
if (features.includes('knex')) {
|
|
332
|
-
deps['knex'] = resolveDepVersion('knex', '^3.1.0');
|
|
333
|
-
deps['pg'] = resolveDepVersion('pg', '^8.11.0');
|
|
334
|
-
}
|
|
335
|
-
if (features.includes('scalar')) {
|
|
336
|
-
deps['@scalar/fastify-api-reference'] = resolveDepVersion('@scalar/fastify-api-reference', '^1.0.0');
|
|
337
|
-
}
|
|
338
|
-
const devDeps = {
|
|
339
|
-
'@types/jest': resolveDepVersion('@types/jest', '^29.5.14'),
|
|
340
|
-
'@types/node': resolveDepVersion('@types/node', '^24.0.3'),
|
|
341
|
-
'jest': resolveDepVersion('jest', '^29.7.0'),
|
|
342
|
-
'ts-jest': resolveDepVersion('ts-jest', '^29.2.6'),
|
|
343
|
-
'typescript': resolveDepVersion('typescript', '^5.7.2'),
|
|
344
|
-
};
|
|
345
|
-
return JSON.stringify({
|
|
346
|
-
name: (0, lodash_1.kebabCase)(fname),
|
|
347
|
-
version: '0.0.1',
|
|
348
|
-
description: `${(0, lodash_1.capitalize)(fname)} API built with Avleon`,
|
|
349
|
-
main: 'dist/serve.js',
|
|
350
|
-
scripts: {
|
|
351
|
-
'start:dev': 'avleon serve',
|
|
352
|
-
'clean': 'rimraf ./dist',
|
|
353
|
-
'build': 'npm run clean && tsc --project ./tsconfig.build.json',
|
|
354
|
-
'start': 'node ./dist/serve.js',
|
|
355
|
-
'test': 'jest',
|
|
356
|
-
'test:watch': 'jest --watch',
|
|
357
|
-
'test:cov': 'jest --coverage',
|
|
358
|
-
'test:e2e': 'jest --config ./test/e2e-spec.json',
|
|
359
|
-
},
|
|
360
|
-
keywords: ['avleon', 'nodejs', 'typescript'],
|
|
361
|
-
license: 'ISC',
|
|
362
|
-
dependencies: deps,
|
|
363
|
-
devDependencies: devDeps,
|
|
364
|
-
jest: {
|
|
365
|
-
preset: 'ts-jest',
|
|
366
|
-
rootDir: 'src',
|
|
367
|
-
testRegex: '.*.spec.ts$',
|
|
368
|
-
collectCoverageFrom: ['**/*.(t|j)s'],
|
|
369
|
-
coverageDirectory: '../coverage',
|
|
370
|
-
testEnvironment: 'node',
|
|
371
|
-
},
|
|
372
|
-
}, null, 2);
|
|
373
|
-
}
|
|
374
|
-
function tsconfigTemplate() {
|
|
375
|
-
return JSON.stringify({
|
|
376
|
-
compilerOptions: {
|
|
377
|
-
target: 'ES2017',
|
|
378
|
-
module: 'CommonJS',
|
|
379
|
-
moduleResolution: 'node',
|
|
380
|
-
experimentalDecorators: true,
|
|
381
|
-
emitDecoratorMetadata: true,
|
|
382
|
-
outDir: './dist',
|
|
383
|
-
esModuleInterop: true,
|
|
384
|
-
allowSyntheticDefaultImports: true,
|
|
385
|
-
forceConsistentCasingInFileNames: true,
|
|
386
|
-
skipLibCheck: true,
|
|
387
|
-
strict: false,
|
|
388
|
-
},
|
|
389
|
-
include: ['src/**/*'],
|
|
390
|
-
exclude: ['node_modules', 'dist'],
|
|
391
|
-
}, null, 2);
|
|
392
|
-
}
|
|
393
|
-
function tsconfigBuildTemplate() {
|
|
394
|
-
return JSON.stringify({
|
|
395
|
-
extends: './tsconfig.json',
|
|
396
|
-
exclude: ['node_modules', 'coverage', 'test', 'dist', '**/*spec.ts'],
|
|
397
|
-
}, null, 2);
|
|
398
|
-
}
|
|
399
|
-
function e2eConfigTemplate() {
|
|
400
|
-
return JSON.stringify({
|
|
401
|
-
moduleFileExtensions: ['js', 'json', 'ts'],
|
|
402
|
-
rootDir: '.',
|
|
403
|
-
testEnvironment: 'node',
|
|
404
|
-
testRegex: '.e2e-spec.ts$',
|
|
405
|
-
transform: { '^.+\\.(t|j)s$': 'ts-jest' },
|
|
406
|
-
}, null, 2);
|
|
407
|
-
}
|
|
408
|
-
function gitignoreTemplate() {
|
|
409
|
-
return `node_modules/\ndist/\n.env\n.env.local\ncoverage/\n`;
|
|
410
|
-
}
|
|
411
|
-
function envTemplate() {
|
|
412
|
-
return `NODE_ENV=development\nPORT=4000\n`;
|
|
413
|
-
}
|
|
414
|
-
function readmeTemplate(fname, pm) {
|
|
415
|
-
const runCmd = pm === 'npm' ? 'npm run start:dev' : `${pm} start:dev`;
|
|
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
|
-
\`\`\`
|
|
445
|
-
`;
|
|
446
|
-
}
|
|
447
|
-
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
448
|
-
async function createApplication(fname, flags = {}) {
|
|
449
|
-
const appPaths = (0, paths_1.appPaths)(fname);
|
|
450
|
-
banner(fname);
|
|
451
|
-
// ── Prompts ───────────────────────────────────────────────────────────────
|
|
452
|
-
const pm = await askForPackageManager();
|
|
453
|
-
const features = await askForFeatures();
|
|
454
|
-
const useScalar = features.includes('scalar');
|
|
455
|
-
// ── Directories ───────────────────────────────────────────────────────────
|
|
456
|
-
section('Scaffolding project structure');
|
|
457
|
-
const dirs = [
|
|
458
|
-
appPaths.root + '/src',
|
|
459
|
-
appPaths.root + '/src/controllers',
|
|
460
|
-
appPaths.root + '/src/config',
|
|
461
|
-
appPaths.root + '/src/services',
|
|
462
|
-
appPaths.root + '/test',
|
|
463
|
-
appPaths.root + '/public',
|
|
464
|
-
];
|
|
465
|
-
for (const dir of dirs) {
|
|
466
|
-
await fs_extra_1.default.ensureDir(dir);
|
|
467
|
-
step('Created directory', path_1.default.relative(process.cwd(), dir));
|
|
468
|
-
}
|
|
469
|
-
// ── Source files ──────────────────────────────────────────────────────────
|
|
470
|
-
section('Generating source files');
|
|
471
|
-
await writeFile(path_1.default.join(appPaths.services, 'home.service.ts'), await fmt(homeServiceTemplate()), 'HomeService');
|
|
472
|
-
await writeFile(path_1.default.join(appPaths.controllers, 'home.controller.ts'), await fmt(homeControllerTemplate()), 'HomeController');
|
|
473
|
-
await writeFile(path_1.default.join(appPaths.controllers, 'home.controller.spec.ts'), await fmt(homeControllerTestTemplate()), 'HomeController spec');
|
|
474
|
-
if (features.includes('openapi')) {
|
|
475
|
-
await writeFile(path_1.default.join(appPaths.configs, 'openapi.config.ts'), await fmt(openApiConfigTemplate(fname, useScalar)), 'OpenApiConfig');
|
|
476
|
-
}
|
|
477
|
-
await writeFile(path_1.default.join(appPaths.src, 'app.ts'), await fmt(appTemplate(features)), 'app.ts');
|
|
478
|
-
await writeFile(path_1.default.join(appPaths.src, 'serve.ts'), await fmt(serveTemplate()), 'serve.ts');
|
|
479
|
-
// ── Config files ──────────────────────────────────────────────────────────
|
|
480
|
-
section('Generating config files');
|
|
481
|
-
await writeFile(path_1.default.join(appPaths.root, 'package.json'), await fmt(packageJsonTemplate(fname, features), 'json'), 'package.json');
|
|
482
|
-
await writeFile(path_1.default.join(appPaths.root, 'tsconfig.json'), await fmt(tsconfigTemplate(), 'json'), 'tsconfig.json');
|
|
483
|
-
await writeFile(path_1.default.join(appPaths.root, 'tsconfig.build.json'), await fmt(tsconfigBuildTemplate(), 'json'), 'tsconfig.build.json');
|
|
484
|
-
await writeFile(path_1.default.join(appPaths.root, 'test/e2e-spec.json'), await fmt(e2eConfigTemplate(), 'json'), 'e2e-spec.json');
|
|
485
|
-
await writeFile(path_1.default.join(appPaths.root, '.gitignore'), gitignoreTemplate(), '.gitignore');
|
|
486
|
-
await writeFile(path_1.default.join(appPaths.root, '.env'), envTemplate(), '.env');
|
|
487
|
-
await writeFile(path_1.default.join(appPaths.root, 'README.md'), readmeTemplate(fname, pm), 'README.md');
|
|
488
|
-
// ── Install ───────────────────────────────────────────────────────────────
|
|
489
|
-
section('Installing dependencies');
|
|
490
|
-
try {
|
|
491
|
-
await installDependencies(pm, appPaths.root);
|
|
492
|
-
success('Dependencies installed');
|
|
493
|
-
}
|
|
494
|
-
catch (error) {
|
|
495
|
-
fail(`Installation failed: ${error instanceof Error ? error.message : error}`);
|
|
496
|
-
console.log(`\n ${C.yellow}Install manually:${C.reset}`);
|
|
497
|
-
console.log(` ${C.dim}cd ${fname} && ${pm} install${C.reset}\n`);
|
|
498
|
-
}
|
|
499
|
-
// ── Done ──────────────────────────────────────────────────────────────────
|
|
500
|
-
const runCmd = pm === 'npm' ? 'npm run start:dev' : `${pm} start:dev`;
|
|
501
|
-
console.log();
|
|
502
|
-
console.log(`${C.bold}${C.green} ✔ Project created successfully!${C.reset}`);
|
|
503
|
-
console.log();
|
|
504
|
-
console.log(` ${C.dim}Next steps:${C.reset}`);
|
|
505
|
-
console.log(` ${C.cyan} cd ${fname}${C.reset}`);
|
|
506
|
-
console.log(` ${C.cyan} ${runCmd}${C.reset}`);
|
|
507
|
-
if (features.includes('openapi')) {
|
|
508
|
-
console.log();
|
|
509
|
-
console.log(` ${C.dim}API docs:${C.reset} ${C.white}http://localhost:4000/docs${C.reset}`);
|
|
510
|
-
}
|
|
511
|
-
console.log();
|
|
512
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
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 };
|
|
@@ -1,36 +0,0 @@
|
|
|
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
|
-
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
|
-
}
|
|
26
|
-
exports.pathHelper = {
|
|
27
|
-
appSoucePath(p) {
|
|
28
|
-
return path_1.default.join(process.cwd(), p ? './src/' + p : './src/');
|
|
29
|
-
},
|
|
30
|
-
appTestPath(p) {
|
|
31
|
-
return path_1.default.join(process.cwd(), p ? './test/' + p : './test/');
|
|
32
|
-
},
|
|
33
|
-
stubPath(p) {
|
|
34
|
-
return path_1.default.join(packageRoot(), 'stubs', p ?? '');
|
|
35
|
-
},
|
|
36
|
-
};
|
package/dist/paths.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
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.appPaths = exports.appPathsMinimal = void 0;
|
|
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;
|
|
18
|
-
const appPaths = (rootPath) => {
|
|
19
|
-
const root = rootPath ? rootPath : node_path_1.default.join(process.cwd(), "./");
|
|
20
|
-
return {
|
|
21
|
-
root: root,
|
|
22
|
-
src: node_path_1.default.join(root, "src"),
|
|
23
|
-
public: node_path_1.default.join(root, "public"),
|
|
24
|
-
test: node_path_1.default.join(root, "test"),
|
|
25
|
-
controllers: node_path_1.default.join(root, "src/controllers"),
|
|
26
|
-
models: node_path_1.default.join(root, "src/models"),
|
|
27
|
-
services: node_path_1.default.join(root, "src/services"),
|
|
28
|
-
dtos: node_path_1.default.join(root, "src/dtos"),
|
|
29
|
-
configs: node_path_1.default.join(root, "src/config")
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
exports.appPaths = appPaths;
|