create-pangza 1.0.1 → 1.1.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 +4 -0
- package/lib/generate.js +12 -6
- package/lib/modules.js +136 -12
- package/lib/scaffold.js +11 -3
- package/package.json +2 -2
- package/template/base/tsconfig.json +4 -0
package/README.md
CHANGED
|
@@ -13,6 +13,10 @@ npm create pangza@latest -- init my-app
|
|
|
13
13
|
交互勾选模块:`orm` / `auth` / `redis` / `log` / `schedule` / `encrypt` / `validate`。
|
|
14
14
|
勾选 `orm` / `redis` 时会写入 `EnableOrm()` / `EnableRedis()`;未勾选则启动不连库、不因缺配置报错。不生成 `.gitkeep`。
|
|
15
15
|
|
|
16
|
+
初始化还会生成:
|
|
17
|
+
- `application.yaml`:默认 `server.port: 5270`;按所选模块追加 `redis` / `datasource`+`orm` 等
|
|
18
|
+
- `tsconfig.json`:`@/*` → `src/*`(dev:`tsconfig-paths`;build:`tsc-alias`)
|
|
19
|
+
|
|
16
20
|
```bash
|
|
17
21
|
npx create-pangza init my-app --modules=orm,auth,redis --db=mysql
|
|
18
22
|
```
|
package/lib/generate.js
CHANGED
|
@@ -31,7 +31,13 @@ function findProjectRoot(cwd = process.cwd()) {
|
|
|
31
31
|
...(json.dependencies || {}),
|
|
32
32
|
...(json.devDependencies || {}),
|
|
33
33
|
};
|
|
34
|
-
if (
|
|
34
|
+
if (
|
|
35
|
+
deps["@pangza/express"] ||
|
|
36
|
+
deps["@pangza/application"] ||
|
|
37
|
+
deps["@pangza/core"]
|
|
38
|
+
) {
|
|
39
|
+
return dir;
|
|
40
|
+
}
|
|
35
41
|
} catch {
|
|
36
42
|
/* ignore */
|
|
37
43
|
}
|
|
@@ -59,7 +65,7 @@ function writeFile(filePath, content, { force }) {
|
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
function tplEntity({ Pascal, snake }) {
|
|
62
|
-
return `import { TableField, TableId, TableName } from "@pangza/
|
|
68
|
+
return `import { TableField, TableId, TableName } from "@pangza/orm";
|
|
63
69
|
|
|
64
70
|
@TableName("${snake}")
|
|
65
71
|
export default class ${Pascal}Entity {
|
|
@@ -89,7 +95,7 @@ export default class ${Pascal}Entity {
|
|
|
89
95
|
}
|
|
90
96
|
|
|
91
97
|
function tplMapper({ Pascal, fileBase }) {
|
|
92
|
-
return `import { Mapper, MapperType } from "@pangza/
|
|
98
|
+
return `import { Mapper, MapperType } from "@pangza/orm";
|
|
93
99
|
import ${Pascal}Entity from "../entity/${fileBase}";
|
|
94
100
|
|
|
95
101
|
@Mapper(${Pascal}Entity)
|
|
@@ -98,7 +104,7 @@ export default class ${Pascal}Mapper extends MapperType {}
|
|
|
98
104
|
}
|
|
99
105
|
|
|
100
106
|
function tplService({ Pascal, fileBase }) {
|
|
101
|
-
return `import { BaseService, Service } from "@pangza/
|
|
107
|
+
return `import { BaseService, Service } from "@pangza/core";
|
|
102
108
|
import ${Pascal}Mapper from "../mapper/${fileBase}";
|
|
103
109
|
|
|
104
110
|
@Service(${Pascal}Mapper)
|
|
@@ -115,8 +121,8 @@ function tplController({ Pascal, fileBase, apiPath, camel }) {
|
|
|
115
121
|
PutMapping,
|
|
116
122
|
RequestBody,
|
|
117
123
|
RequestPath,
|
|
118
|
-
|
|
119
|
-
} from "@pangza/
|
|
124
|
+
} from "@pangza/application";
|
|
125
|
+
import { Resource } from "@pangza/core";
|
|
120
126
|
import ${Pascal}Service from "../../service/${fileBase}";
|
|
121
127
|
|
|
122
128
|
@Controller("/api/${apiPath}")
|
package/lib/modules.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
/**
|
|
3
|
+
/** 可选能力模块(按分包安装;入口按模块分包导入) */
|
|
4
4
|
const MODULES = [
|
|
5
5
|
{
|
|
6
6
|
id: "orm",
|
|
@@ -35,7 +35,7 @@ const MODULES = [
|
|
|
35
35
|
{
|
|
36
36
|
id: "validate",
|
|
37
37
|
label: "Validate",
|
|
38
|
-
hint: "
|
|
38
|
+
hint: "参数校验装饰器(含在 @pangza/core)",
|
|
39
39
|
},
|
|
40
40
|
];
|
|
41
41
|
|
|
@@ -81,7 +81,8 @@ const DB_ENV = {
|
|
|
81
81
|
/** @param {string[]} moduleIds @param {string} [dbType] */
|
|
82
82
|
function resolveDependencies(moduleIds, dbType = "mysql") {
|
|
83
83
|
const deps = {
|
|
84
|
-
"@pangza/
|
|
84
|
+
"@pangza/application": "^1.1.0",
|
|
85
|
+
"@pangza/core": "^1.1.0",
|
|
85
86
|
cors: "^2.8.5",
|
|
86
87
|
express: "^5.2.1",
|
|
87
88
|
inversify: "^8.2.3",
|
|
@@ -90,18 +91,28 @@ function resolveDependencies(moduleIds, dbType = "mysql") {
|
|
|
90
91
|
const set = new Set(moduleIds);
|
|
91
92
|
|
|
92
93
|
if (set.has("orm")) {
|
|
94
|
+
deps["@pangza/orm"] = "^1.1.0";
|
|
93
95
|
Object.assign(deps, DB_DEPS[dbType] || DB_DEPS.mysql);
|
|
94
96
|
}
|
|
95
97
|
if (set.has("redis") || set.has("auth")) {
|
|
98
|
+
deps["@pangza/redis"] = "^1.1.0";
|
|
96
99
|
deps.redis = "^6.2.1";
|
|
97
100
|
}
|
|
98
101
|
if (set.has("auth")) {
|
|
102
|
+
deps["@pangza/auth"] = "^1.1.0";
|
|
99
103
|
deps.jsonwebtoken = "^9.0.3";
|
|
100
104
|
deps.bcryptjs = "^3.0.3";
|
|
101
105
|
}
|
|
106
|
+
if (set.has("log")) {
|
|
107
|
+
deps["@pangza/log"] = "^1.1.0";
|
|
108
|
+
}
|
|
102
109
|
if (set.has("schedule")) {
|
|
110
|
+
deps["@pangza/schedule"] = "^1.1.0";
|
|
103
111
|
deps["node-cron"] = "^4.6.0";
|
|
104
112
|
}
|
|
113
|
+
if (set.has("encrypt")) {
|
|
114
|
+
deps["@pangza/encrypt"] = "^1.1.0";
|
|
115
|
+
}
|
|
105
116
|
|
|
106
117
|
return deps;
|
|
107
118
|
}
|
|
@@ -142,34 +153,146 @@ function resolveDirs(moduleIds) {
|
|
|
142
153
|
return dirs;
|
|
143
154
|
}
|
|
144
155
|
|
|
156
|
+
const DB_YAML = {
|
|
157
|
+
mysql: {
|
|
158
|
+
type: "mysql",
|
|
159
|
+
port: 3306,
|
|
160
|
+
user: "root",
|
|
161
|
+
database: "pangza",
|
|
162
|
+
},
|
|
163
|
+
postgresql: {
|
|
164
|
+
type: "postgresql",
|
|
165
|
+
port: 5432,
|
|
166
|
+
user: "postgres",
|
|
167
|
+
database: "pangza",
|
|
168
|
+
},
|
|
169
|
+
mssql: {
|
|
170
|
+
type: "sqlserver",
|
|
171
|
+
port: 1433,
|
|
172
|
+
user: "sa",
|
|
173
|
+
database: "pangza",
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 按所选模块生成 application.yaml(始终含 server.port=5270)。
|
|
179
|
+
* @param {string[]} moduleIds
|
|
180
|
+
* @param {string} [dbType]
|
|
181
|
+
*/
|
|
182
|
+
function generateApplicationYaml(moduleIds, dbType = "mysql") {
|
|
183
|
+
const set = new Set(moduleIds);
|
|
184
|
+
const lines = [
|
|
185
|
+
"# Generated by create-pangza init",
|
|
186
|
+
"# profile: PANGZA_PROFILE / APP_ENV / NODE_ENV(默认 development)",
|
|
187
|
+
"",
|
|
188
|
+
"server:",
|
|
189
|
+
" port: 5270",
|
|
190
|
+
" trustProxy: false",
|
|
191
|
+
];
|
|
192
|
+
|
|
193
|
+
if (set.has("redis") || set.has("auth")) {
|
|
194
|
+
lines.push(
|
|
195
|
+
"",
|
|
196
|
+
"redis:",
|
|
197
|
+
" host: 127.0.0.1",
|
|
198
|
+
" port: 6379",
|
|
199
|
+
" password: \"\"",
|
|
200
|
+
" db: 0",
|
|
201
|
+
" keyPrefix: \"pangza:\"",
|
|
202
|
+
" mode: standalone",
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (set.has("orm")) {
|
|
207
|
+
const db = DB_YAML[dbType] || DB_YAML.mysql;
|
|
208
|
+
lines.push(
|
|
209
|
+
"",
|
|
210
|
+
"datasource:",
|
|
211
|
+
" default:",
|
|
212
|
+
` type: ${db.type}`,
|
|
213
|
+
" host: 127.0.0.1",
|
|
214
|
+
` port: ${db.port}`,
|
|
215
|
+
` user: ${db.user}`,
|
|
216
|
+
" password: \"\"",
|
|
217
|
+
` database: ${db.database}`,
|
|
218
|
+
" connectionLimit: 10",
|
|
219
|
+
"",
|
|
220
|
+
"orm:",
|
|
221
|
+
" logicDelete: true",
|
|
222
|
+
" logicDeleteField: delete_flag",
|
|
223
|
+
" logicDeleteValue: 1",
|
|
224
|
+
" logicNotDeleteValue: 0",
|
|
225
|
+
" idType: ASSIGN_ID",
|
|
226
|
+
" mapUnderscoreToCamelCase: true",
|
|
227
|
+
" mapperLocations: []",
|
|
228
|
+
" sqlLog:",
|
|
229
|
+
" enabled: false",
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (set.has("encrypt")) {
|
|
234
|
+
lines.push(
|
|
235
|
+
"",
|
|
236
|
+
"# encrypt: 密钥建议放代码或环境变量,勿提交生产密钥到仓库",
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (set.has("schedule")) {
|
|
241
|
+
lines.push("", "# schedule: 任务写在 src/schedule,由 Application.scan 加载");
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (set.has("log")) {
|
|
245
|
+
lines.push("", "# log: 在入口 registry(Log({ writer })) 中配置落库");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (set.has("auth")) {
|
|
249
|
+
lines.push(
|
|
250
|
+
"",
|
|
251
|
+
"# auth: jwtSecret 等在入口 Auth({ ... }) 配置,勿写进 yaml 明文(除非自管)",
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
lines.push("");
|
|
256
|
+
return lines.join("\n");
|
|
257
|
+
}
|
|
258
|
+
|
|
145
259
|
/**
|
|
146
260
|
* 生成空项目入口:只起 HTTP;选了 redis/orm 才 Enable*,否则启动不连库。
|
|
147
261
|
* @param {string[]} moduleIds
|
|
148
262
|
*/
|
|
149
263
|
function generateMainTs(moduleIds) {
|
|
150
264
|
const set = new Set(moduleIds);
|
|
151
|
-
const named = ["Application", "Logger"];
|
|
152
|
-
if (set.has("orm")) named.push("EnableOrm");
|
|
153
|
-
if (set.has("redis") || set.has("auth")) named.push("EnableRedis");
|
|
154
|
-
if (set.has("auth")) named.push("Auth", "Redis");
|
|
155
|
-
if (set.has("log")) named.push("Log");
|
|
156
265
|
|
|
157
266
|
const imports = [
|
|
158
267
|
'import "reflect-metadata";',
|
|
159
268
|
'import cors from "cors";',
|
|
160
269
|
'import { json } from "express";',
|
|
161
|
-
|
|
270
|
+
'import { Application } from "@pangza/application";',
|
|
271
|
+
'import { Logger } from "@pangza/core";',
|
|
162
272
|
];
|
|
163
273
|
|
|
274
|
+
if (set.has("orm")) {
|
|
275
|
+
imports.push('import { EnableOrm } from "@pangza/orm";');
|
|
276
|
+
}
|
|
277
|
+
if (set.has("redis") || set.has("auth")) {
|
|
278
|
+
imports.push('import Redis, { EnableRedis } from "@pangza/redis";');
|
|
279
|
+
}
|
|
280
|
+
if (set.has("auth")) {
|
|
281
|
+
imports.push('import Auth from "@pangza/auth";');
|
|
282
|
+
}
|
|
283
|
+
if (set.has("log")) {
|
|
284
|
+
imports.push('import Log from "@pangza/log";');
|
|
285
|
+
}
|
|
286
|
+
|
|
164
287
|
const notes = [];
|
|
165
288
|
if (set.has("schedule")) {
|
|
166
|
-
notes.push("// Schedule: 在 src/schedule
|
|
289
|
+
notes.push("// Schedule: 在 src/schedule 编写任务并由扫描加载(@pangza/schedule)");
|
|
167
290
|
}
|
|
168
291
|
if (set.has("encrypt")) {
|
|
169
|
-
notes.push("// Encrypt:
|
|
292
|
+
notes.push("// Encrypt: import { AESUtil } from \"@pangza/encrypt\"");
|
|
170
293
|
}
|
|
171
294
|
if (set.has("validate")) {
|
|
172
|
-
notes.push("// Validate: 在 Controller
|
|
295
|
+
notes.push("// Validate: 在 Controller 参数上使用 @pangza/core 校验装饰器");
|
|
173
296
|
}
|
|
174
297
|
|
|
175
298
|
const chain = [
|
|
@@ -209,5 +332,6 @@ module.exports = {
|
|
|
209
332
|
resolveDependencies,
|
|
210
333
|
resolveEnvLines,
|
|
211
334
|
resolveDirs,
|
|
335
|
+
generateApplicationYaml,
|
|
212
336
|
generateMainTs,
|
|
213
337
|
};
|
package/lib/scaffold.js
CHANGED
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
resolveDependencies,
|
|
7
7
|
resolveEnvLines,
|
|
8
8
|
resolveDirs,
|
|
9
|
+
generateApplicationYaml,
|
|
9
10
|
generateMainTs,
|
|
10
11
|
} = require("./modules");
|
|
11
12
|
|
|
@@ -64,7 +65,7 @@ function scaffold(opts) {
|
|
|
64
65
|
description: "Pangza Express app",
|
|
65
66
|
scripts: {
|
|
66
67
|
dev: "ts-node -r tsconfig-paths/register src/main.ts",
|
|
67
|
-
build: "tsc -p tsconfig.json",
|
|
68
|
+
build: "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
|
|
68
69
|
start: "node dist/main.js",
|
|
69
70
|
},
|
|
70
71
|
dependencies: resolveDependencies(modules, dbType),
|
|
@@ -73,6 +74,7 @@ function scaffold(opts) {
|
|
|
73
74
|
"@types/express": "^5.0.6",
|
|
74
75
|
"@types/node": "^22.0.0",
|
|
75
76
|
"ts-node": "^10.9.2",
|
|
77
|
+
"tsc-alias": "^1.8.16",
|
|
76
78
|
"tsconfig-paths": "^4.2.0",
|
|
77
79
|
typescript: "^5.9.3",
|
|
78
80
|
},
|
|
@@ -86,6 +88,10 @@ function scaffold(opts) {
|
|
|
86
88
|
path.join(targetDir, ".env.example"),
|
|
87
89
|
resolveEnvLines(modules, dbType).join("\n") + "\n",
|
|
88
90
|
);
|
|
91
|
+
writeFile(
|
|
92
|
+
path.join(targetDir, "application.yaml"),
|
|
93
|
+
generateApplicationYaml(modules, dbType),
|
|
94
|
+
);
|
|
89
95
|
writeFile(path.join(targetDir, "src", "main.ts"), generateMainTs(modules));
|
|
90
96
|
|
|
91
97
|
writeFile(
|
|
@@ -102,12 +108,14 @@ ${modules.includes("orm") ? `Database: **${dbType}**\n` : ""}
|
|
|
102
108
|
## Run
|
|
103
109
|
|
|
104
110
|
\`\`\`bash
|
|
105
|
-
cp .env.example .env
|
|
111
|
+
cp .env.example .env # 可选;端口与库配置以 application.yaml 为准
|
|
106
112
|
npm install
|
|
107
113
|
npm run dev
|
|
108
114
|
\`\`\`
|
|
109
115
|
|
|
110
|
-
|
|
116
|
+
- 默认端口:\`application.yaml\` → \`server.port: 5270\`
|
|
117
|
+
- 路径别名:\`@/*\` → \`src/*\`(dev 用 tsconfig-paths,build 用 tsc-alias)
|
|
118
|
+
- 需要 Redis / 数据库时,入口已按模块写入 \`EnableRedis()\` / \`EnableOrm()\`
|
|
111
119
|
`,
|
|
112
120
|
);
|
|
113
121
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-pangza",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "Scaffold & generate for @pangza
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Scaffold & generate for @pangza/* (init / g controller|service|mapper|entity|all)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"create-pangza": "./bin/create-pangza.js"
|
|
7
7
|
},
|