fastnode-cli 0.5.0 → 0.6.1
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/index.js +146 -96
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
const child_process_1 = require("child_process");
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
|
-
const [, , command, resource, name] = process.argv;
|
|
10
|
+
const [, , command, resource, name, moduleName] = process.argv;
|
|
11
11
|
if (command === "create" && resource) {
|
|
12
12
|
createProject(resource);
|
|
13
13
|
}
|
|
@@ -15,151 +15,131 @@ else if (command === "serve" && resource) {
|
|
|
15
15
|
serveProject(resource);
|
|
16
16
|
}
|
|
17
17
|
else if (command === "generate" && resource === "controller" && name) {
|
|
18
|
-
generateController(name);
|
|
18
|
+
generateController(name, moduleName);
|
|
19
19
|
}
|
|
20
20
|
else {
|
|
21
21
|
printUsage();
|
|
22
22
|
}
|
|
23
23
|
function createProject(projectName) {
|
|
24
24
|
const projectDir = path_1.default.resolve(projectName);
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const srcDir = path_1.default.join(projectDir, "src");
|
|
26
|
+
const constantsDir = path_1.default.join(srcDir, "constants");
|
|
27
|
+
const controllersDir = path_1.default.join(srcDir, "controllers");
|
|
28
|
+
const servicesDir = path_1.default.join(srcDir, "services");
|
|
29
|
+
const helpersDir = path_1.default.join(srcDir, "helpers");
|
|
30
|
+
fs_1.default.mkdirSync(constantsDir, { recursive: true });
|
|
31
|
+
fs_1.default.mkdirSync(controllersDir, { recursive: true });
|
|
32
|
+
fs_1.default.mkdirSync(servicesDir, { recursive: true });
|
|
33
|
+
fs_1.default.mkdirSync(helpersDir, { recursive: true });
|
|
34
|
+
fs_1.default.writeFileSync(path_1.default.join(srcDir, "main.ts"), buildMainTemplate());
|
|
35
|
+
fs_1.default.writeFileSync(path_1.default.join(srcDir, "app.module.ts"), buildAppModuleTemplate(projectName));
|
|
36
|
+
fs_1.default.writeFileSync(path_1.default.join(controllersDir, "app.controller.ts"), buildAppControllerTemplate(projectName));
|
|
37
|
+
fs_1.default.writeFileSync(path_1.default.join(constantsDir, "config.ts"), buildConfigTemplate());
|
|
28
38
|
fs_1.default.writeFileSync(path_1.default.join(projectDir, "tsconfig.json"), `{
|
|
29
39
|
"compilerOptions": {
|
|
30
|
-
"target": "
|
|
31
|
-
"module": "
|
|
32
|
-
"
|
|
33
|
-
"
|
|
40
|
+
"target": "ES2022",
|
|
41
|
+
"module": "es2022",
|
|
42
|
+
"moduleResolution": "bundler",
|
|
43
|
+
"rootDir": "src",
|
|
44
|
+
"outDir": "dist",
|
|
34
45
|
"strict": true,
|
|
35
46
|
"esModuleInterop": true,
|
|
36
47
|
"experimentalDecorators": true,
|
|
37
48
|
"emitDecoratorMetadata": true,
|
|
38
|
-
"
|
|
49
|
+
"skipLibCheck": true,
|
|
50
|
+
"resolveJsonModule": true,
|
|
51
|
+
"types": ["node"]
|
|
39
52
|
},
|
|
40
|
-
"include": ["src"]
|
|
53
|
+
"include": ["src/**/*.ts"],
|
|
54
|
+
"exclude": ["dist", "node_modules"]
|
|
41
55
|
}
|
|
42
56
|
`);
|
|
43
57
|
fs_1.default.writeFileSync(path_1.default.join(projectDir, "package.json"), `{
|
|
44
58
|
"name": "${projectName}",
|
|
45
59
|
"version": "1.0.0",
|
|
46
|
-
"type": "
|
|
47
|
-
"main": "dist/index.js",
|
|
60
|
+
"type": "module",
|
|
48
61
|
"scripts": {
|
|
49
|
-
"dev": "tsx src
|
|
50
|
-
"build": "tsc",
|
|
51
|
-
"start": "node dist
|
|
62
|
+
"dev": "tsx watch src/main.ts",
|
|
63
|
+
"build": "tsc -p tsconfig.json",
|
|
64
|
+
"start": "node dist/main.js"
|
|
52
65
|
},
|
|
53
66
|
"dependencies": {
|
|
54
|
-
"fastnode-core": "
|
|
55
|
-
"reflect-metadata": "^0.
|
|
67
|
+
"fastnode-core": "^0.6.1",
|
|
68
|
+
"reflect-metadata": "^0.2.2"
|
|
56
69
|
},
|
|
57
70
|
"devDependencies": {
|
|
58
|
-
"
|
|
59
|
-
"
|
|
71
|
+
"@types/node": "^24.12.0",
|
|
72
|
+
"tsx": "^4.21.0",
|
|
73
|
+
"typescript": "^5.9.3"
|
|
60
74
|
}
|
|
61
75
|
}
|
|
62
76
|
`);
|
|
63
|
-
console.log(
|
|
77
|
+
console.log(`Project '${projectName}' created at ${projectDir}`);
|
|
64
78
|
}
|
|
65
79
|
function serveProject(projectName) {
|
|
66
|
-
const entry = path_1.default.resolve(process.cwd(),
|
|
80
|
+
const entry = path_1.default.resolve(process.cwd(), "src", "main.ts");
|
|
67
81
|
if (!fs_1.default.existsSync(entry)) {
|
|
68
|
-
console.error(
|
|
82
|
+
console.error(`Cannot find module at ${entry}`);
|
|
69
83
|
process.exit(1);
|
|
70
84
|
}
|
|
71
85
|
(0, child_process_1.execSync)(`npx tsx ${entry}`, { stdio: "inherit" });
|
|
72
86
|
}
|
|
73
|
-
function generateController(controllerName) {
|
|
87
|
+
function generateController(controllerName, moduleName) {
|
|
74
88
|
const normalizedName = toKebabCase(controllerName);
|
|
75
89
|
const className = `${toPascalCase(controllerName)}Controller`;
|
|
76
|
-
const
|
|
90
|
+
const moduleFile = resolveModuleFile(moduleName);
|
|
91
|
+
const controllerDir = path_1.default.resolve(process.cwd(), "src", "controllers");
|
|
77
92
|
const controllerFile = path_1.default.join(controllerDir, `${normalizedName}.controller.ts`);
|
|
78
93
|
fs_1.default.mkdirSync(controllerDir, { recursive: true });
|
|
79
94
|
if (fs_1.default.existsSync(controllerFile)) {
|
|
80
|
-
console.error(
|
|
95
|
+
console.error(`Controller already exists at ${controllerFile}`);
|
|
81
96
|
process.exit(1);
|
|
82
97
|
}
|
|
83
98
|
fs_1.default.writeFileSync(controllerFile, buildControllerTemplate(normalizedName));
|
|
84
|
-
|
|
85
|
-
console.log(
|
|
99
|
+
updateModuleControllers(moduleFile, className, normalizedName);
|
|
100
|
+
console.log(`Controller '${normalizedName}' created at ${controllerFile}`);
|
|
101
|
+
console.log(`Added ${className} to ${path_1.default.basename(moduleFile)}.`);
|
|
86
102
|
}
|
|
87
|
-
function buildMainTemplate(
|
|
88
|
-
const className = `${toPascalCase(projectName)}Controller`;
|
|
89
|
-
const moduleName = `${toPascalCase(projectName)}Module`;
|
|
103
|
+
function buildMainTemplate() {
|
|
90
104
|
return `import "reflect-metadata";
|
|
91
|
-
import {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
Controller,
|
|
95
|
-
EmitToClient,
|
|
96
|
-
ExecutionPolicy,
|
|
97
|
-
Get,
|
|
98
|
-
Module,
|
|
99
|
-
Param,
|
|
100
|
-
Post,
|
|
101
|
-
Query,
|
|
102
|
-
SocketController,
|
|
103
|
-
Subscribe,
|
|
104
|
-
createApp,
|
|
105
|
-
} from "fastnode-core";
|
|
106
|
-
|
|
107
|
-
@Controller("/${projectName}")
|
|
108
|
-
@ExecutionPolicy({ timeout: 5000 })
|
|
109
|
-
class ${className} {
|
|
110
|
-
@Get("/")
|
|
111
|
-
async hello(
|
|
112
|
-
@Query("name") name?: string,
|
|
113
|
-
@Context() ctx?: any
|
|
114
|
-
) {
|
|
115
|
-
await ctx?.sleep(25);
|
|
105
|
+
import { createApp } from "fastnode-core";
|
|
106
|
+
import { AppModule } from "./app.module.js";
|
|
107
|
+
import { API_CONFIG } from "./constants/config.js";
|
|
116
108
|
|
|
117
|
-
|
|
118
|
-
message: \`Hello from ${projectName}\${name ? \`, \${name}\` : ""}\`,
|
|
119
|
-
deadline: ctx?.snapshot?.().deadline,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
109
|
+
export const app = createApp([AppModule], {
|
|
122
110
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return {
|
|
129
|
-
|
|
130
|
-
include,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
111
|
+
}).listen({ port: API_CONFIG.port, host: API_CONFIG.host });
|
|
112
|
+
`;
|
|
113
|
+
}
|
|
114
|
+
function buildAppModuleTemplate(projectName) {
|
|
115
|
+
const controllerName = `${toPascalCase(projectName)}Controller`;
|
|
116
|
+
return `import { Module } from "fastnode-core";
|
|
117
|
+
import { ${controllerName} } from "./controllers/app.controller.js";
|
|
133
118
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
created: true,
|
|
138
|
-
};
|
|
139
|
-
}
|
|
119
|
+
@Module({ controllers: [${controllerName}] })
|
|
120
|
+
export class AppModule {}
|
|
121
|
+
`;
|
|
140
122
|
}
|
|
123
|
+
function buildAppControllerTemplate(projectName) {
|
|
124
|
+
const className = `${toPascalCase(projectName)}Controller`;
|
|
125
|
+
return `import { Controller, Get } from "fastnode-core";
|
|
141
126
|
|
|
142
|
-
@
|
|
143
|
-
class ${
|
|
144
|
-
@
|
|
145
|
-
|
|
146
|
-
ping(@Body("message") message?: string) {
|
|
127
|
+
@Controller("/")
|
|
128
|
+
export class ${className} {
|
|
129
|
+
@Get("/")
|
|
130
|
+
getHello() {
|
|
147
131
|
return {
|
|
148
|
-
message:
|
|
132
|
+
message: "Hello from ${projectName}",
|
|
149
133
|
};
|
|
150
134
|
}
|
|
151
135
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
timeout: 30000,
|
|
160
|
-
mode: "inline",
|
|
161
|
-
},
|
|
162
|
-
}).listen(3000);
|
|
136
|
+
`;
|
|
137
|
+
}
|
|
138
|
+
function buildConfigTemplate() {
|
|
139
|
+
return `export const API_CONFIG = {
|
|
140
|
+
host: "0.0.0.0",
|
|
141
|
+
port: 3000,
|
|
142
|
+
};
|
|
163
143
|
`;
|
|
164
144
|
}
|
|
165
145
|
function buildControllerTemplate(controllerName) {
|
|
@@ -168,8 +148,8 @@ function buildControllerTemplate(controllerName) {
|
|
|
168
148
|
Body,
|
|
169
149
|
Controller,
|
|
170
150
|
Get,
|
|
171
|
-
Post,
|
|
172
151
|
Param,
|
|
152
|
+
Post,
|
|
173
153
|
Query,
|
|
174
154
|
} from "fastnode-core";
|
|
175
155
|
|
|
@@ -211,6 +191,76 @@ export class ${className} {
|
|
|
211
191
|
}
|
|
212
192
|
`;
|
|
213
193
|
}
|
|
194
|
+
function resolveModuleFile(moduleName) {
|
|
195
|
+
const srcDir = path_1.default.resolve(process.cwd(), "src");
|
|
196
|
+
if (!fs_1.default.existsSync(srcDir)) {
|
|
197
|
+
console.error(`Cannot find src directory at ${srcDir}`);
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
if (!moduleName) {
|
|
201
|
+
const defaultModuleFile = path_1.default.join(srcDir, "app.module.ts");
|
|
202
|
+
if (!fs_1.default.existsSync(defaultModuleFile)) {
|
|
203
|
+
console.error(`Cannot find default module at ${defaultModuleFile}`);
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
return defaultModuleFile;
|
|
207
|
+
}
|
|
208
|
+
const expectedFileName = `${toKebabCase(moduleName)}.module.ts`;
|
|
209
|
+
const moduleFile = findFileRecursive(srcDir, expectedFileName);
|
|
210
|
+
if (!moduleFile) {
|
|
211
|
+
console.error(`Cannot find module '${moduleName}'. Expected ${expectedFileName} under ${srcDir}`);
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
return moduleFile;
|
|
215
|
+
}
|
|
216
|
+
function findFileRecursive(dir, fileName) {
|
|
217
|
+
const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
218
|
+
for (const entry of entries) {
|
|
219
|
+
const fullPath = path_1.default.join(dir, entry.name);
|
|
220
|
+
if (entry.isDirectory()) {
|
|
221
|
+
const match = findFileRecursive(fullPath, fileName);
|
|
222
|
+
if (match) {
|
|
223
|
+
return match;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else if (entry.isFile() && entry.name === fileName) {
|
|
227
|
+
return fullPath;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
function updateModuleControllers(moduleFile, controllerClassName, controllerName) {
|
|
233
|
+
const controllerFile = path_1.default.resolve(process.cwd(), "src", "controllers", `${controllerName}.controller.ts`);
|
|
234
|
+
const importStatement = `import { ${controllerClassName} } from "${buildRelativeImportPath(moduleFile, controllerFile)}";`;
|
|
235
|
+
let moduleSource = fs_1.default.readFileSync(moduleFile, "utf8");
|
|
236
|
+
if (!moduleSource.includes(importStatement)) {
|
|
237
|
+
moduleSource = `${importStatement}\n${moduleSource}`;
|
|
238
|
+
}
|
|
239
|
+
const controllersMatch = moduleSource.match(/controllers\s*:\s*\[([\s\S]*?)\]/);
|
|
240
|
+
if (!controllersMatch) {
|
|
241
|
+
console.error(`Could not find a controllers array inside ${moduleFile}`);
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
const existingControllers = controllersMatch[1]
|
|
245
|
+
.split(",")
|
|
246
|
+
.map((value) => value.trim())
|
|
247
|
+
.filter(Boolean);
|
|
248
|
+
if (!existingControllers.includes(controllerClassName)) {
|
|
249
|
+
existingControllers.push(controllerClassName);
|
|
250
|
+
}
|
|
251
|
+
moduleSource = moduleSource.replace(/controllers\s*:\s*\[[\s\S]*?\]/, `controllers: [${existingControllers.join(", ")}]`);
|
|
252
|
+
fs_1.default.writeFileSync(moduleFile, moduleSource);
|
|
253
|
+
}
|
|
254
|
+
function buildRelativeImportPath(fromFile, toFile) {
|
|
255
|
+
const relativePath = path_1.default
|
|
256
|
+
.relative(path_1.default.dirname(fromFile), toFile)
|
|
257
|
+
.replace(/\\/g, "/")
|
|
258
|
+
.replace(/\.ts$/, ".js");
|
|
259
|
+
if (relativePath.startsWith(".")) {
|
|
260
|
+
return relativePath;
|
|
261
|
+
}
|
|
262
|
+
return `./${relativePath}`;
|
|
263
|
+
}
|
|
214
264
|
function capitalize(value) {
|
|
215
265
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
216
266
|
}
|
|
@@ -233,6 +283,6 @@ function printUsage() {
|
|
|
233
283
|
Usage:
|
|
234
284
|
fastnode create <project-name>
|
|
235
285
|
fastnode serve <project-name>
|
|
236
|
-
fastnode generate controller <controller-name>
|
|
286
|
+
fastnode generate controller <controller-name> [module-name]
|
|
237
287
|
`);
|
|
238
288
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastnode-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "The official CLI for scaffolding and serving FastNode applications.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fastnode": "dist/index.js"
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"chalk": "^5.3.0",
|
|
27
27
|
"commander": "^11.0.0",
|
|
28
|
-
"fastnode-core": "^0.
|
|
28
|
+
"fastnode-core": "^0.6.1",
|
|
29
29
|
"reflect-metadata": "^0.1.13"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|