evaengine 1.0.2 → 1.0.4

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 CHANGED
@@ -2,113 +2,443 @@
2
2
 
3
3
  [![NPM version](https://img.shields.io/npm/v/evaengine.svg?style=flat-square)](http://badge.fury.io/js/evaengine)
4
4
  [![CI](https://github.com/EvaEngine/EvaEngine.js/actions/workflows/ci.yml/badge.svg)](https://github.com/EvaEngine/EvaEngine.js/actions/workflows/ci.yml)
5
- [![codecov](https://codecov.io/gh/EvaEngine/EvaEngine.js/branch/master/graph/badge.svg)](https://codecov.io/gh/EvaEngine/EvaEngine.js)
5
+ [![codecov](https://codecov.io/gh/EvaEngine/EvaEngine.js/branch/main/graph/badge.svg)](https://codecov.io/gh/EvaEngine/EvaEngine.js)
6
6
  [![npm](https://img.shields.io/npm/dm/evaengine.svg?maxAge=2592000)](https://www.npmjs.com/package/evaengine)
7
- [![License](https://img.shields.io/npm/l/evaengine.svg?maxAge=2592000?style=plastic)](https://github.com/EvaEngine/EvaEngine.js/blob/master/LICENSE)
7
+ [![License](https://img.shields.io/npm/l/evaengine.svg?maxAge=2592000?style=plastic)](https://github.com/EvaEngine/EvaEngine.js/blob/main/LICENSE)
8
8
 
9
- EvaEngine is a lightweight Node.js microservice development engine. It gives you dependency injection, middleware, CLI commands, scheduled jobs, session and auth helpers, cache support, Swagger generation, and a simple way to structure services.
9
+ 面向 Node.js 微服务的 **Application Runtime**:同一套引擎覆盖 **HTTP**、**CLI**、**定时任务**,并提供 DI、Provider、中间件、配置、缓存、鉴权辅助、实体(Sequelize)、异常体系与 Swagger 生成。
10
10
 
11
- ## Requirements
11
+ > **消费方(人与 agent):** 本 README 即为完整对外说明。使用本包**不需要**阅读仓库内的 `docs/`。
12
12
 
13
- - Node.js 24 or newer
14
- - npm
13
+ ## 环境要求
15
14
 
16
- ## Install
15
+ - Node.js **≥ 24**
16
+ - ESM(`"type": "module"`)
17
+ - npm(或其它可从 npm registry 安装的客户端)
17
18
 
18
- For a new project:
19
+ ## 安装
19
20
 
20
21
  ```bash
21
22
  npm install evaengine
22
23
  ```
23
24
 
24
- For local development of this repository:
25
+ 可选脚手架:[EvaSkeleton.js](https://github.com/EvaEngine/EvaSkeleton.js)。
25
26
 
26
- ```bash
27
- git clone https://github.com/EvaEngine/EvaEngine.js.git
28
- cd EvaEngine.js
29
- npm install
27
+ ## 导入方式(重要)
28
+
29
+ 包的 **default 导出** 是一个 `core` 对象。顶层具名导出只有 `default` 与 `core`(同一对象)。
30
+
31
+ ```js
32
+ import eva from 'evaengine';
33
+ // 或:import { core as eva } from 'evaengine';
34
+
35
+ const {
36
+ EvaEngine,
37
+ Command,
38
+ DI,
39
+ Entities,
40
+ express,
41
+ wrapper,
42
+ services,
43
+ middlewares,
44
+ providers,
45
+ exceptions,
46
+ swagger,
47
+ utils,
48
+ commands, // 内置 CLI 命令
49
+ Joi,
50
+ sequelize
51
+ } = eva;
30
52
  ```
31
53
 
32
- ## Quick Start
54
+ **不要**依赖 `import { EvaEngine } from 'evaengine'`——该具名导出不存在。
55
+
56
+ ---
57
+
58
+ ## 心智模型
59
+
60
+ ```text
61
+ new EvaEngine(meta, mode?)
62
+ → 绑定 base 服务(env, config, logger, namespace, now, event_manager)
63
+ → bootstrap() # web 服务 + 中间件 Provider
64
+ → use(...) / registerCommands
65
+ → run() | runHttps() | runCLI() | runCrontab() | runCommand()
66
+ ```
67
+
68
+ | 模式 | 典型流程 |
69
+ |------|----------|
70
+ | `web`(默认) | `bootstrap()` → `use()` → `run()` / `runHttps()` |
71
+ | `cli` | `registerCommands()` → `runCLI()` / `runCrontab()` / `runCommand()` |
72
+
73
+ **进程级事实(按每进程一个 Engine 规划):**
33
74
 
34
- ### Run as a web server
75
+ - `DI` 是**全局**容器。
76
+ - `EvaEngine.getApp()` 是**模块级** Express app 单例。
77
+ - `bootstrap()` 注册 **web** 服务与中间件 Provider;CLI 路径在 `getCLI` / `runCrontab` 内注册 CLI 服务。
78
+ - 内置 `EventManager` **仅进程内**(不是消息队列)。
79
+
80
+ ---
81
+
82
+ ## 快速开始
83
+
84
+ ### Web
35
85
 
36
86
  ```js
37
- import { EvaEngine } from 'evaengine';
87
+ import eva from 'evaengine';
88
+
89
+ const { EvaEngine, DI, wrapper, exceptions } = eva;
90
+ const { UnauthorizedException } = exceptions;
38
91
 
39
92
  const engine = new EvaEngine({
40
93
  projectRoot: process.cwd(),
41
- port: 3000
94
+ port: Number(process.env.PORT) || 3000
95
+ // configPath、sourceRoot 可选
42
96
  });
43
97
 
44
98
  engine.bootstrap();
45
- engine.use('/', (req, res) => {
46
- res.json({ hello: 'world' });
99
+
100
+ // 可选横切中间件(须在 bootstrap 之后)
101
+ engine.use(DI.get('trace')());
102
+ // engine.use(DI.get('session')());
103
+ // engine.use(DI.get('auth')());
104
+
105
+ engine.use('/health', (req, res) => {
106
+ res.json({ ok: true });
47
107
  });
108
+
109
+ engine.use('/me', wrapper(async (req, res) => {
110
+ if (!req.auth?.uid) {
111
+ throw new UnauthorizedException('Login required');
112
+ }
113
+ res.json({ uid: req.auth.uid });
114
+ }));
115
+
48
116
  engine.run();
49
117
  ```
50
118
 
51
- Then open http://localhost:3000.
52
-
53
- ### Run as a CLI app
119
+ ### CLI
54
120
 
55
121
  ```js
56
- import { EvaEngine } from 'evaengine';
122
+ import eva from 'evaengine';
57
123
  import * as UserCommands from './commands/user.js';
58
124
 
59
- const engine = new EvaEngine({
60
- projectRoot: process.cwd()
61
- }, 'cli');
125
+ const { EvaEngine } = eva;
62
126
 
127
+ const engine = new EvaEngine({ projectRoot: process.cwd() }, 'cli');
63
128
  engine.registerCommands(UserCommands);
64
-
65
129
  await engine.runCLI();
130
+ // node app.js user:create --name=Ada
66
131
  ```
67
132
 
68
- ### Run as a cron job
133
+ ### 定时任务
69
134
 
70
135
  ```js
71
- import { EvaEngine } from 'evaengine';
72
- import * as HelloWorldCommands from './commands/hello_world.js';
136
+ import eva from 'evaengine';
137
+ import * as Jobs from './commands/jobs.js';
73
138
 
74
- const engine = new EvaEngine({
75
- projectRoot: process.cwd()
76
- }, 'cli');
139
+ const { EvaEngine } = eva;
77
140
 
78
- engine.registerCommands([HelloWorldCommands]);
141
+ const engine = new EvaEngine({ projectRoot: process.cwd() }, 'cli');
142
+ engine.registerCommands([Jobs]);
143
+ // 六段 cron(含秒)等细节见 runCrontab 第三参数 useSeconds
79
144
  engine.runCrontab('0/10 * * * * *', 'hello:world --id=EvaEngine');
80
145
  ```
81
146
 
82
- ## Common Commands
147
+ ### 内置 CLI 二进制
83
148
 
84
149
  ```bash
85
- npm run lint
86
- npm run build
87
- npm test
150
+ npx engine
151
+ npx engine make:entity
152
+ npx engine make:dbview
153
+ npx engine make:graphql
154
+ npx engine tramp:dump-config
155
+ ```
156
+
157
+ 配合 Spring Cloud Config(仅 bin):
158
+
159
+ - `SPRING_CONFIG_ENDPOINT`(设置后启用)
160
+ - `SPRING_CONFIG_NAME`、`SPRING_CONFIG_PROFILES`、`SPRING_CONFIG_LABEL`
161
+
162
+ ---
163
+
164
+ ## 推荐项目结构
165
+
166
+ ```text
167
+ project/
168
+ package.json # "type": "module"
169
+ config/
170
+ config.default.cjs
171
+ config.development.cjs
172
+ config.production.cjs
173
+ config.local.development.cjs # 本地覆盖,建议 gitignore
174
+ src/
175
+ app.js # web 入口
176
+ cli.js
177
+ commands/
178
+ entities/
179
+ routes/
180
+ test/
88
181
  ```
89
182
 
90
- ## Environment Variables
183
+ ---
91
184
 
92
- Common variables include:
185
+ ## 配置
93
186
 
94
- - `NODE_ENV`
95
- - `PORT`
96
- - `LOG_LEVEL`
97
- - `CLI_NAME`
98
- - `MAX_REQUEST_DEBUG_BODY`
99
- - `SEQUELIZE_REPLICATION_CONFIG_KEY`
187
+ 配置目录为 `{projectRoot}/config`(可用构造参数 `configPath` 覆盖),按以下顺序合并:
100
188
 
101
- ## Generate entities
189
+ 1. 引擎内置默认(随包提供)
190
+ 2. `config.default.cjs`
191
+ 3. `config.<NODE_ENV>.cjs`
192
+ 4. 可选 `config.local.<NODE_ENV>.cjs`(不存在则忽略)
102
193
 
103
- ```bash
104
- ./node_modules/.bin/engine make:entity
105
- ./node_modules/.bin/engine make:dbview
194
+ 配置文件使用 **CommonJS** `.cjs`(经 `require` 加载)。
195
+
196
+ ```js
197
+ // config/config.default.cjs
198
+ module.exports = {
199
+ app: { name: 'my-service' },
200
+ redis: { host: '127.0.0.1', port: 6379, lazyConnect: true },
201
+ cache: { prefix: 'myapp', driver: 'redis' },
202
+ token: {
203
+ secret: process.env.TOKEN_SECRET || '',
204
+ provider: undefined, // 设为 'kong' 时使用 Kong JWT 与对应 auth 中间件
205
+ faker: { enable: false, key: 'eva', uid: 1 }
206
+ },
207
+ session: {
208
+ secret: process.env.SESSION_SECRET || 'change-me',
209
+ resave: true,
210
+ saveUninitialized: true,
211
+ cookie: { path: '/', httpOnly: true, secure: false, maxAge: 3600_000 }
212
+ },
213
+ db: {
214
+ dialect: 'mysql',
215
+ port: 3306,
216
+ database: '',
217
+ replication: {
218
+ write: { host: '', username: '', password: '', pool: {} },
219
+ read: []
220
+ }
221
+ }
222
+ };
223
+ ```
224
+
225
+ 运行时读取:
226
+
227
+ ```js
228
+ const config = DI.get('config');
229
+ config.get('redis.host');
230
+ config.get(); // 完整对象
231
+ ```
232
+
233
+ ### 环境变量
234
+
235
+ | 变量 | 作用 |
236
+ |------|------|
237
+ | `NODE_ENV` | 选择 `config.<env>.cjs` |
238
+ | `PORT` | 常见应用端口(使用时传入构造参数) |
239
+ | `LOG_LEVEL` | 覆盖日志级别 |
240
+ | `TZ` | moment 默认时区(未设置时为 `Asia/Shanghai`) |
241
+ | `CLI_NAME` | CLI 模式下 logger 标签 |
242
+ | `MAX_REQUEST_DEBUG_BODY` | debug 中间件 body 限制 |
243
+ | `SEQUELIZE_REPLICATION_CONFIG_KEY` | `db` 下 replication 配置的替代键名 |
244
+ | `SPRING_CONFIG_*` | bin 远程配置(见上文) |
245
+
246
+ ---
247
+
248
+ ## DI 与服务
249
+
250
+ ```js
251
+ DI.get('logger').info('hello');
252
+ DI.get('redis').getInstance();
253
+ DI.get('cache'); // 缓存门面
254
+ DI.get('jwt');
255
+ DI.get('http_client');
256
+ DI.get('rest_client');
257
+ DI.get('event_manager');
258
+ DI.get('namespace');
259
+ DI.get('now');
260
+ DI.get('env');
261
+ DI.get('validator_base');
106
262
  ```
107
263
 
108
- ## Start from a skeleton project
264
+ | DI 名 | 绑定时机 |
265
+ |-------|----------|
266
+ | `env`、`config`、`logger`、`namespace`、`now`、`event_manager` | 构造时(base) |
267
+ | `redis`、`cache`、`http_client`、`rest_client`、`validator_base`、`jwt` | `bootstrap()`(web)或 CLI 执行路径 |
268
+ | 下文中间件名 | `bootstrap()` |
269
+
270
+ **自定义 Provider:**
271
+
272
+ ```js
273
+ import eva from 'evaengine';
274
+
275
+ const { DI, providers } = eva;
276
+ const { ServiceProvider } = providers.services;
277
+
278
+ class MyApiProvider extends ServiceProvider {
279
+ get name() { return 'my_api'; }
280
+ register() {
281
+ DI.bindValue(this.name, { ping: () => 'pong' });
282
+ }
283
+ }
284
+
285
+ engine.registerService(MyApiProvider);
286
+ // 或替换整表:
287
+ // EvaEngine.setServiceProvidersForWeb([...EvaEngine.getServiceProvidersForWeb(), MyApiProvider]);
288
+ ```
289
+
290
+ 测试辅助:`DI.reset()`、`DI.registerMockedProviders(providers, configPath)`、`DI.bindClass` / `bindValue` / `bindMethod`。
291
+
292
+ ---
109
293
 
110
- If you want a ready-made starting point, use the skeleton repository:
294
+ ## 中间件
111
295
 
112
- - [EvaSkeleton.js](https://github.com/EvaEngine/EvaSkeleton.js)
296
+ `bootstrap()` 之后按名称绑定工厂。**需要调用工厂**(注意部分场景二次调用):
297
+
298
+ ```js
299
+ engine.use(DI.get('trace')());
300
+ engine.use(DI.get('session')());
301
+ engine.use(DI.get('auth')());
302
+ // validator 是高阶工厂:
303
+ engine.use('/items', DI.get('validator')(() => ({
304
+ query: eva.Joi.object({ page: eva.Joi.number().integer().required() })
305
+ })), handler);
306
+ ```
307
+
308
+ | 名称 | 作用 |
309
+ |------|------|
310
+ | `session` | `express-session`(经 connect-redis 的 Redis 存储) |
311
+ | `auth` | 从 `X-Token` 或 `api_key` 取 JWT,或 session `uid`;可选 faker token |
312
+ | `trace` | 请求追踪(与 namespace 协作) |
313
+ | `validator` | Joi 请求校验 |
314
+ | `view_cache` | 响应缓存辅助 |
315
+ | `debug` | 调试输出 |
316
+
317
+ 当 `config.token.provider === 'kong'` 时,`jwt` 服务与 `auth` 中间件均切换为 Kong 实现。
318
+
319
+ 使用 `wrapper(async (req,res) => …)`,以便抛出的 `exceptions.*` 进入默认错误处理器。
320
+
321
+ ---
322
+
323
+ ## 命令(Command)
324
+
325
+ ```js
326
+ import eva from 'evaengine';
327
+
328
+ const { Command, DI } = eva;
329
+
330
+ export class HelloWorld extends Command {
331
+ static getName() { return 'hello:world'; }
332
+ static getDescription() { return 'Say hello'; }
333
+ static getSpec() {
334
+ return {
335
+ id: { type: 'string', description: 'Who to greet' }
336
+ };
337
+ }
338
+ async run() {
339
+ const { id = 'world' } = this.getOptions();
340
+ DI.get('logger').info(`Hello ${id}`);
341
+ }
342
+ }
343
+ ```
344
+
345
+ 通过 `engine.registerCommands(moduleExports)` 或模块数组注册。名称来自 `getName()`。
346
+
347
+ Engine API:`runCLI()`、`runCommand('name --flag=1')`、`runCrontab(expression, 'name --flag=1', useSeconds?)`、`clearCommands()`、`clearCrontabs()`。
348
+
349
+ ---
350
+
351
+ ## 实体(Sequelize)
352
+
353
+ ```js
354
+ import path from 'path';
355
+ import eva from 'evaengine';
356
+
357
+ const { Entities, DI } = eva;
358
+
359
+ const entities = new Entities(path.join(process.cwd(), 'src/entities'));
360
+ entities.init(); // 按 config.db 构建 Sequelize 并扫描目录
361
+
362
+ const User = entities.get('user');
363
+ const all = entities.getAll();
364
+ await entities.getTransaction(async (t) => { /* … */ });
365
+ ```
366
+
367
+ 实体文件(经 `require` 加载的 CJS 或 ESM 工厂):
368
+
369
+ ```js
370
+ // src/entities/user.cjs
371
+ module.exports = (sequelize, DataTypes) =>
372
+ sequelize.define('user', {
373
+ id: { type: DataTypes.INTEGER.UNSIGNED, primaryKey: true, autoIncrement: true },
374
+ name: { type: DataTypes.STRING, allowNull: false }
375
+ }, { tableName: 'users' });
376
+ ```
377
+
378
+ ---
379
+
380
+ ## 异常
381
+
382
+ ```js
383
+ import eva from 'evaengine';
384
+
385
+ const {
386
+ StandardException,
387
+ LogicException,
388
+ InvalidArgumentException,
389
+ UnauthorizedException,
390
+ ResourceNotFoundException,
391
+ RuntimeException
392
+ // …完整列表见包导出 exceptions
393
+ } = eva.exceptions;
394
+ ```
395
+
396
+ 默认 HTTP 错误处理器在 `run` / `runHttps` 时挂载:将 `StandardException` 子类映射为 JSON 与状态码;生产环境会剥离 stack 等细节。
397
+
398
+ ---
399
+
400
+ ## Swagger
401
+
402
+ 使用 `eva.swagger`(`ExSwagger`、注解辅助等)从源码注释与模型生成 Swagger 2.0。在应用脚本中自行接入生成流程;UI 资源来自依赖 `swagger-ui-dist`。
403
+
404
+ ---
405
+
406
+ ## EvaEngine API 一览
407
+
408
+ ```text
409
+ constructor({ projectRoot, configPath?, sourceRoot?, port?, config?, logger?, namespace? }, mode?='web')
410
+ getMeta() getDI()
411
+ bootstrap() use(...args) run(port?) runHttps(port?, options?) getServer()
412
+ registerCommands(commands) getCommands() clearCommands() getCommand() getCommandName()
413
+ runCLI(name?) runCommand(commandString) runCrontab(seq, commandString, useSeconds?) clearCrontabs()
414
+ registerServiceProviders(providers) registerService(ProviderClass)
415
+ setDefaultErrorHandler / getDefaultErrorHandler
416
+ setUncaughtExceptionHandler / getUncaughtExceptionHandler
417
+ setServerErrorHandler / getServerErrorHandler
418
+ static getApp() createRouter() getVersion()
419
+ static get/set BaseServiceProviders | ServiceProvidersForWeb | ServiceProvidersForCLI | MiddlewareProviders
420
+ ```
421
+
422
+ ---
423
+
424
+ ## 本库不是什么
425
+
426
+ - 不只是 Express 薄封装——HTTP 只是入口之一
427
+ - 不是业务领域框架或业务规则层
428
+ - 不是消息总线(可靠投递请用真正的 MQ)
429
+ - 不是完整 ORM 产品——仅提供 Sequelize 集成辅助
430
+
431
+ ---
432
+
433
+ ## 本仓库开发
434
+
435
+ ```bash
436
+ git clone https://github.com/EvaEngine/EvaEngine.js.git
437
+ cd EvaEngine.js
438
+ npm install
439
+ npm run lint
440
+ npm run build
441
+ npm test # 部分测试需要本机 Redis 127.0.0.1:6379
442
+ ```
113
443
 
114
- For project conventions and setup guidance, see [docs/new_project_guide.md](docs/new_project_guide.md).
444
+ 发版:在 `main` 上由 semantic-release(Conventional Commits)执行——仅发布 npm,不创建 GitHub Release。维护者文档在 git 的 `docs/` 下,**npm 消费方无需阅读**。
package/bin/engine CHANGED
@@ -13,7 +13,7 @@ try {
13
13
  endpoint: process.env.SPRING_CONFIG_ENDPOINT,
14
14
  name: process.env.SPRING_CONFIG_NAME || 'unknown-spring-config-name',
15
15
  profiles: process.env.SPRING_CONFIG_PROFILES || process.env.NODE_ENV,
16
- label: process.env.SPRING_CONFIG_LABEL || 'master'
16
+ label: process.env.SPRING_CONFIG_LABEL || 'main'
17
17
  });
18
18
  }
19
19
  await engine.runCLI();
package/package.json CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "name": "evaengine",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "EvaEngine for Node.js, a micro service development engine",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
- "package-lock": false,
8
7
  "repository": {
9
8
  "type": "git",
10
9
  "url": "https://github.com/EvaEngine/EvaEngine.js.git"
@@ -12,8 +11,7 @@
12
11
  "scripts": {
13
12
  "prestart": "node src/index.js",
14
13
  "prepublish": "npm run test",
15
- "ava": "cross-env LOG_LEVEL=error NODE_ENV=test ava --verbose --serial",
16
- "test": "nyc -a --reporter=lcov --reporter=text --reporter=html npm run ava",
14
+ "test": "LOG_LEVEL=error NODE_ENV=test node --import ./test/bootstrap.js --test --test-concurrency=1 --experimental-test-coverage \"test/di.js\" \"test/engine.js\" \"test/error_handlers.js\" \"test/index.js\" \"test/exceptions/index.js\" \"test/entities/index.js\" \"test/commands/make_entity.js\" \"test/middlewares/*.js\" \"test/services/*.js\" \"test/swagger/index.js\" \"test/utils/*.js\"",
17
15
  "lint": "eslint src test index.js",
18
16
  "build": "node --check src/index.js",
19
17
  "ci:check": "npm run lint && npm run build",
@@ -38,31 +36,6 @@
38
36
  "lint"
39
37
  ],
40
38
  "author": "AlloVince",
41
- "ava": {
42
- "files": [
43
- "test/**/*.js",
44
- "!test/bootstrap.js",
45
- "!test/_*/**/*.js",
46
- "!test/swagger/_*/**/*.js"
47
- ],
48
- "source": [
49
- "src/**/*.js"
50
- ],
51
- "failFast": false,
52
- "tap": false,
53
- "require": [
54
- "./test/bootstrap.js"
55
- ]
56
- },
57
- "nyc": {
58
- "require": [],
59
- "include": [
60
- "src/**/*.js"
61
- ],
62
- "exclude": [
63
- "src/config/index.js"
64
- ]
65
- },
66
39
  "dependencies": {
67
40
  "acorn": "^8.18.0",
68
41
  "app-root-path": "^3.1.0",
@@ -73,24 +46,15 @@
73
46
  "doctrine": "^3.0.0",
74
47
  "express": "^5.2.1",
75
48
  "express-session": "^1.19.0",
76
- "glob": "^13.0.6",
77
49
  "ioredis": "^5.11.1",
78
50
  "joi": "^18.2.3",
79
51
  "js-yaml": "^5.2.2",
80
52
  "jwt-simple": "^0.5.6",
81
- "later": "^1.2.0",
82
53
  "lodash": "^4.18.1",
83
- "mkdirp": "^3.0.1",
84
- "moment": "^2.30.1",
85
54
  "moment-timezone": "^0.6.3",
86
55
  "morgan": "^1.11.0",
87
- "mysql": "^2.18.1",
88
56
  "mysql2": "^3.23.2",
89
57
  "node-mocks-http": "~1.18.1",
90
- "on-headers": "^1.1.0",
91
- "pug": "^3.0.4",
92
- "request": "^2.88.2",
93
- "request-promise-native": "^1.0.9",
94
58
  "sequelize": "^6.37.8",
95
59
  "swagger-ui-dist": "^5.32.11",
96
60
  "winston": "^3.19.0",
@@ -101,18 +65,12 @@
101
65
  "@semantic-release/changelog": "^6.0.0",
102
66
  "@semantic-release/commit-analyzer": "^13.0.0",
103
67
  "@semantic-release/git": "^10.0.0",
104
- "@semantic-release/github": "^11.0.0",
105
68
  "@semantic-release/npm": "^12.0.0",
106
69
  "@semantic-release/release-notes-generator": "^14.0.0",
107
- "ava": "^8.0.1",
108
70
  "conventional-changelog-conventionalcommits": "^8.0.0",
109
- "cross-env": "^10.1.0",
110
71
  "eslint": "^9.39.5",
111
72
  "eslint-plugin-import": "^2.32.0",
112
73
  "globals": "^17.8.0",
113
- "is-type-of": "^2.2.0",
114
- "nock": "^14.0.17",
115
- "nyc": "^18.0.0",
116
74
  "pre-commit": "^2.0.0",
117
75
  "semantic-release": "^25.0.8"
118
76
  }
@@ -1,7 +1,7 @@
1
- import _ from 'lodash';
1
+ import groupBy from 'lodash/groupBy.js';
2
+ import template from 'lodash/template.js';
2
3
  import Sequelize from 'sequelize';
3
4
  import fs from 'fs';
4
- import * as mkdirp from 'mkdirp';
5
5
  import Command from './interface.js';
6
6
  import DI from '../di.js';
7
7
  import Entities from '../entities/index.js';
@@ -55,7 +55,7 @@ CREATE ALGORITHM=UNDEFINED SQL SECURITY DEFINER VIEW view_${tableName}
55
55
  const entities = new Entities(entityPath);
56
56
 
57
57
  logger.info('Start generate db views to %s', file);
58
- mkdirp.sync(path);
58
+ fs.mkdirSync(path, { recursive: true });
59
59
  const models = Object.values(entities.getInstance().models);
60
60
  const sql = [];
61
61
  models.forEach((model) => {
@@ -202,7 +202,7 @@ export class MakeEntity extends Command {
202
202
  if (!rawIndexes) {
203
203
  return [];
204
204
  }
205
- rawIndexes = _.groupBy(rawIndexes, 'Key_name');
205
+ rawIndexes = groupBy(rawIndexes, 'Key_name');
206
206
  return Object.entries(rawIndexes).filter(([key]) => key !== 'PRIMARY').map(([name, columns]) => {
207
207
  const index = columns[0].Non_unique !== 1 ? { name, unique: true } : { name };
208
208
  index.fields = columns.map(c => c.Column_name);
@@ -239,8 +239,8 @@ export class MakeEntity extends Command {
239
239
  const schemaPath = `${path}/schemas`;
240
240
  const entityTemplate = fs.readFileSync(`${import.meta.dirname}/../../template/entity.ejs`, 'utf8');
241
241
  const schemaTemplate = fs.readFileSync(`${import.meta.dirname}/../../template/schema.ejs`, 'utf8');
242
- mkdirp.sync(path);
243
- mkdirp.sync(schemaPath);
242
+ fs.mkdirSync(path, { recursive: true });
243
+ fs.mkdirSync(schemaPath, { recursive: true });
244
244
 
245
245
  logger.info('Start generate DB schemas to dir %s', path);
246
246
 
@@ -269,7 +269,7 @@ export class MakeEntity extends Command {
269
269
  fs.accessSync(entityFile);
270
270
  logger.info('Entity file %s generate skipped, already exists by %s', table, entityFile);
271
271
  } catch {
272
- fs.writeFileSync(entityFile, _.template(entityTemplate)({ table }));
272
+ fs.writeFileSync(entityFile, template(entityTemplate)({ table }));
273
273
  logger.info('Entity file %s generated as %s', table, entityFile);
274
274
  }
275
275
 
@@ -279,7 +279,7 @@ export class MakeEntity extends Command {
279
279
  } catch {
280
280
  logger.info('Schema file %s generated as %s', table, schemaFile);
281
281
  }
282
- fs.writeFileSync(schemaFile, _.template(schemaTemplate)({
282
+ fs.writeFileSync(schemaFile, template(schemaTemplate)({
283
283
  columns,
284
284
  table,
285
285
  indexes,
@@ -438,8 +438,8 @@ export class MakeGraphql extends Command {
438
438
  const mappingContent = JSON.parse(fs.readFileSync(mappingFile, 'utf8'));
439
439
  const getMappedTableName = tableName =>
440
440
  (mappingContent[tableName] ? mappingContent[tableName] : tableName);
441
- mkdirp.sync(path);
442
- mkdirp.sync(schemaPath);
441
+ fs.mkdirSync(path, { recursive: true });
442
+ fs.mkdirSync(schemaPath, { recursive: true });
443
443
 
444
444
  logger.info('Start generate GraphQL schemas to dir %s', path);
445
445
 
@@ -474,7 +474,7 @@ export class MakeGraphql extends Command {
474
474
  } catch {
475
475
  logger.info('Graphql schema file %s generated as %s', tableName, schemaFile);
476
476
  }
477
- fs.writeFileSync(schemaFile, _.template(schemaTemplate)({
477
+ fs.writeFileSync(schemaFile, template(schemaTemplate)({
478
478
  tableName,
479
479
  mappedTableName,
480
480
  columns,