@aicblock/nserve 1.0.0 → 1.0.2
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 +305 -4
- package/lib/commander.js +1 -1
- package/lib/core/run.js +1 -1
- package/lib/index.d.ts +112 -26
- package/lib/index.js +3 -1
- package/lib/runtime.js +24 -7
- package/lib/tools/index.d.ts +16 -0
- package/lib/tools/index.js +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -4,11 +4,15 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
# NServe 用户使用文档
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## 1. 项目简介
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
NServe 是一个 Node.js 服务器端开发 CLI 工具,旨在简化 Node.js 服务器应用的开发、构建和部署流程。它提供了代码生成、热重载开发服务器和项目构建等功能,帮助开发者快速搭建和维护 Node.js 服务器应用。
|
|
12
|
+
|
|
13
|
+
## 2. 快速开始
|
|
14
|
+
|
|
15
|
+
您可以使用以下命令创建一个新的 NServe 项目:
|
|
12
16
|
|
|
13
17
|
#### 使用 NPM:
|
|
14
18
|
|
|
@@ -25,5 +29,302 @@ $ yarn create nserve@latest
|
|
|
25
29
|
#### 使用 PNPM:
|
|
26
30
|
|
|
27
31
|
```sh
|
|
28
|
-
$ pnpm create
|
|
32
|
+
$ pnpm create nserve@latest
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 3. 核心功能
|
|
36
|
+
|
|
37
|
+
### 3.1 命令行接口
|
|
38
|
+
|
|
39
|
+
NServe 提供了三个主要命令:
|
|
40
|
+
|
|
41
|
+
- `nserve serve` - 启动开发服务器
|
|
42
|
+
- `nserve build` - 构建项目
|
|
43
|
+
- `nserve gen` - 根据配置文件生成代码
|
|
44
|
+
|
|
45
|
+
### 3.2 代码生成
|
|
46
|
+
|
|
47
|
+
- **路由生成**:根据配置文件自动生成 Express 路由
|
|
48
|
+
- **模型生成**:从 SQL CREATE TABLE 语句生成数据模型
|
|
49
|
+
|
|
50
|
+
### 3.3 开发服务器
|
|
51
|
+
|
|
52
|
+
- 支持 TypeScript 实时编译
|
|
53
|
+
- 热重载功能
|
|
54
|
+
- 支持环境变量配置
|
|
55
|
+
|
|
56
|
+
### 3.4 项目构建
|
|
57
|
+
|
|
58
|
+
- 使用 esbuild 进行快速构建
|
|
59
|
+
- 支持生产环境优化
|
|
60
|
+
- 生成可执行的 JavaScript 代码
|
|
61
|
+
|
|
62
|
+
## 4. 配置文件
|
|
63
|
+
|
|
64
|
+
### 4.1 基本配置
|
|
65
|
+
|
|
66
|
+
在项目根目录创建 `nserve.config.ts` 文件:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { DefineNserveConfig } from '@aicblock/nserve'
|
|
70
|
+
|
|
71
|
+
export default DefineNserveConfig({
|
|
72
|
+
entry: 'app.ts', // 应用入口文件
|
|
73
|
+
outputDir: 'dist', // 构建输出目录
|
|
74
|
+
sourceDir: 'src', // 源代码目录
|
|
75
|
+
testing: false, // 是否为测试模式
|
|
76
|
+
yamlConfig: {}, // YAML 配置文件内容
|
|
77
|
+
plugins: [], // 自定义插件
|
|
78
|
+
external: [], // 外部依赖
|
|
79
|
+
generateConfig: {
|
|
80
|
+
genDir: 'nserve-config', // 生成配置目录
|
|
81
|
+
routerDir: 'router', // 路由配置目录
|
|
82
|
+
modelDir: 'model', // 模型配置目录
|
|
83
|
+
codePrettier: {
|
|
84
|
+
semi: false, // 是否使用分号
|
|
85
|
+
singleQuote: true, // 是否使用单引号
|
|
86
|
+
trailingComma: 'none' // 尾随逗号配置
|
|
87
|
+
},
|
|
88
|
+
middleware: {} // 中间件配置
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 4.2 路由配置
|
|
94
|
+
|
|
95
|
+
在 `nserve-config/router` 目录下创建路由配置文件,例如 `user.ts`:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { DefineGenRouter } from '@aicblock/nserve'
|
|
99
|
+
|
|
100
|
+
export default DefineGenRouter({
|
|
101
|
+
servicePath: '/api/user', // 路由前缀
|
|
102
|
+
serviceHandler: 'user', // 处理逻辑目录
|
|
103
|
+
routers: [
|
|
104
|
+
{
|
|
105
|
+
path: '/list', // 路由路径
|
|
106
|
+
method: 'GET', // HTTP 方法
|
|
107
|
+
name: 'list', // 处理函数名
|
|
108
|
+
middleware: [] // 路由级中间件
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
path: '/create',
|
|
112
|
+
method: 'POST',
|
|
113
|
+
name: 'create',
|
|
114
|
+
session: {
|
|
115
|
+
/* session 配置 */
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
middleware: ['auth'] // 全局中间件
|
|
120
|
+
})
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 4.3 模型配置
|
|
124
|
+
|
|
125
|
+
在 `nserve-config/model` 目录下创建 SQL 文件,例如 `user.sql`:
|
|
126
|
+
|
|
127
|
+
```sql
|
|
128
|
+
CREATE TABLE `user` (
|
|
129
|
+
`id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
|
|
130
|
+
`username` VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
|
|
131
|
+
`password` VARCHAR(255) NOT NULL COMMENT '密码',
|
|
132
|
+
`email` VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱',
|
|
133
|
+
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
|
|
134
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 5. 命令使用
|
|
138
|
+
|
|
139
|
+
### 5.1 启动开发服务器
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
nserve serve
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
选项:
|
|
146
|
+
|
|
147
|
+
- `--mode <mode>` - 指定运行模式(development/production)
|
|
148
|
+
- `--config <path>` - 指定配置文件路径
|
|
149
|
+
|
|
150
|
+
### 5.2 构建项目
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
nserve build
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
选项:
|
|
157
|
+
|
|
158
|
+
- `--mode <mode>` - 指定构建模式(development/production)
|
|
159
|
+
- `--config <path>` - 指定配置文件路径
|
|
160
|
+
|
|
161
|
+
### 5.3 生成代码
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
nserve gen
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
选项:
|
|
168
|
+
|
|
169
|
+
- `--config <path>` - 指定配置文件路径
|
|
170
|
+
|
|
171
|
+
## 6. 项目结构
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
project/
|
|
175
|
+
├── src/ # 源代码目录
|
|
176
|
+
│ ├── handler/ # 路由处理器
|
|
177
|
+
│ ├── logic/ # 业务逻辑
|
|
178
|
+
│ ├── model/ # 数据模型
|
|
179
|
+
│ └── app.ts # 应用入口
|
|
180
|
+
├── nserve-config/ # 生成配置目录
|
|
181
|
+
│ ├── router/ # 路由配置
|
|
182
|
+
│ └── model/ # 模型 SQL 文件
|
|
183
|
+
├── nserve.config.ts # NServe 配置文件
|
|
184
|
+
└── package.json # 项目配置
|
|
185
|
+
└── tsconfig.json # TypeScript 配置文件
|
|
29
186
|
```
|
|
187
|
+
|
|
188
|
+
## 7. 路由生成流程
|
|
189
|
+
|
|
190
|
+
1. 创建路由配置文件 `nserve-config/router/*.ts`
|
|
191
|
+
2. 运行 `nserve gen` 命令
|
|
192
|
+
3. NServe 会自动生成:
|
|
193
|
+
- 路由处理器文件 `src/handler/*.handler.ts`
|
|
194
|
+
- 业务逻辑模板文件 `src/logic/*/*.logic.ts`
|
|
195
|
+
- 路由注册文件 `src/handler/router.ts`
|
|
196
|
+
|
|
197
|
+
## 8. 模型生成流程
|
|
198
|
+
|
|
199
|
+
1. 创建 SQL 文件 `nserve-config/model/*.sql`
|
|
200
|
+
2. 运行 `nserve gen` 命令
|
|
201
|
+
3. NServe 会自动生成:
|
|
202
|
+
- 数据模型文件 `src/model/*.ts`
|
|
203
|
+
- 模型索引文件 `src/model/index.ts`
|
|
204
|
+
|
|
205
|
+
## 9. 环境变量
|
|
206
|
+
|
|
207
|
+
NServe 支持 `.env` 文件和环境特定的配置文件(如 `.env.development`、`.env.production`)。
|
|
208
|
+
|
|
209
|
+
示例 `.env` 文件:
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
# yamlConfig 配置
|
|
213
|
+
YAML_CONFIG.APP_CONFIG.PORT=3000
|
|
214
|
+
YAML_CONFIG.MYSQL_CONF.host=localhost
|
|
215
|
+
YAML_CONFIG.MYSQL_CONF.port=3306
|
|
216
|
+
YAML_CONFIG.MYSQL_CONF.user=root
|
|
217
|
+
YAML_CONFIG.MYSQL_CONF.password=password
|
|
218
|
+
YAML_CONFIG.MYSQL_CONF.database=test
|
|
219
|
+
|
|
220
|
+
# NServe 配置
|
|
221
|
+
AICBLOCK_NSERVE_APP_ENTRY=app.ts
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## 10. 中间件配置
|
|
225
|
+
|
|
226
|
+
在 `nserve.config.ts` 中配置全局中间件:
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
export default DefineNserveConfig({
|
|
230
|
+
generateConfig: {
|
|
231
|
+
middleware: {
|
|
232
|
+
auth: {
|
|
233
|
+
libName: '@/middleware/auth',
|
|
234
|
+
funcName: 'authMiddleware'
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
在路由配置中使用中间件:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
export default DefineGenRouter({
|
|
245
|
+
routers: [
|
|
246
|
+
{
|
|
247
|
+
path: '/protected',
|
|
248
|
+
method: 'GET',
|
|
249
|
+
name: 'protected',
|
|
250
|
+
middleware: ['auth']
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
})
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## 11. 高级功能
|
|
257
|
+
|
|
258
|
+
### 11.1 自定义插件
|
|
259
|
+
|
|
260
|
+
NServe 支持自定义 esbuild 插件:
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
export default DefineNserveConfig({
|
|
264
|
+
plugins: [
|
|
265
|
+
{
|
|
266
|
+
name: 'custom-plugin',
|
|
267
|
+
setup(build) {
|
|
268
|
+
// 插件逻辑
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
})
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### 11.2 类型定义
|
|
276
|
+
|
|
277
|
+
NServe 提供了完整的 TypeScript 类型定义,可以在项目中直接使用:
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
import type { Config, DefineGenRouterConfig } from '@aicblock/nserve'
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## 12. 最佳实践
|
|
284
|
+
|
|
285
|
+
### 12.1 项目组织
|
|
286
|
+
|
|
287
|
+
- 将路由和业务逻辑分离
|
|
288
|
+
- 使用模型层抽象数据库操作
|
|
289
|
+
- 为不同功能模块创建独立的路由配置文件
|
|
290
|
+
|
|
291
|
+
### 12.2 开发流程
|
|
292
|
+
|
|
293
|
+
1. 创建项目结构
|
|
294
|
+
2. 配置 `nserve.config.ts`
|
|
295
|
+
3. 编写路由配置文件
|
|
296
|
+
4. 编写 SQL 模型文件
|
|
297
|
+
5. 运行 `nserve gen` 生成代码框架
|
|
298
|
+
6. 实现业务逻辑
|
|
299
|
+
7. 使用 `nserve serve` 启动开发服务器进行测试
|
|
300
|
+
8. 使用 `nserve build` 构建生产版本
|
|
301
|
+
|
|
302
|
+
## 13. 常见问题
|
|
303
|
+
|
|
304
|
+
### 13.1 端口被占用
|
|
305
|
+
|
|
306
|
+
如果开发服务器端口被占用,可以在 `.env` 文件中修改 PORT 配置:
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
PORT=3001
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### 13.2 热重载不生效
|
|
313
|
+
|
|
314
|
+
确保:
|
|
315
|
+
|
|
316
|
+
- 源代码目录配置正确
|
|
317
|
+
- 入口文件存在且配置正确
|
|
318
|
+
- 没有语法错误
|
|
319
|
+
|
|
320
|
+
### 13.3 构建失败
|
|
321
|
+
|
|
322
|
+
检查:
|
|
323
|
+
|
|
324
|
+
- TypeScript 语法错误
|
|
325
|
+
- 依赖是否安装正确
|
|
326
|
+
- 配置文件是否正确
|
|
327
|
+
|
|
328
|
+
## 15. 贡献
|
|
329
|
+
|
|
330
|
+
欢迎提交 Issue 和 Pull Request 来改进 NServe。
|
package/lib/commander.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var
|
|
2
|
+
"use strict";var d=Object.create;var l=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var y=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var b=(e,n,t,s)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of m(n))!h.call(e,r)&&r!==t&&l(e,r,{get:()=>n[r],enumerable:!(s=g(n,r))||s.enumerable});return e};var O=(e,n,t)=>(t=e!=null?d(y(e)):{},b(n||!e||!e.__esModule?l(t,"default",{value:e,enumerable:!0}):t,e));var R=require("esbuild");var S=O(require("js-yaml"));function i(e,n="INFO"){let t=(p,f="green")=>`\x1B[${{green:"32m",red:"31m",blue:"34m",orange:"30m"}[f]}${p}\x1B[0m`,r={INFO:"blue",WARNING:"orange",ERROR:"red",SUCCESS:"green"}[n],u=t(n,r);console.log(`[${u}] - ${e}`)}var a=require("./runtime"),o=require("commander"),c=process.argv;c[2]===void 0&&c.push("serve");o.program.version("1.0.2");o.program.on("command:*",function(){let e=o.program.args[0];if(["serve","build","gen"].includes(e)){(0,a.execRun)(e);return}i("See --help for a list of available commands."),i(`Invalid command: ${e}`,"ERROR"),process.exit(0)});o.program.on("--help",function(){console.log("Commands:"),console.log(" serve Start Run the dev server"),console.log(" build Build the project"),console.log(" gen Generate code based on the configuration file")});o.program.parse(c);
|
package/lib/core/run.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var J=Object.create;var _=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var G=Object.getPrototypeOf,W=Object.prototype.hasOwnProperty;var B=(t,n,r,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let e of k(n))!W.call(t,e)&&e!==r&&_(t,e,{get:()=>n[e],enumerable:!(o=K(n,e))||o.enumerable});return t};var S=(t,n,r)=>(r=t!=null?J(G(t)):{},B(n||!t||!t.__esModule?_(r,"default",{value:t,enumerable:!0}):r,t));var T=require("esbuild");var I=require("esbuild"),s=require("fs"),b=require("path"),C=S(require("vm")),L=S(require("js-yaml"));function R(t,n="INFO"){let r=(c,i="green")=>`\x1B[${{green:"32m",red:"31m",blue:"34m",orange:"30m"}[i]}${c}\x1B[0m`,e={INFO:"blue",WARNING:"orange",ERROR:"red",SUCCESS:"green"}[n],l=r(n,e);console.log(`[${l}] - ${t}`)}function P(t){let n=(r,o)=>{try{let e=(0,s.readdirSync)(r);if(e.length===0){(0,s.rmdirSync)(r),o&&o();return}let l=e.length,c=0,i=f=>{f===l&&((0,s.rmdirSync)(r),o&&o())};e.forEach(f=>{let a=(0,b.join)(r,f);if((0,s.statSync)(a).isDirectory()){n(a,()=>{i(c+=1)});return}(0,s.unlinkSync)(a),i(c+=1)})}catch(e){o&&o(e)}};return new Promise((r,o)=>{if(!t||!(0,s.existsSync)(t)){r();return}if(!(0,s.statSync)(t).isDirectory()){o("The directory path to be deleted is not a directory path");return}n(t,e=>{e?o(e):r()})})}function w(t,n){try{let r=(0,s.readFileSync)(t,"utf-8"),o=(0,I.transformSync)(r,{format:"cjs",loader:"ts",platform:"node",target:"node18"}),e={module:{paths:[(0,b.join)(n,"node_modules")],exports:{default:void 0}},require,__dirname:n,global,__filename,process},l=new C.default.Script(o.code);return C.default.createContext(e),l.runInContext(e),e.module.exports.default||e.module.exports}catch(r){console.error(r),process.exit(0)}}async function v(t,n,r={}){let{createDir:o=!0,indent:e=2,noRefs:l=!0,lineWidth:c=80,skipInvalid:i=!1,quotingType:f='"',forceQuotes:a=!1,encoding:g="utf8",...h}=r;try{let p;if(typeof t=="string")try{p=JSON.parse(t)}catch(y){throw new Error(`\u65E0\u6548\u7684 JSON \u5B57\u7B26\u4E32: ${y instanceof Error?y.message:String(y)}`)}else if(typeof t=="object"&&t!==null)p=t;else throw new Error("jsonData \u5FC5\u987B\u662F\u6709\u6548\u7684 JSON \u5B57\u7B26\u4E32\u3001\u5BF9\u8C61\u6216\u6570\u7EC4");let u=L.default.dump(p,{indent:e,noRefs:l,skipInvalid:i,lineWidth:c,quotingType:f,forceQuotes:a,...h,styles:{"!!null":"canonical",...h.styles}});if(o){let y=(0,b.dirname)(n);try{(0,s.accessSync)(y)}catch{(0,s.mkdirSync)(y,{recursive:!0}),console.log(`\u5DF2\u521B\u5EFA\u76EE\u5F55: ${y}`)}}(0,s.writeFileSync)(n,u,{encoding:g});let O=Buffer.byteLength(u,g);return console.log(`YAML \u6587\u4EF6\u5DF2\u6210\u529F\u751F\u6210: ${n}`),console.log(`\u6587\u4EF6\u5927\u5C0F: ${O} \u5B57\u8282`),{content:u,filePath:n,fileSize:O}}catch(p){throw console.error("\u8F6C\u6362\u6216\u4FDD\u5B58\u5931\u8D25:",p instanceof Error?p.message:String(p)),p}}var d=require("path"),N=S(require("os")),m=require("fs"),x=require("child_process");function A(t,n){let r=Date.now(),o=()=>`${Date.now()-r}ms`;try{(0,T.build)(t).then(({errors:e})=>{if(e.length===0){n&&n(),R(`Compile successfully.[${o()}]`,"SUCCESS");return}R(JSON.stringify(e),"ERROR")})}catch(e){R(JSON.stringify(e),"ERROR")}}var U=t=>{let n=t.compilerOptions?.paths||{},r=Object.keys(n);return{name:"alias",setup(o){o.onLoad({filter:/\.ts$/},async e=>{let l=await m.promises.readFile(e.path,"utf8"),c="ts";if(r.length===0)return{contents:l,loader:c};let i=l;return r.forEach(a=>{let g=a.replace(/\*$/,""),h=new RegExp(`from[\\s]{1,}[\\'\\"]${g}((?!\\n[\\'\\"]).)*[\\'\\"]`,"g"),p=(n[a]&&n[a][0]).replace(/\*$/,"");i.replace(h,u=>`from '${u.replace("from","").replace(/['"]/g,"")}'`)}),{contents:i,loader:c}})}}};function Y(t){return new Promise(n=>{let r;N.default.type().startsWith("Windows")?r=`tasklist /FI "PID eq ${t}" /NH`:r=`kill -0 ${t} 2>/dev/null`,(0,x.exec)(r,(o,e,l)=>{o?n(!1):N.default.type().startsWith("Windows")?n(e.includes(t.toString())):n(l==="")})})}var M=(t,n,r,o)=>{let e=()=>{let c=process.platform==="win32"?"node.cmd":"node";return(0,x.spawnSync)(c,[t],{stdio:"inherit",cwd:r}).pid};(0,m.watch)(n,{recursive:!0},(()=>{let c,i=e();return()=>{c&&clearTimeout(c),c=setTimeout(()=>{Y(i).then(f=>{try{f&&process.kill(i),o&&o().then(()=>i=e())}catch(a){R("Fial","ERROR"),console.log(a)}})},500)}})())},q=()=>{try{let t=process.env.AICBLOCK_NSERVE_RUN_CWD,n=process.env.AICBLOCK_NSERVE_RUN_CONFIG_PATH,r=process.env.AICBLOCK_NSERVE_RUN_MODE,o=w(n,process.env.AICBLOCK_NSERVE_RUN_CWD),{entry:e,testing:l,outputDir:c,sourceDir:i,plugins:f,external:a,yamlConfig:g}=o;if(!i||!(0,m.existsSync)((0,d.join)(t,i)))throw Error("[ERROR] The compilation directory is not configured or does not exist");let h=(0,d.join)(t,i,e);if((!e||typeof e!="string"||!(0,m.existsSync)(h))&&r==="serve")throw Error(`[ERROR] The run file does not exist. Please check the config:[${h}]`);let p=!l,u=(0,d.join)(t,c||"dist");r==="build"&&(0,m.existsSync)(u)&&P(u);let O=(0,d.join)(t,"tsconfig.json"),y=(0,m.readFileSync)(O,"utf-8"),F=JSON.parse(y),j={entryPoints:[h],minify:p,outdir:u,plugins:[U(F),...f||[]],bundle:!0,platform:"node",format:"cjs",external:a},$=()=>new Promise(E=>{A(j,()=>{g&&v(g,(0,d.join)(u,"config.yaml")),E(void 0)})});A(j,()=>{if(g&&v(g,(0,d.join)(u,"config.yaml")),r==="build"||!e)return;let E=(0,d.basename)(e),D=E.substring(0,E.length-3)+".js",V=(0,d.join)(u,D);M(V,(0,d.join)(t,i||"src"),u,$)})}catch(t){console.error("[ERROR_STACK]",t);let n=t?.message||"[FN::esbuild::exec]";R(n,"ERROR"),process.exit(0)}};q();
|
package/lib/index.d.ts
CHANGED
|
@@ -4,25 +4,30 @@ export declare const nbuild: {
|
|
|
4
4
|
build: typeof build;
|
|
5
5
|
};
|
|
6
6
|
export declare function DefineNserveConfig(options?: Config): Config | undefined;
|
|
7
|
-
export declare const DefineGenRouter: (param: DefineGenRouterConfig) =>
|
|
8
|
-
prefix: string;
|
|
9
|
-
service: (RouterOption & {
|
|
10
|
-
handler: string;
|
|
11
|
-
})[];
|
|
12
|
-
handler: string;
|
|
13
|
-
};
|
|
7
|
+
export declare const DefineGenRouter: (param: DefineGenRouterConfig) => GenRouterConfig;
|
|
14
8
|
declare const _default: {
|
|
15
9
|
DefineNserveConfig: typeof DefineNserveConfig;
|
|
16
|
-
DefineGenRouter: (param: DefineGenRouterConfig) =>
|
|
17
|
-
prefix: string;
|
|
18
|
-
service: (RouterOption & {
|
|
19
|
-
handler: string;
|
|
20
|
-
})[];
|
|
21
|
-
handler: string;
|
|
22
|
-
};
|
|
10
|
+
DefineGenRouter: (param: DefineGenRouterConfig) => GenRouterConfig;
|
|
23
11
|
};
|
|
24
12
|
export default _default;
|
|
25
13
|
|
|
14
|
+
interface CodePrettierConfigOption {
|
|
15
|
+
/**
|
|
16
|
+
* 是否添加分号
|
|
17
|
+
* Whether to add semicolons
|
|
18
|
+
*/
|
|
19
|
+
semi?: boolean
|
|
20
|
+
/**
|
|
21
|
+
* 是否使用单引号
|
|
22
|
+
* Whether to use single quotes
|
|
23
|
+
*/
|
|
24
|
+
singleQuote?: boolean
|
|
25
|
+
/**
|
|
26
|
+
* 是否使用尾逗号
|
|
27
|
+
* Whether to use trailing commas
|
|
28
|
+
*/
|
|
29
|
+
trailingComma?: 'none' | 'es5' | 'all'
|
|
30
|
+
}
|
|
26
31
|
interface MiddlewareConfigOption {
|
|
27
32
|
/**
|
|
28
33
|
* 中间件库名
|
|
@@ -33,7 +38,7 @@ interface MiddlewareConfigOption {
|
|
|
33
38
|
* 中间件函数名
|
|
34
39
|
* Middleware function name
|
|
35
40
|
*/
|
|
36
|
-
funcName
|
|
41
|
+
funcName?: string
|
|
37
42
|
/**
|
|
38
43
|
* 是否为 AMD 模块
|
|
39
44
|
* Whether it is an AMD module
|
|
@@ -66,7 +71,12 @@ interface GenerateConfigOption {
|
|
|
66
71
|
* 中间件配置
|
|
67
72
|
* Middleware configuration
|
|
68
73
|
*/
|
|
69
|
-
middleware?: MiddlewareConfigOption
|
|
74
|
+
middleware?: Record<string, MiddlewareConfigOption>
|
|
75
|
+
/**
|
|
76
|
+
* 代码格式化配置
|
|
77
|
+
* Code prettier configuration
|
|
78
|
+
*/
|
|
79
|
+
codePrettier?: CodePrettierConfigOption
|
|
70
80
|
}
|
|
71
81
|
interface Config {
|
|
72
82
|
/**
|
|
@@ -134,22 +144,42 @@ type RouterMethod =
|
|
|
134
144
|
| 'CONNECT'
|
|
135
145
|
| 'TRACE'
|
|
136
146
|
|
|
147
|
+
// 数据类型属性定义
|
|
148
|
+
type PropertyType = 'string' | 'number' | 'boolean' | 'object' | 'array'
|
|
149
|
+
|
|
137
150
|
interface DataTypeProperty {
|
|
138
151
|
// 数据类型
|
|
139
|
-
type
|
|
152
|
+
type?: PropertyType | { type: 'custom'; name: string }
|
|
140
153
|
// 数据类型名称
|
|
141
|
-
name
|
|
154
|
+
name?: string
|
|
142
155
|
// 数据类型描述
|
|
143
156
|
description?: string
|
|
144
157
|
// 对象属性定义
|
|
145
|
-
properties?: DataTypeProperty
|
|
146
|
-
//
|
|
147
|
-
|
|
158
|
+
properties?: Record<string, DataTypeProperty>
|
|
159
|
+
// 是否必填
|
|
160
|
+
required?: boolean
|
|
148
161
|
}
|
|
149
|
-
|
|
150
|
-
|
|
162
|
+
|
|
163
|
+
// 泛型参数定义
|
|
164
|
+
interface GenericityParam {
|
|
165
|
+
name: string
|
|
166
|
+
typeParams: string[]
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// 数据类型选项定义
|
|
170
|
+
interface DataTypeOption {
|
|
171
|
+
// 数据类型名称
|
|
151
172
|
name: string
|
|
152
|
-
|
|
173
|
+
// 数据类型
|
|
174
|
+
type?: PropertyType | string
|
|
175
|
+
// 数据类型描述
|
|
176
|
+
description?: string
|
|
177
|
+
// 数据类型属性定义
|
|
178
|
+
properties?: Record<string, DataTypeProperty>
|
|
179
|
+
// 数据类型继承
|
|
180
|
+
extends?: string | string[]
|
|
181
|
+
// 数据类型泛型定义
|
|
182
|
+
genericity?: string | GenericityParam
|
|
153
183
|
}
|
|
154
184
|
|
|
155
185
|
// 路由选项定义
|
|
@@ -163,16 +193,72 @@ interface RouterOption {
|
|
|
163
193
|
// 路由文档备注
|
|
164
194
|
docRemark?: string
|
|
165
195
|
// 路由请求数据类型定义
|
|
166
|
-
requestDataType?:
|
|
196
|
+
requestDataType?: DataTypeOption
|
|
167
197
|
// 路由响应数据类型定义
|
|
168
|
-
responseDataType?:
|
|
198
|
+
responseDataType?: DataTypeOption
|
|
199
|
+
// 路由中间件
|
|
200
|
+
middleware?: RouterMiddleware
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* 路由中间件选项定义
|
|
205
|
+
*/
|
|
206
|
+
interface RouterMiddlewareOption {
|
|
207
|
+
name: string
|
|
208
|
+
value?: Array<string | boolean | number> | (string | boolean | number)
|
|
169
209
|
}
|
|
170
210
|
|
|
211
|
+
/**
|
|
212
|
+
* 路由中间件类型定义
|
|
213
|
+
*/
|
|
214
|
+
type RouterMiddleware =
|
|
215
|
+
| string
|
|
216
|
+
| string[]
|
|
217
|
+
| RouterMiddlewareOption
|
|
218
|
+
| RouterMiddlewareOption[]
|
|
219
|
+
|
|
171
220
|
// 路由配置定义
|
|
172
221
|
interface DefineGenRouterConfig {
|
|
222
|
+
/**
|
|
223
|
+
* 服务路径
|
|
224
|
+
*/
|
|
173
225
|
servicePath: string
|
|
226
|
+
/**
|
|
227
|
+
* 服务处理函数
|
|
228
|
+
*/
|
|
174
229
|
serviceHandler: string
|
|
230
|
+
/**
|
|
231
|
+
* 路由定义
|
|
232
|
+
*/
|
|
175
233
|
routers: RouterOption[]
|
|
234
|
+
/**
|
|
235
|
+
* 路由全局中间件
|
|
236
|
+
*/
|
|
237
|
+
middleware?: RouterMiddleware
|
|
238
|
+
}
|
|
239
|
+
type GenRouterConfigService = RouterOption & {
|
|
240
|
+
/**
|
|
241
|
+
* 路由处理函数
|
|
242
|
+
*/
|
|
243
|
+
handler: string
|
|
244
|
+
}
|
|
245
|
+
interface GenRouterConfig {
|
|
246
|
+
/**
|
|
247
|
+
* 路由前缀
|
|
248
|
+
*/
|
|
249
|
+
prefix: string
|
|
250
|
+
/**
|
|
251
|
+
* 路由处理函数
|
|
252
|
+
*/
|
|
253
|
+
handler: string
|
|
254
|
+
/**
|
|
255
|
+
* 路由服务定义
|
|
256
|
+
*/
|
|
257
|
+
service: GenRouterConfigService[]
|
|
258
|
+
/**
|
|
259
|
+
* 路由全局中间件
|
|
260
|
+
*/
|
|
261
|
+
middleware?: RouterMiddleware
|
|
176
262
|
}
|
|
177
263
|
|
|
178
264
|
type EXEC_COMMAND = 'serve' | 'build' | 'gen'
|
package/lib/index.js
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var T=Object.create;var h=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var D=Object.getPrototypeOf,G=Object.prototype.hasOwnProperty;var F=(e,t)=>{for(var r in t)h(e,r,{get:t[r],enumerable:!0})},x=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of w(t))!G.call(e,n)&&n!==r&&h(e,n,{get:()=>t[n],enumerable:!(s=P(t,n))||s.enumerable});return e};var V=(e,t,r)=>(r=e!=null?T(D(e)):{},x(t||!e||!e.__esModule?h(r,"default",{value:e,enumerable:!0}):r,e)),B=e=>x(h({},"__esModule",{value:!0}),e);var Q={};F(Q,{DefineGenRouter:()=>L,DefineNserveConfig:()=>j,default:()=>z,nbuild:()=>q});module.exports=B(Q);var b=require("esbuild");var K=require("esbuild"),f=require("fs"),m=require("path");var $=V(require("js-yaml"));function v(e,t="INFO"){let r=(c,u="green")=>`\x1B[${{green:"32m",red:"31m",blue:"34m",orange:"30m"}[u]}${c}\x1B[0m`,n={INFO:"blue",WARNING:"orange",ERROR:"red",SUCCESS:"green"}[t],o=r(t,n);console.log(`[${o}] - ${e}`)}function O(e,t){let r=(n,o)=>{if(Object.prototype.toString.call(n)!=="[object Object]"||Object.prototype.toString.call(o)!=="[object Object]")return console.warn("[STACK_LOG] AICBLOCK_UTIL: \u53C2\u6570\u9519\u8BEF"),{};let c={},u=Object.keys(n);return Object.keys(o).filter(l=>!u.includes(l)).forEach(l=>Object.assign(c,{[l]:o[l]})),Object.keys(n).forEach(l=>{let i=o[l],p=n[l];if(i!==void 0&&Object.prototype.toString.call(i)==="[object Object]"&&Object.prototype.toString.call(p)==="[object Object]"){Object.assign(c,{[l]:r(p,i)});return}Object.assign(c,{[l]:i!==void 0?i:p})}),c};return(Array.isArray(t)?t:[t]).reduce((n,o)=>r(n,o),e)}function Y(e,t){let r=e.findIndex(n=>n===t);if(r<0||e.length-1===r)return;let s=e[r+1];if(s.indexOf("--")!==0)return s}function J(e){return e===void 0||e===""||e===null}function M(e){let t={};return e.split(/(\r\n)|[\r\n]/).filter(s=>!J(s)).forEach(s=>{let n=s.split("="),o=(n[0]||"").trim(),c=(n[1]||"").trim();o.split("")[0]!=="#"&&o!==""&&(t[o]=c)}),t}function k(e){let t=Number(e);if(!isNaN(t)&&e.trim()!=="")return t;let r=e.toLowerCase();if(r==="true")return!0;if(r==="false")return!1;if(r==="null")return null;if(r!=="undefined")return e}function U(e,t="."){let r=e.trim().split(`
|
|
2
|
+
`),s={};return r.filter(n=>n.indexOf("YAML_CONFIG"+t)===0).forEach(n=>{if(!n.trim())return;let[o,c]=n.split("=");if(!o||c===void 0)return;let u=o.trim(),a=c.trim(),l=u.split(t),i=s;for(let p=0;p<l.length;p++){let d=l[p];p===l.length-1?i[d]=k(a):((!i[d]||typeof i[d]!="object")&&(i[d]={}),i=i[d])}}),s}function S(e,t){let r={},s={},n={},o=(0,m.join)(e,".env"),c=process.env.AICBLOCK_NSERVE_RUN_ARGV||"[]",u=Y(JSON.parse(c),"--mode"),a=u!==void 0&&u||(t==="build"?"production":"development"),l=(0,m.join)(e,`.env.${a}`),i={},p=[o,l],d=(0,m.join)(e,".env.local");(0,f.existsSync)(d)&&p.push(d);let C=(0,m.join)(e,`.env.${a}.local`);(0,f.existsSync)(C)&&p.push(C);let R=[],_=g=>{if(!(0,f.existsSync)(g))return;let y=(0,f.readFileSync)(g,"utf-8"),E=M(y);R.push(y),Object.assign(i,E)};p.forEach(_);let A=["YAML_CONFIG."];return Object.keys(i).forEach(g=>{if(A.some(I=>g.indexOf(I)===0))return;let y=i[g];if(g.indexOf("AICBLOCK_NSERVE_APP_")===0){r[g]=y;return}let E=t==="serve"?g.replace(/^(APPTEST_)/,""):g;s[E]=y}),R.join("").indexOf("YAML_CONFIG.")>=0&&Object.assign(n,U(R.join(`
|
|
3
|
+
`))),{system:r,app:s,yamlConfig:n}}var W=e=>{let{servicePath:t,serviceHandler:r,routers:s,middleware:n}=e,o=s.map(c=>{let{name:u}=c;return Object.assign(c,{handler:u})});return{prefix:t,service:o,handler:r,middleware:n}},N=W;var q={transformSync:b.transformSync,build:b.build};function j(e){try{let t=process.env.AICBLOCK_NSERVE_RUN_CWD,r=process.env.AICBLOCK_NSERVE_RUN_MODE,s={},n=S(t,r),{app:o,system:c}=n;n.system.AICBLOCK_NSERVE_APP_ENTRY&&Object.assign(s,{entry:n.system.AICBLOCK_NSERVE_APP_ENTRY}),Object.keys(n.yamlConfig||{}).length>0&&Object.assign(s,{yamlConfig:n.yamlConfig.YAML_CONFIG});let u=l=>{let i=o&&o[l];i&&(process.env[l]=i)};Object.keys(o||{}).forEach(u);let a=O({outputDir:"dist",entry:"app.ts",sourceDir:"src"},{...e,envs:{system:c}});return Object.keys(n.yamlConfig||{}).length>0&&(a=O(a||{},{yamlConfig:n.yamlConfig.YAML_CONFIG})),a.lifecycleBefore&&typeof a.lifecycleBefore=="function"&&(a=O(a||{},a.lifecycleBefore(a)||{})),a}catch(t){v("defineNserveConfig fial::","ERROR"),console.error(t)}}var L=N,z={DefineNserveConfig:j,DefineGenRouter:L};0&&(module.exports={DefineGenRouter,DefineNserveConfig,nbuild});
|
package/lib/runtime.js
CHANGED
|
@@ -1,14 +1,31 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var Ne=Object.create;var Y=Object.defineProperty;var xe=Object.getOwnPropertyDescriptor;var Ae=Object.getOwnPropertyNames;var Le=Object.getPrototypeOf,je=Object.prototype.hasOwnProperty;var we=(e,r)=>{for(var o in r)Y(e,o,{get:r[o],enumerable:!0})},fe=(e,r,o,c)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of Ae(r))!je.call(e,i)&&i!==o&&Y(e,i,{get:()=>r[i],enumerable:!(c=xe(r,i))||c.enumerable});return e};var de=(e,r,o)=>(o=e!=null?Ne(Le(e)):{},fe(r||!e||!e.__esModule?Y(o,"default",{value:e,enumerable:!0}):o,e)),De=e=>fe(Y({},"__esModule",{value:!0}),e);var Je={};we(Je,{default:()=>We,execRun:()=>_e});module.exports=De(Je);var q=require("path");var me=require("esbuild"),$=require("fs"),ee=require("path"),Z=de(require("vm")),Ue=de(require("js-yaml"));function S(e,r="INFO"){let o=(l,u="green")=>`\x1B[${{green:"32m",red:"31m",blue:"34m",orange:"30m"}[u]}${l}\x1B[0m`,i={INFO:"blue",WARNING:"orange",ERROR:"red",SUCCESS:"green"}[r],d=o(r,i);console.log(`[${d}] - ${e}`)}function te(e,r){let o=e.findIndex(i=>i===r);if(o<0||e.length-1===o)return;let c=e[o+1];if(c.indexOf("--")!==0)return c}function F(e,r){try{let o=(0,$.readFileSync)(e,"utf-8"),c=(0,me.transformSync)(o,{format:"cjs",loader:"ts",platform:"node",target:"node18"}),i={module:{paths:[(0,ee.join)(r,"node_modules")],exports:{default:void 0}},require,__dirname:r,global,__filename,process},d=new Z.default.Script(c.code);return Z.default.createContext(i),d.runInContext(i),i.module.exports.default||i.module.exports}catch(o){console.error(o),process.exit(0)}}var re=require("fs"),Te=require("child_process");var g=require("fs"),b=require("path");function ge(e){return!e||typeof e!="string"?e:e.replace(/([A-Z])/g," $1").trim().split(/\s+/).join("-").toLowerCase()}function P(e){return!e||typeof e!="string"?e:e.split(/[\-\_]/g).map(o=>o.charAt(0).toUpperCase()+o.slice(1)).join("")}var ve=e=>{let r=[],o=new Map,c=new Map;function i(n){if(!c.has(n))return c.set(n,1),n;let t=c.get(n)+1;return c.set(n,t),`${n}${t}`}function d(n,t,a){let s=[];if(t.type==="array"){if(t.properties&&Object.keys(t.properties).length>0){let p=t.name||i(`${a||"Anonymous"}_${n}_Item`),y=l(p,t.properties,t.description);return y&&(o.set(p,y),s.push(p)),{type:`${p}[]`,generatedInterfaces:s}}return{type:"any[]",generatedInterfaces:s}}if(t.type==="object"&&t.properties){let p=t.name||i(`${a||"Anonymous"}_${n}`),y=l(p,t.properties,t.description);return y&&(o.set(p,y),s.push(p)),{type:p,generatedInterfaces:s}}return typeof t.type=="object"?{type:t.type.name,generatedInterfaces:s}:{type:t.type||"string",generatedInterfaces:s}}function l(n,t,a){let s=[];return a&&s.push(`// ${a}`),Object.entries(t).forEach(([p,y])=>{let h=d(p,y,n),O=y.description?` // ${y.description}`:"",A=` ${p}${y.required===!1?"?":""}: ${h.type};`;s.push(O?`${O}
|
|
2
|
+
${A}`:A)}),s.length===0?`interface ${n} {}`:`interface ${n} {
|
|
3
|
+
${s.join(`
|
|
4
|
+
`)}
|
|
5
|
+
}`}function u(n){if(n.type!==void 0){let s=[];return n.description&&s.push(`// ${n.description}`),s.push(`type ${n.name} = ${n.type};`),s.join(`
|
|
6
|
+
`)}Object.entries(n.properties||{}).forEach(([s,p])=>{d(s,p,n.name)});let t="";if(n.genericity)if(typeof n.genericity=="string"){let s=m(n);s?t=` extends ${n.genericity}<${s}>`:t=` extends ${n.genericity}`}else{let{name:s,typeParams:p}=n.genericity;t=` extends ${s}<${p.join(", ")}>`}else n.extends&&(Array.isArray(n.extends)?t=` extends ${n.extends.join(", ")}`:t=` extends ${n.extends}`);if(n.genericity)return`interface ${n.name}${t} {}`;let a=[];return Object.entries(n.properties||{}).forEach(([s,p])=>{let y=d(s,p,n.name),h=p.description?` // ${p.description}`:"",O=` ${s}${p.required===!1?"?":""}: ${y.type};`;a.push(h?`${h}
|
|
7
|
+
${O}`:O)}),`interface ${n.name}${t} {
|
|
8
|
+
${a.join(`
|
|
9
|
+
`)}
|
|
10
|
+
}`}function m(n){let t=n.properties?.list;if(t&&t.type==="array"&&t.name)return t.name;for(let[a,s]of Object.entries(n.properties||{}))if(s.type==="array"&&s.name)return s.name;return null}let E=u(e);return o.forEach(n=>{r.push(n)}),r.push(E),r.join(`
|
|
11
|
+
|
|
12
|
+
`)},ne=ve;var Me=(e,r,o,c="@")=>{let i=(0,b.join)(r,o,"handler"),d=(0,b.join)(r,o,"logic"),l=(0,b.join)(r,o,"types");!(0,g.existsSync)(i)&&(0,g.mkdirSync)(i,{recursive:!0}),!(0,g.existsSync)(d)&&(0,g.mkdirSync)(d,{recursive:!0}),!(0,g.existsSync)(l)&&(0,g.mkdirSync)(l,{recursive:!0});let m=Object.assign({},{genDir:"nserve-config",routerDir:"router",modelDir:"model"},e),{genDir:E,routerDir:n,middleware:t}=m,a=(0,b.join)(r,E),s=(0,b.join)(a,n||"");if(!(0,g.existsSync)(s)){console.log("[ERROR] API\u63CF\u8FF0\u6587\u4EF6\u4E0D\u5B58\u5728::",s);return}if(!(0,g.statSync)(s).isDirectory()){console.log("[ERROR] API\u63CF\u8FF0\u6587\u4EF6\u4E0D\u662F\u76EE\u5F55");return}let y=(0,g.readdirSync)(s).filter(N=>N.endsWith(".ts")||N.endsWith(".js"));if(y.length===0){console.log("[ERROR] API\u63CF\u8FF0\u6587\u4EF6\u76EE\u5F55\u4E0B\u6CA1\u6709\u63CF\u8FF0\u751F\u6210\u6587\u4EF6");return}let h=[],O=[];y.forEach(N=>{let oe=F((0,b.join)(s,N),__dirname);if(!oe)return;let x=oe,se=N.replace(".ts",".handler"),ie=P(N.replace(".ts",""))+"Server",be=(0,b.join)(i,[se,".ts"].join("")),Ie=[c,"handler",se].join("/");h.push(`import ${ie} from '${Ie}'`),O.push(ie);let k=[],ce=[],K=(0,b.join)(d,x.handler),W=(0,b.join)(l,x.handler);!(0,g.existsSync)(K)&&(0,g.mkdirSync)(K,{recursive:!0}),!(0,g.existsSync)(W)&&(0,g.mkdirSync)(W,{recursive:!0});let ae=["ErrorResponse","SuccessResponse"],J=["import type { Request, Response } from 'express'"],G={},M={};t&&Object.keys(t).forEach(f=>{let{libName:T,funcName:_}=t[f],j=_?`{${_} as ${f}}`:f;G[f]=`import ${j} from '${T}'`}),x.service?.forEach(f=>{let T=ge(f.handler),_=[];if(f.responseDataType&&_.push(ne(f.responseDataType)),f.requestDataType&&_.push(ne(f.requestDataType)),_.length>0){let L=(0,b.join)(W,`${T}.types.d.ts`);(0,g.writeFileSync)(L,_.join(`
|
|
13
|
+
`),"utf-8")}let j=f.method?.toLowerCase()||"get",H=P(f.handler),w=[];if(f.middleware&&m.middleware){let L=Array.isArray(f.middleware)?f.middleware:[f.middleware];if(!L.every(R=>{let I=typeof R=="string"?R:R.name;return!!G[I]}))throw new Error(`[ERROR] \u8DEF\u7531\u914D\u7F6E\u4E2D\u4F7F\u7528\u4E86\u4E0D\u5B58\u5728\u7684\u4E2D\u95F4\u4EF6::${L}`);let B=[];L.forEach(R=>{let I=typeof R=="string"?R:R.name;M[I]=G[I];let pe=(typeof R=="string"?void 0:Array.isArray(R.value)?R.value:[R.value])?.map(z=>typeof z=="string"?`'${z}'`:z),Se=pe?`${I}(${pe.join(",")})`:I;B.push(Se)}),w.push(...B)}let X=[c,"logic",x.handler,T].join("/");k.push(`import ${H} from '${X}.logic'`),ce.push(`Router.${j}('${f.path}',${w.join(",")}${w.length>0?",":""}${H})`),f.docRemark&&J.concat(`// ${f.docRemark}`);let D=[];if(f.requestDataType&&f.requestDataType.properties){let L=f.requestDataType,U=L.properties,B=Object.keys(U).reduce((R,I)=>{let ue=typeof U[I].type=="string"?U[I].type:"object";return R[I]={required:U[I].required===void 0||U[I].required===!0,type:ue},R},{});D.push(`const data = ${f.method==="GET"?"req.query":"req.body"} as ${L.name}`,`CheckFieldRequired(data, ${JSON.stringify(B)})`),ae.push("CheckFieldRequired")}J.push(`import { ${ae.join(",")} } from '@aicblock/nserve/lib/tools'`);let $e=J.concat(`
|
|
14
|
+
${f.docRemark?`// ${f.docRemark}`:""}
|
|
2
15
|
export async function ServiceLogic(req: Request, res: Response) {
|
|
3
16
|
try {
|
|
4
|
-
|
|
17
|
+
// todo: \u63A5\u53E3\u670D\u52A1\u903B\u8F91\u5B9E\u73B0
|
|
18
|
+
${D.join(`
|
|
19
|
+
`)}
|
|
20
|
+
SuccessResponse(res, true)
|
|
5
21
|
} catch (error) {
|
|
6
22
|
ErrorResponse(res, error)
|
|
7
23
|
}
|
|
8
24
|
}
|
|
9
25
|
export default ServiceLogic
|
|
10
|
-
`),
|
|
11
|
-
`))});let
|
|
12
|
-
`))});let
|
|
13
|
-
`)),console.log("[INFO] gen router file ",
|
|
14
|
-
`),"utf-8"),O(`The model file ${
|
|
26
|
+
`),le=(0,b.join)(K,`${T}.logic.ts`);!(0,g.existsSync)(le)&&(0,g.writeFileSync)(le,$e.join(`
|
|
27
|
+
`),"utf-8")});let Q=[];x.middleware&&(Array.isArray(x.middleware)?x.middleware:[x.middleware]).forEach(T=>{let _=typeof T=="string"?T:T.name,j=G[_];if(!j||M[_])return;M[_]=j;let w=(typeof T=="string"?void 0:Array.isArray(T.value)?T.value:[T.value])?.map(D=>typeof D=="string"?`'${D}'`:D),X=w?`${_}(${w.join(",")})`:_;Q.push(X)}),Object.keys(M).forEach(f=>{k.push(M[f])});let Ce=["// Code generated by plugin. Templates Edited by aicblock cli. DO NOT EDIT.","import express from 'express'",...k,"const app = express()","const Router = express.Router()",Q.length>0?`Router.use(${Q.join(",")})`:"",`app.use('${x.prefix}', Router)`,...ce,"export default app"];(0,g.writeFileSync)(be,Ce.join(`
|
|
28
|
+
`))});let A=(0,b.join)(i,"router.ts"),V=["// Code generated by plugin. Templates Edited by aicblock cli. DO NOT EDIT.",...h,"export default [",O.join(","),"]"];(0,g.writeFileSync)(A,V.join(`
|
|
29
|
+
`)),console.log("[INFO] gen router file ",A)},ye=Me;var C=require("fs"),v=require("path");var Pe=new Set(["INT","BIGINT","BIT","DECIMAL","DOUBLE","FLOAT","INTEGER","MEDIUMINT","NUMERIC","REAL","SMALLINT","TINYINT"]);function qe(e){let c=e.replace(/\/\*[\s\S]*?\*\//g,"").trim().replace(/--.*$/gm,"").replace(/\s+/g," "),i=c.match(/CREATE TABLE [`"]?([\w_]+)[`"]?\s*\(/i);if(!i)throw new Error("\u65E0\u6CD5\u89E3\u6790\u8868\u540D");let l={tableName:i[1],columns:[]},u=c.indexOf("("),m=c.lastIndexOf(")");if(u===-1||m===-1||m<=u)throw new Error("\u65E0\u6CD5\u627E\u5230\u5217\u5B9A\u4E49\u90E8\u5206");let E=c.substring(u+1,m);if(!E.trim())return l;let n=Ge(E),t=new Set,a=new Set;return n.forEach(s=>{let p=s.trim();if(p.toUpperCase().startsWith("PRIMARY KEY")){let h=p.match(/PRIMARY KEY\s*\([`"]?([\w_]+)[`"]?\)/i);h&&t.add(h[1]);return}if(p.toUpperCase().startsWith("UNIQUE")){let h=p.match(/\([`"]?([\w_]+)[`"]?(?:\s+ASC|DESC)?\)/i);h&&a.add(h[1]);return}let y=Be(p);y&&l.columns.push(y)}),l.columns.forEach(s=>{t.has(s.name)&&(s.primaryKey=!0),a.has(s.name)&&(s.unique=!0)}),l}function Ge(e){let r=[],o="",c=!1,i=!1,d=0;for(let l=0;l<e.length;l++){let u=e[l],m=l+1<e.length?e[l+1]:"";u==="'"&&!i&&(c=!c),u==="-"&&m==="-"&&!c&&(i=!0),i&&(u===","||u===")")&&(i=!1),u==="("&&!c&&!i&&d++,u===")"&&!c&&!i&&d--,u===","&&!c&&!i&&d===0?(o.trim()&&r.push(o.trim()),o=""):o+=u}return o.trim()&&r.push(o.trim()),r}function Be(e){if(e.toUpperCase().startsWith("PRIMARY KEY")||e.toUpperCase().startsWith("UNIQUE")||e.toUpperCase().startsWith("KEY"))return null;let r=/^[`"]?([\w_]+)[`"]?\s+([a-zA-Z]+)(?:\s*\(\s*(\d+)\s*\))?(?:\s+(?:CHARACTER\s+SET|CHARSET)\s+\w+)?(?:\s+COLLATE\s+\w+)?(?:\s+(NOT\s+NULL|NULL))?(?:\s+UNIQUE)?(?:\s+AUTO_INCREMENT)?(?:\s+DEFAULT\s+([\w'"-]+))?(?:\s+COMMENT\s+'([^']*)')?/i,o=e.match(r);if(!o)return null;let[,c,i,d,l,u,m]=o,E=i.toUpperCase(),n={name:c,dataType:E};if(d&&(n.length=parseInt(d,10)),l&&l.toUpperCase()==="NOT NULL"&&(n.notNull=!0),e.toUpperCase().includes("UNIQUE")&&(n.unique=!0),e.toUpperCase().includes("AUTO_INCREMENT")&&(n.autoIncrement=!0),u!==void 0&&u!==""&&u!=="NULL"){let t=u.trim();if((t.startsWith("'")&&t.endsWith("'")&&t.length>1||t.startsWith('"')&&t.endsWith('"')&&t.length>1)&&(t=t.substring(1,t.length-1)),Pe.has(E)){let a=Number(t);!isNaN(a)&&t!==""?n.defaultValue=a:t!==""&&(n.defaultValue=t)}else t!==""&&(n.defaultValue=t)}return m&&(n.comments=m),n}var Ye=(e,r,o)=>{let c={genDir:"nserve-config",modelDir:"model"},{genDir:i,modelDir:d}=Object.assign({},c,e),l=(0,v.join)(r,i,d);if(!(0,C.existsSync)(l))return;let u=(0,C.readdirSync)(l).filter(s=>s.endsWith(".sql"));if(u.length===0)throw new Error(`The SQL model directory does not contain any SQL files::${l}`);let m=(0,v.join)(r,o,d);(0,C.existsSync)(m)||(0,C.mkdirSync)(m);let E=[],n=[];u.forEach(s=>{let p=(0,v.join)(l,s),y=(0,C.readFileSync)(p,"utf-8");try{let h=qe(y),O=h.tableName,A=(0,v.join)(m,`${O}.ts`),V=["import type { TableOption } from '@dpapejs/emysql'",`const table:TableOption = ${JSON.stringify(h,null,2)}`,"export default table"];(0,C.writeFileSync)(A,V.join(`
|
|
30
|
+
`),"utf-8");let N=P(O);n.push(N),E.push(`import ${N} from './${O}'`),S(`The model file ${O} has been generated::${A}`)}catch{throw new Error(`The SQL file ${s} is not a valid CREATE TABLE statement::${p}`)}});let t=(0,v.join)(m,"index.ts"),a=[...E,`export default [${n.join(", ")}]`];(0,C.writeFileSync)(t,a.join(`
|
|
31
|
+
`),"utf-8"),S(`The model index file has been generated::${t}`)},he=Ye;var Ee=require("child_process"),Re=require("path"),Fe=(e,r,o)=>{try{let c=r||process.cwd();ye(e||{},c,o||"src"),he(e||{},c,o||"src");let i={semi:!1,singleQuote:!0,trailingComma:"none"},{semi:d,singleQuote:l,trailingComma:u}=Object.assign({},i,e?.codePrettier||{}),m=["npx prettier"];d===!1&&m.push("--no-semi"),l===!0&&m.push("--single-quote"),u&&m.push(`--trailing-comma ${u}`);let E=["'logic/**/*.ts'","'handler/**/*.ts'","'model/**/*.ts'","'types/**/*.d.ts'"];m.push("--write",...E);let n=m.join(" "),t=(0,Re.join)(c,o||"src");console.log("[INFO] execRunGen::",t),console.log("[INFO] cmd::",n),(0,Ee.spawnSync)(n,{cwd:t,stdio:"inherit",shell:!0}),S("[INFO] execRunGen","SUCCESS")}catch(c){S("execRunGen fial::","ERROR"),console.error(c)}},Oe=Fe;function Ve(e,r){S(`${r?`The [${r}] app has been `:""}Build DONE. [Build time:${Date.now()-e} ms]`,"SUCCESS")}function ke(e){S(e==="build"?"Build Fail.":"Serve process has exited.","ERROR")}function Ke(){let e=process.cwd(),r=te(process.argv,"--config"),o=(0,q.join)(e,"nserve.config.ts"),c=(0,q.join)(e,"nserve.config.js"),i=r?(0,q.join)(e,r):(0,re.existsSync)(o)?o:c;if(!(0,re.existsSync)(i))throw Error(`The configuration file does not exist. [${i}]`);return i}function _e(e){try{let o=Ke(),c=process.cwd(),i=e,d=te(process.argv,"--mode"),l=JSON.stringify(process.argv),u={AICBLOCK_NSERVE_RUN_CWD:c,AICBLOCK_NSERVE_RUN_CONFIG_PATH:o,AICBLOCK_NSERVE_RUN_MODE:i,AICBLOCK_NSERVE_ENV_MODE:d,AICBLOCK_NSERVE_RUN_ARGV:l};if(Object.keys(u).forEach(a=>{let s=u[a];s!==void 0&&(process.env[a]=s)}),e==="gen"){let{generateConfig:a,sourceDir:s}=F(o,process.cwd());Oe(a||{},c,s||"src");return}let m=Date.now();var r=void 0;let E=process.platform==="win32"?"node.cmd":"node",t=(0,Te.spawn)(E,["./lib/core/run.js","--cmd"],{cwd:(0,q.join)(__dirname,"../"),stdio:e==="build"?"inherit":"pipe",env:Object.assign({},process.env,u)});t.stdout?.on("data",a=>{r&&r.stop(),console.log(a.toString("utf-8"))}),t.stdout?.on("error",a=>{r&&r.stop(),console.log(a.toString())}),t.stderr?.on("data",a=>{r&&r.stop(),console.log(a.toString("utf-8"))}),t.on("exit",a=>{r&&r.stop(),a===0&&e==="build"&&Ve(m,d),a!==0&&ke(e)})}catch(o){S("execRun fial::","ERROR"),console.error(o)}}var We=_e;0&&(module.exports={execRun});
|
package/lib/tools/index.d.ts
CHANGED
|
@@ -2,8 +2,24 @@ import type { Response } from 'express';
|
|
|
2
2
|
export declare function ErrorResponse(res: Response, err: any, code?: number): void;
|
|
3
3
|
export declare function SuccessResponse<T>(res: Response, data?: T, message?: string): void;
|
|
4
4
|
export declare const LoadConfig: (config_path: string) => void;
|
|
5
|
+
export declare const CheckFieldRequired: (data: Record<string, any>, config: Record<string, {
|
|
6
|
+
required: boolean;
|
|
7
|
+
type: "string" | "number" | "array" | "object";
|
|
8
|
+
}>, msg_temp?: {
|
|
9
|
+
required?: string;
|
|
10
|
+
array?: string;
|
|
11
|
+
object?: string;
|
|
12
|
+
}) => void;
|
|
5
13
|
declare const _default: {
|
|
6
14
|
ErrorResponse: typeof ErrorResponse;
|
|
7
15
|
SuccessResponse: typeof SuccessResponse;
|
|
16
|
+
CheckFieldRequired: (data: Record<string, any>, config: Record<string, {
|
|
17
|
+
required: boolean;
|
|
18
|
+
type: "string" | "number" | "array" | "object";
|
|
19
|
+
}>, msg_temp?: {
|
|
20
|
+
required?: string;
|
|
21
|
+
array?: string;
|
|
22
|
+
object?: string;
|
|
23
|
+
}) => void;
|
|
8
24
|
};
|
|
9
25
|
export default _default;
|
package/lib/tools/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var R=Object.create;var f=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,O=Object.prototype.hasOwnProperty;var q=(e,r)=>{for(var t in r)f(e,t,{get:r[t],enumerable:!0})},y=(e,r,t,s)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of E(r))!O.call(e,o)&&o!==t&&f(e,o,{get:()=>r[o],enumerable:!(s=T(r,o))||s.enumerable});return e};var w=(e,r,t)=>(t=e!=null?R(j(e)):{},y(r||!e||!e.__esModule?f(t,"default",{value:e,enumerable:!0}):t,e)),x=e=>y(f({},"__esModule",{value:!0}),e);var S={};q(S,{CheckFieldRequired:()=>b,ErrorResponse:()=>p,LoadConfig:()=>_,SuccessResponse:()=>h,default:()=>k});module.exports=x(S);var l=require("fs"),g=w(require("yaml"));function m(e,r,t=200,s){let i=Object.assign({code:t,data:r,msg:s||"\u6210\u529F"});e.send(i)}function p(e,r,t=500){console.error("[ERROR] STACK_INFO",r);let s=r?.message||"\u670D\u52A1\u5F02\u5E38",o=/^(\[[\d]*\])/,a=s&&s.match(o)&&s.replace(/^(\[[\d]*\]\-)/,"")||s;m(e,null,t,a)}function h(e,r,t){m(e,r,200,t)}var A=e=>{try{if(!(0,l.existsSync)(e))throw Error(`The configuration file does not exist. [${e}]`);let r=(0,l.readFileSync)(e,"utf8");return g.default.parse(r)}catch(r){throw console.error(r),Error()}},_=e=>{try{if(console.info("[INFO] config path::",e),!(0,l.existsSync)(e))throw Error(`The configuration file does not exist. [${e}]`);let r=A(e);if(!r)return;let t=Array.isArray(r),s=o=>{Object.keys(o)?.forEach(a=>{let n=o[a];global[a]=Array.isArray(n)?n.reduce((d,u)=>Object.assign(d,u),{}):n})};t?r.forEach(s):s(r)}catch(r){throw console.error(r),Error("LOAD_CONFIG_PARAM_ERROR")}},b=(e,r,t)=>{if(e==null)throw Error("The data is required.");if(r==null)throw Error("The config is required.");let o={...{required:"The field [${key}] is required.",array:"The field [${key}] must be an array with at least one element.",object:"The field [${key}] must be an object."},...t},i=(n,d)=>n.replace(/\$\{key\}/g,d);Object.keys(r).forEach(n=>{if(!r[n].required)return;let u=r[n].type,c=e[n];if(c==null)throw Error(i(o.required,n));if(u==="array"&&(!Array.isArray(c)||c.length===0))throw Error(i(o.array,n));if(u==="object"&&(Object.prototype.toString.call(c)!=="[object Object]"||Object.keys(c).length===0))throw Error(i(o.object,n))})},k={ErrorResponse:p,SuccessResponse:h,CheckFieldRequired:b};0&&(module.exports={CheckFieldRequired,ErrorResponse,LoadConfig,SuccessResponse});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aicblock/nserve",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "🛠️ Description NodeJS Server-side development CLI",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"serve-cli",
|
|
14
14
|
"node-server"
|
|
15
15
|
],
|
|
16
|
+
"homepage": "http://nserve.aicblock.cn/",
|
|
16
17
|
"bin": {
|
|
17
18
|
"nserve": "lib/commander.js"
|
|
18
19
|
},
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
"esbuild": "0.27.2",
|
|
51
52
|
"express": "5.2.1",
|
|
52
53
|
"js-yaml": "4.1.1",
|
|
54
|
+
"prettier": "3.7.4",
|
|
53
55
|
"yaml": "2.8.2"
|
|
54
56
|
}
|
|
55
57
|
}
|