fastnode-cli 0.1.2 β 0.2.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/README.md +113 -121
- package/dist/index.js +186 -62
- package/package.json +35 -33
- package/src/index.ts +0 -97
- package/tsconfig.json +0 -9
package/README.md
CHANGED
|
@@ -1,121 +1,113 @@
|
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
Inspired by how fast and intuitive **FastAPI** is for Python developers, `fastnode` aims to bring that same DX (developer experience) to the **Node.js/NestJS** world.
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
## π Links
|
|
119
|
-
|
|
120
|
-
- CLI: [fastnode-cli on npm](https://www.npmjs.com/package/fastnode-cli)
|
|
121
|
-
- Core: [fastnode-core on npm](https://www.npmjs.com/package/fastnode-core)
|
|
1
|
+
# fastnode-cli
|
|
2
|
+
|
|
3
|
+
`fastnode-cli` scaffolds FastNode applications and works with `fastnode-core`.
|
|
4
|
+
|
|
5
|
+
FastNode is built on Fastify and is not NestJS internally.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Create a new FastNode app quickly
|
|
10
|
+
- Generate a starter TypeScript project
|
|
11
|
+
- Scaffold an app that already shows execution policy usage
|
|
12
|
+
- Works with `fastnode-core`
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g fastnode-cli
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Create a project
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
fastnode create my-app
|
|
26
|
+
cd my-app
|
|
27
|
+
npm install
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Start the generated app
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
fastnode serve my-app
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Generate a controller
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
fastnode generate controller items
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This creates:
|
|
43
|
+
|
|
44
|
+
```txt
|
|
45
|
+
src/items/items.controller.ts
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## What the Scaffold Includes
|
|
49
|
+
|
|
50
|
+
The generated app now includes a simple execution policy example:
|
|
51
|
+
|
|
52
|
+
- app-level default execution policy in `createApp(...)`
|
|
53
|
+
- controller-level policy with `@ExecutionPolicy(...)`
|
|
54
|
+
- FastAPI-style path placeholders like `/{item_id}`
|
|
55
|
+
- parameter decorators like `@Param()` and `@Query()`
|
|
56
|
+
|
|
57
|
+
Example generated shape:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import "reflect-metadata";
|
|
61
|
+
import {
|
|
62
|
+
Controller,
|
|
63
|
+
ExecutionPolicy,
|
|
64
|
+
Get,
|
|
65
|
+
Module,
|
|
66
|
+
Param,
|
|
67
|
+
Query,
|
|
68
|
+
createApp,
|
|
69
|
+
} from "fastnode-core";
|
|
70
|
+
|
|
71
|
+
@Controller("/hello")
|
|
72
|
+
@ExecutionPolicy({ timeout: 5000 })
|
|
73
|
+
class HelloController {
|
|
74
|
+
@Get("/")
|
|
75
|
+
hello(@Query("name") name?: string) {
|
|
76
|
+
return {
|
|
77
|
+
message: `Hello from hello${name ? `, ${name}` : ""}`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@Get("/{item_id}")
|
|
82
|
+
getOne(@Param("item_id") itemId: number) {
|
|
83
|
+
return { item_id: itemId };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@Module({ controllers: [HelloController] })
|
|
88
|
+
class HelloModule {}
|
|
89
|
+
|
|
90
|
+
createApp([HelloModule], {
|
|
91
|
+
executionPolicy: {
|
|
92
|
+
timeout: 30000,
|
|
93
|
+
mode: "inline",
|
|
94
|
+
},
|
|
95
|
+
}).listen(3000);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Generated controller files also include request-data examples for:
|
|
99
|
+
|
|
100
|
+
- `@Param("id")`
|
|
101
|
+
- `@Query("page")`
|
|
102
|
+
- `@Body()`
|
|
103
|
+
- `@Body("name")`
|
|
104
|
+
|
|
105
|
+
## Related Docs
|
|
106
|
+
|
|
107
|
+
See `packages/core/README.md` for the full execution policy guide, including:
|
|
108
|
+
|
|
109
|
+
- `@ExecutionPolicy()`
|
|
110
|
+
- `@UseExecutionPolicy()`
|
|
111
|
+
- `@IsolatedHandler()`
|
|
112
|
+
- inline vs isolated execution
|
|
113
|
+
- timeout response behavior
|
package/dist/index.js
CHANGED
|
@@ -7,76 +7,200 @@ 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,
|
|
11
|
-
if (command === "create" &&
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const [, , command, resource, name] = process.argv;
|
|
11
|
+
if (command === "create" && resource) {
|
|
12
|
+
createProject(resource);
|
|
13
|
+
}
|
|
14
|
+
else if (command === "serve" && resource) {
|
|
15
|
+
serveProject(resource);
|
|
16
|
+
}
|
|
17
|
+
else if (command === "generate" && resource === "controller" && name) {
|
|
18
|
+
generateController(name);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
printUsage();
|
|
22
|
+
}
|
|
23
|
+
function createProject(projectName) {
|
|
24
|
+
const projectDir = path_1.default.resolve(projectName);
|
|
25
|
+
const moduleDir = path_1.default.join(projectDir, "src", projectName);
|
|
14
26
|
fs_1.default.mkdirSync(moduleDir, { recursive: true });
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
createApp([${capitalize(arg)}Module]).listen(3000);
|
|
32
|
-
`);
|
|
33
|
-
// 2οΈβ£ tsconfig.json
|
|
34
|
-
fs_1.default.writeFileSync(path_1.default.join(projectDir, "tsconfig.json"), `{
|
|
35
|
-
"compilerOptions": {
|
|
36
|
-
"target": "ES2020",
|
|
37
|
-
"module": "CommonJS",
|
|
38
|
-
"rootDir": "./src",
|
|
39
|
-
"outDir": "./dist",
|
|
40
|
-
"strict": true,
|
|
41
|
-
"esModuleInterop": true,
|
|
42
|
-
"experimentalDecorators": true,
|
|
43
|
-
"emitDecoratorMetadata": true,
|
|
44
|
-
"useDefineForClassFields": false
|
|
45
|
-
},
|
|
46
|
-
"include": ["src"]
|
|
47
|
-
}
|
|
27
|
+
fs_1.default.writeFileSync(path_1.default.join(moduleDir, "main.ts"), buildMainTemplate(projectName));
|
|
28
|
+
fs_1.default.writeFileSync(path_1.default.join(projectDir, "tsconfig.json"), `{
|
|
29
|
+
"compilerOptions": {
|
|
30
|
+
"target": "ES2020",
|
|
31
|
+
"module": "CommonJS",
|
|
32
|
+
"rootDir": "./src",
|
|
33
|
+
"outDir": "./dist",
|
|
34
|
+
"strict": true,
|
|
35
|
+
"esModuleInterop": true,
|
|
36
|
+
"experimentalDecorators": true,
|
|
37
|
+
"emitDecoratorMetadata": true,
|
|
38
|
+
"useDefineForClassFields": false
|
|
39
|
+
},
|
|
40
|
+
"include": ["src"]
|
|
41
|
+
}
|
|
48
42
|
`);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
43
|
+
fs_1.default.writeFileSync(path_1.default.join(projectDir, "package.json"), `{
|
|
44
|
+
"name": "${projectName}",
|
|
45
|
+
"version": "1.0.0",
|
|
46
|
+
"type": "commonjs",
|
|
47
|
+
"main": "dist/index.js",
|
|
48
|
+
"scripts": {
|
|
49
|
+
"dev": "tsx src/${projectName}/main.ts",
|
|
50
|
+
"build": "tsc",
|
|
51
|
+
"start": "node dist/${projectName}/main.js"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"fastnode-core": "latest",
|
|
55
|
+
"reflect-metadata": "^0.1.13"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"tsx": "^4.7.0",
|
|
59
|
+
"typescript": "^5.0.0"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
69
62
|
`);
|
|
70
|
-
console.log(`β Project '${
|
|
63
|
+
console.log(`β Project '${projectName}' created at ${projectDir}`);
|
|
71
64
|
}
|
|
72
|
-
|
|
73
|
-
const entry = path_1.default.resolve(process.cwd(), `src/${
|
|
65
|
+
function serveProject(projectName) {
|
|
66
|
+
const entry = path_1.default.resolve(process.cwd(), `src/${projectName}/main.ts`);
|
|
74
67
|
if (!fs_1.default.existsSync(entry)) {
|
|
75
68
|
console.error(`β Cannot find module at ${entry}`);
|
|
76
69
|
process.exit(1);
|
|
77
70
|
}
|
|
78
71
|
(0, child_process_1.execSync)(`npx tsx ${entry}`, { stdio: "inherit" });
|
|
79
72
|
}
|
|
80
|
-
function
|
|
81
|
-
|
|
73
|
+
function generateController(controllerName) {
|
|
74
|
+
const normalizedName = toKebabCase(controllerName);
|
|
75
|
+
const className = `${toPascalCase(controllerName)}Controller`;
|
|
76
|
+
const controllerDir = path_1.default.resolve(process.cwd(), "src", normalizedName);
|
|
77
|
+
const controllerFile = path_1.default.join(controllerDir, `${normalizedName}.controller.ts`);
|
|
78
|
+
fs_1.default.mkdirSync(controllerDir, { recursive: true });
|
|
79
|
+
if (fs_1.default.existsSync(controllerFile)) {
|
|
80
|
+
console.error(`β Controller already exists at ${controllerFile}`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
fs_1.default.writeFileSync(controllerFile, buildControllerTemplate(normalizedName));
|
|
84
|
+
console.log(`β Controller '${normalizedName}' created at ${controllerFile}`);
|
|
85
|
+
console.log(`βΉ Add ${className} to a module so FastNode can register it.`);
|
|
86
|
+
}
|
|
87
|
+
function buildMainTemplate(projectName) {
|
|
88
|
+
const className = `${toPascalCase(projectName)}Controller`;
|
|
89
|
+
const moduleName = `${toPascalCase(projectName)}Module`;
|
|
90
|
+
return `import "reflect-metadata";
|
|
91
|
+
import {
|
|
92
|
+
Controller,
|
|
93
|
+
ExecutionPolicy,
|
|
94
|
+
Get,
|
|
95
|
+
Module,
|
|
96
|
+
Param,
|
|
97
|
+
Query,
|
|
98
|
+
createApp,
|
|
99
|
+
} from "fastnode-core";
|
|
100
|
+
|
|
101
|
+
@Controller("/${projectName}")
|
|
102
|
+
@ExecutionPolicy({ timeout: 5000 })
|
|
103
|
+
class ${className} {
|
|
104
|
+
@Get("/")
|
|
105
|
+
hello(@Query("name") name?: string) {
|
|
106
|
+
return {
|
|
107
|
+
message: \`Hello from ${projectName}\${name ? \`, \${name}\` : ""}\`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@Get("/{item_id}")
|
|
112
|
+
getOne(
|
|
113
|
+
@Param("item_id") itemId: number,
|
|
114
|
+
@Query("include") include?: string
|
|
115
|
+
) {
|
|
116
|
+
return {
|
|
117
|
+
item_id: itemId,
|
|
118
|
+
include,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@Module({ controllers: [${className}] })
|
|
124
|
+
class ${moduleName} {}
|
|
125
|
+
|
|
126
|
+
createApp([${moduleName}], {
|
|
127
|
+
executionPolicy: {
|
|
128
|
+
timeout: 30000,
|
|
129
|
+
mode: "inline",
|
|
130
|
+
},
|
|
131
|
+
}).listen(3000);
|
|
132
|
+
`;
|
|
133
|
+
}
|
|
134
|
+
function buildControllerTemplate(controllerName) {
|
|
135
|
+
const className = `${toPascalCase(controllerName)}Controller`;
|
|
136
|
+
return `import {
|
|
137
|
+
Body,
|
|
138
|
+
Controller,
|
|
139
|
+
Get,
|
|
140
|
+
Param,
|
|
141
|
+
Query,
|
|
142
|
+
} from "fastnode-core";
|
|
143
|
+
|
|
144
|
+
@Controller("/${controllerName}")
|
|
145
|
+
export class ${className} {
|
|
146
|
+
@Get("/")
|
|
147
|
+
list(
|
|
148
|
+
@Query("page") page?: number,
|
|
149
|
+
@Query("search") search?: string
|
|
150
|
+
) {
|
|
151
|
+
return {
|
|
152
|
+
resource: "${controllerName}",
|
|
153
|
+
page,
|
|
154
|
+
search,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@Get("/{id}")
|
|
159
|
+
findOne(
|
|
160
|
+
@Param("id") id: number,
|
|
161
|
+
@Query("expand") expand?: string
|
|
162
|
+
) {
|
|
163
|
+
return {
|
|
164
|
+
id,
|
|
165
|
+
expand,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@Get("/request/echo")
|
|
170
|
+
echoRequest(
|
|
171
|
+
@Body() payload?: Record<string, unknown>,
|
|
172
|
+
@Body("name") name?: string
|
|
173
|
+
) {
|
|
174
|
+
return {
|
|
175
|
+
payload,
|
|
176
|
+
name,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
182
|
+
function capitalize(value) {
|
|
183
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
184
|
+
}
|
|
185
|
+
function toPascalCase(value) {
|
|
186
|
+
return toKebabCase(value)
|
|
187
|
+
.split("-")
|
|
188
|
+
.filter(Boolean)
|
|
189
|
+
.map(capitalize)
|
|
190
|
+
.join("");
|
|
191
|
+
}
|
|
192
|
+
function toKebabCase(value) {
|
|
193
|
+
return value
|
|
194
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
195
|
+
.replace(/[\s_]+/g, "-")
|
|
196
|
+
.toLowerCase();
|
|
197
|
+
}
|
|
198
|
+
function printUsage() {
|
|
199
|
+
console.log(`FastNode CLI
|
|
200
|
+
|
|
201
|
+
Usage:
|
|
202
|
+
fastnode create <project-name>
|
|
203
|
+
fastnode serve <project-name>
|
|
204
|
+
fastnode generate controller <controller-name>
|
|
205
|
+
`);
|
|
82
206
|
}
|
package/package.json
CHANGED
|
@@ -1,39 +1,41 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "fastnode-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
5
|
-
"bin": {
|
|
6
|
-
"fastnode": "dist/index.js"
|
|
7
|
-
},
|
|
8
|
-
"main": "dist/index.js",
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
1
|
+
{
|
|
2
|
+
"name": "fastnode-cli",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "The official CLI for scaffolding and serving FastNode applications.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"fastnode": "dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"files": ["dist", "README.md"],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node dist/index.js",
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"cli",
|
|
17
|
+
"fastapi",
|
|
18
|
+
"nodejs",
|
|
19
|
+
"scaffolding",
|
|
20
|
+
"generator",
|
|
21
|
+
"fastnode"
|
|
21
22
|
],
|
|
22
23
|
"author": "Valentine Emmanuel Ikechukwu",
|
|
23
24
|
"license": "MIT",
|
|
24
|
-
"dependencies": {
|
|
25
|
-
"chalk": "^5.3.0",
|
|
26
|
-
"commander": "^11.0.0",
|
|
27
|
-
"fastnode-core": "
|
|
28
|
-
"reflect-metadata": "^0.1.13"
|
|
29
|
-
},
|
|
30
|
-
"devDependencies": {
|
|
31
|
-
"
|
|
32
|
-
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"chalk": "^5.3.0",
|
|
27
|
+
"commander": "^11.0.0",
|
|
28
|
+
"fastnode-core": "^0.2.0",
|
|
29
|
+
"reflect-metadata": "^0.1.13"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^24.5.2",
|
|
33
|
+
"typescript": "^5.0.0"
|
|
34
|
+
},
|
|
33
35
|
"engines": {
|
|
34
36
|
"node": ">=18.0.0"
|
|
35
37
|
},
|
|
36
|
-
"publishConfig": {
|
|
37
|
-
"access": "public"
|
|
38
|
-
}
|
|
39
|
-
}
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/index.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { execSync } from "child_process";
|
|
3
|
-
import fs from "fs";
|
|
4
|
-
import path from "path";
|
|
5
|
-
|
|
6
|
-
const [, , command, arg] = process.argv;
|
|
7
|
-
|
|
8
|
-
if (command === "create" && arg) {
|
|
9
|
-
const projectDir = path.resolve(arg);
|
|
10
|
-
const moduleDir = path.join(projectDir, "src", arg);
|
|
11
|
-
|
|
12
|
-
fs.mkdirSync(moduleDir, { recursive: true });
|
|
13
|
-
|
|
14
|
-
// 1οΈβ£ main.ts
|
|
15
|
-
const mainFile = path.join(moduleDir, "main.ts");
|
|
16
|
-
fs.writeFileSync(
|
|
17
|
-
mainFile,
|
|
18
|
-
`import "reflect-metadata";
|
|
19
|
-
import { Controller, Get, Module, createApp } from "fastnode-core";
|
|
20
|
-
|
|
21
|
-
@Controller("/${arg}")
|
|
22
|
-
class ${capitalize(arg)}Controller {
|
|
23
|
-
@Get("/")
|
|
24
|
-
hello() {
|
|
25
|
-
return { message: "Hello from ${arg}" };
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
@Module({ controllers: [${capitalize(arg)}Controller] })
|
|
30
|
-
class ${capitalize(arg)}Module {}
|
|
31
|
-
|
|
32
|
-
createApp([${capitalize(arg)}Module]).listen(3000);
|
|
33
|
-
`
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
// 2οΈβ£ tsconfig.json
|
|
37
|
-
fs.writeFileSync(
|
|
38
|
-
path.join(projectDir, "tsconfig.json"),
|
|
39
|
-
`{
|
|
40
|
-
"compilerOptions": {
|
|
41
|
-
"target": "ES2020",
|
|
42
|
-
"module": "CommonJS",
|
|
43
|
-
"rootDir": "./src",
|
|
44
|
-
"outDir": "./dist",
|
|
45
|
-
"strict": true,
|
|
46
|
-
"esModuleInterop": true,
|
|
47
|
-
"experimentalDecorators": true,
|
|
48
|
-
"emitDecoratorMetadata": true,
|
|
49
|
-
"useDefineForClassFields": false
|
|
50
|
-
},
|
|
51
|
-
"include": ["src"]
|
|
52
|
-
}
|
|
53
|
-
`
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
// 3οΈβ£ package.json
|
|
57
|
-
fs.writeFileSync(
|
|
58
|
-
path.join(projectDir, "package.json"),
|
|
59
|
-
`{
|
|
60
|
-
"name": "${arg}",
|
|
61
|
-
"version": "1.0.0",
|
|
62
|
-
"type": "commonjs",
|
|
63
|
-
"main": "dist/index.js",
|
|
64
|
-
"scripts": {
|
|
65
|
-
"dev": "tsx src/${arg}/main.ts",
|
|
66
|
-
"build": "tsc",
|
|
67
|
-
"start": "node dist/${arg}/main.js"
|
|
68
|
-
},
|
|
69
|
-
"dependencies": {
|
|
70
|
-
"fastnode-core": "latest",
|
|
71
|
-
"reflect-metadata": "^0.1.13"
|
|
72
|
-
},
|
|
73
|
-
"devDependencies": {
|
|
74
|
-
"tsx": "^4.7.0",
|
|
75
|
-
"typescript": "^5.0.0"
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
`
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
console.log(`β Project '${arg}' created at ${projectDir}`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (command === "serve" && arg) {
|
|
85
|
-
const entry = path.resolve(process.cwd(), `src/${arg}/main.ts`);
|
|
86
|
-
|
|
87
|
-
if (!fs.existsSync(entry)) {
|
|
88
|
-
console.error(`β Cannot find module at ${entry}`);
|
|
89
|
-
process.exit(1);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
execSync(`npx tsx ${entry}`, { stdio: "inherit" });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function capitalize(str: string): string {
|
|
96
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
97
|
-
}
|