fastnode-cli 0.6.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 -97
- 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,152 +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
|
-
executionPolicy: {
|
|
160
|
-
timeout: 30000,
|
|
161
|
-
mode: "inline",
|
|
162
|
-
},
|
|
163
|
-
}).listen(3000);
|
|
136
|
+
`;
|
|
137
|
+
}
|
|
138
|
+
function buildConfigTemplate() {
|
|
139
|
+
return `export const API_CONFIG = {
|
|
140
|
+
host: "0.0.0.0",
|
|
141
|
+
port: 3000,
|
|
142
|
+
};
|
|
164
143
|
`;
|
|
165
144
|
}
|
|
166
145
|
function buildControllerTemplate(controllerName) {
|
|
@@ -169,8 +148,8 @@ function buildControllerTemplate(controllerName) {
|
|
|
169
148
|
Body,
|
|
170
149
|
Controller,
|
|
171
150
|
Get,
|
|
172
|
-
Post,
|
|
173
151
|
Param,
|
|
152
|
+
Post,
|
|
174
153
|
Query,
|
|
175
154
|
} from "fastnode-core";
|
|
176
155
|
|
|
@@ -212,6 +191,76 @@ export class ${className} {
|
|
|
212
191
|
}
|
|
213
192
|
`;
|
|
214
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
|
+
}
|
|
215
264
|
function capitalize(value) {
|
|
216
265
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
217
266
|
}
|
|
@@ -234,6 +283,6 @@ function printUsage() {
|
|
|
234
283
|
Usage:
|
|
235
284
|
fastnode create <project-name>
|
|
236
285
|
fastnode serve <project-name>
|
|
237
|
-
fastnode generate controller <controller-name>
|
|
286
|
+
fastnode generate controller <controller-name> [module-name]
|
|
238
287
|
`);
|
|
239
288
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastnode-cli",
|
|
3
|
-
"version": "0.6.
|
|
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.6.
|
|
28
|
+
"fastnode-core": "^0.6.1",
|
|
29
29
|
"reflect-metadata": "^0.1.13"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|