mirror of
https://github.com/certd/certd.git
synced 2026-04-24 20:57:26 +08:00
chore: lib-server
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
logs/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
node_modules/
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
coverage/
|
||||
!dist/
|
||||
.idea/
|
||||
run/
|
||||
.DS_Store
|
||||
*.sw*
|
||||
*.un~
|
||||
.tsbuildinfo
|
||||
.tsbuildinfo.*
|
||||
/data/db.sqlite
|
||||
@@ -0,0 +1,11 @@
|
||||
# 🎨 editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./node_modules/mwts/",
|
||||
"ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "typings"],
|
||||
"env": {
|
||||
"jest": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
test/user.secret.ts
|
||||
|
||||
tsconfig.tsbuildinfo
|
||||
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
src
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"printWidth": 160,
|
||||
"bracketSpacing": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.25.9](https://github.com/certd/certd/compare/v1.25.8...v1.25.9) (2024-10-01)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.25.8](https://github.com/certd/certd/compare/v1.25.7...v1.25.8) (2024-09-30)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.25.7](https://github.com/certd/certd/compare/v1.25.6...v1.25.7) (2024-09-29)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.25.6](https://github.com/certd/certd/compare/v1.25.5...v1.25.6) (2024-09-29)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 部署支持1Panel ([d047234](https://github.com/certd/certd/commit/d047234d98d31504f2e5a472b66e1b75806af26e))
|
||||
|
||||
## [1.25.5](https://github.com/certd/certd/compare/v1.25.4...v1.25.5) (2024-09-26)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.25.4](https://github.com/certd/certd/compare/v1.25.3...v1.25.4) (2024-09-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.25.3](https://github.com/certd/certd/compare/v1.25.2...v1.25.3) (2024-09-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.25.2](https://github.com/certd/certd/compare/v1.25.1...v1.25.2) (2024-09-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.25.1](https://github.com/certd/certd/compare/v1.25.0...v1.25.1) (2024-09-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
# [1.25.0](https://github.com/certd/certd/compare/v1.24.4...v1.25.0) (2024-09-24)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.24.4](https://github.com/certd/certd/compare/v1.24.3...v1.24.4) (2024-09-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.22.6](https://github.com/certd/certd/compare/v1.22.5...v1.22.6) (2024-08-03)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.22.3](https://github.com/certd/certd/compare/v1.22.2...v1.22.3) (2024-07-25)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.22.2](https://github.com/certd/certd/compare/v1.22.1...v1.22.2) (2024-07-23)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.22.1](https://github.com/certd/certd/compare/v1.22.0...v1.22.1) (2024-07-20)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
# [1.22.0](https://github.com/certd/certd/compare/v1.21.2...v1.22.0) (2024-07-19)
|
||||
|
||||
### Features
|
||||
|
||||
* 升级midway,支持esm ([485e603](https://github.com/certd/certd/commit/485e603b5165c28bc08694997726eaf2a585ebe7))
|
||||
* 支持postgresql ([3b19bfb](https://github.com/certd/certd/commit/3b19bfb4291e89064b3b407a80dae092d54747d5))
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Greper
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Vue 3 + TypeScript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
|
||||
|
||||
## Type Support For `.vue` Imports in TS
|
||||
|
||||
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
|
||||
|
||||
1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default, Take Over mode will enable itself if the default TypeScript extension is disabled.
|
||||
2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
|
||||
|
||||
You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).
|
||||
@@ -0,0 +1,125 @@
|
||||
# midway-flyway-js
|
||||
|
||||
[English](./README.md) | [简体中文](./README_zhCN.md)
|
||||
|
||||
|
||||
`midway-flyway-js`是基于typeorm的flyway的js实现。
|
||||
本项目被构建为midway组件,可与midway无缝集成。
|
||||
|
||||
# flyway
|
||||
flyway是一款java版本的数据库升级迁移解决方案。
|
||||
它能在server启动时自动检查脚本目录,执行sql升级脚本,记录执行历史。
|
||||
|
||||
本项目根据类似flyway的思路实现数据库升级迁移方案
|
||||
|
||||
# 快速开始
|
||||
|
||||
## 1. 准备
|
||||
* nodejs环境
|
||||
* midway项目
|
||||
* [配置typeorm](https://www.yuque.com/midwayjs/midway_v2/orm)
|
||||
|
||||
## 2. 安装
|
||||
```
|
||||
npm install midway-flyway-js
|
||||
# or
|
||||
yarn add midway-flyway-js
|
||||
```
|
||||
## 3. 集成
|
||||
```js
|
||||
import * as orm from 'typeorm';
|
||||
import * as flyway from 'midway-flyway-js';
|
||||
@Configuration({
|
||||
imports: [
|
||||
orm, // 加载 orm 组件
|
||||
flyway, //加载flyway组件
|
||||
],
|
||||
})
|
||||
export class ContainerConfiguration {}
|
||||
```
|
||||
|
||||
|
||||
## 4. 配置参数【可选】
|
||||
`/src/config/config.default.js`文件
|
||||
```js
|
||||
export const flyway ={
|
||||
// 脚本目录
|
||||
// 默认值 "./db/migrition"
|
||||
scriptDir:"./db/migrition",
|
||||
// 基线,基线脚本及之前的脚本都跳过不执行
|
||||
// 默认值:null
|
||||
// 如果你原本就是空数据库,那么不需要配置此项
|
||||
baseline: 'v1__init.sql',
|
||||
// 执行记录表名
|
||||
// 默认值 flyway_history
|
||||
flywayTableName:'flyway_history',
|
||||
// 是否允许hash值不同
|
||||
// 默认值:false
|
||||
// 相同名称sql文件被改动后,hash会变化
|
||||
// 此时运行会报hash conflict错误
|
||||
// 配置此参数为true,将忽略hash conflict错误
|
||||
allowHashNotMatch:false
|
||||
}
|
||||
|
||||
```
|
||||
## 5. 编写升级sql
|
||||
|
||||
将你的sql升级脚本,放到 `/src/db/migrition`目录下
|
||||
|
||||
建议命名规则`v{version}__{name}.sql`,例如`v1__init.sql`
|
||||
|
||||
|
||||
## 6. 启动你的midway服务
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 7. 运行效果
|
||||
以下效果为midway自动启动后,自动执行`v1__init.sql`脚本的记录
|
||||
```
|
||||
2021-06-26 15:45:39,630 INFO 12245 [ midfly ] start-------------
|
||||
query: SELECT * FROM "sqlite_master" WHERE "type" = 'table' AND "name" = 'flyway_history'
|
||||
query: CREATE TABLE "flyway_history" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "timestamp" bigint NOT NULL, "name" varchar NOT NULL, "hash" varchar, "success" boolean)
|
||||
query: BEGIN TRANSACTION
|
||||
query: SELECT "FlywayHistory"."id" AS "FlywayHistory_id", "FlywayHistory"."name" AS "FlywayHistory_name", "FlywayHistory"."hash" AS "FlywayHistory_hash", "FlywayHistory"."timestamp" AS "FlywayHistory_timestamp", "FlywayHistory"."success" AS "FlywayHistory_success" FROM "flyway_history" "FlywayHistory" WHERE "FlywayHistory"."name" = ? AND "FlywayHistory"."success" = ? LIMIT 1 -- PARAMETERS: ["v1__init.sql",1]
|
||||
2021-06-26 15:45:39,664 INFO 12245 need exec script file:
|
||||
2021-06-26 15:45:39,666 INFO 12245 [ midfly ] exec
|
||||
query: -- 表:sys_permission
|
||||
CREATE TABLE "sys_permission" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(100) NOT NULL, "permission" varchar(100), "parent_id" integer NOT NULL DEFAULT (-1), "sort" integer NOT NULL, "create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP));
|
||||
query: INSERT INTO sys_permission (id, title, permission, parent_id, sort, create_time, update_time) VALUES (1, '系统管理', 'sys', -1, 1, 1, 1624085863636);
|
||||
query: -- 表:sys_role
|
||||
CREATE TABLE "sys_role" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(100) NOT NULL, "create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP));
|
||||
query: INSERT INTO sys_role (id, name, create_time, update_time) VALUES (1, '管理员', 1, 1623749138537);
|
||||
query: -- 表:sys_role_permission
|
||||
CREATE TABLE "sys_role_permission" ("role_id" integer NOT NULL, "permission_id" integer NOT NULL, PRIMARY KEY ("role_id", "permission_id"));
|
||||
query: INSERT INTO sys_role_permission (role_id, permission_id) VALUES (1, 1);
|
||||
query: -- 表:sys_user
|
||||
CREATE TABLE "sys_user" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "username" varchar(100) NOT NULL, "password" varchar(50) NOT NULL, "nick_name" varchar(50), "avatar" varchar(255), "phone_code" varchar(20), "mobile" varchar(20), "email" varchar(100),"remark" varchar(100), "status" integer NOT NULL DEFAULT (1), "create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP));
|
||||
query: INSERT INTO sys_user (id, username, password, nick_name, avatar, phone_code, mobile, email, status, create_time, update_time,remark) VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 'admin', NULL, NULL, NULL, NULL, 1, 2011123132, 123132,NULL);
|
||||
query: -- 表:sys_user_role
|
||||
CREATE TABLE "sys_user_role" ("role_id" integer NOT NULL, "user_id" integer NOT NULL, PRIMARY KEY ("role_id", "user_id"));
|
||||
query: INSERT INTO sys_user_role (role_id, user_id) VALUES (1, 1);
|
||||
query: -- 索引:IDX_223de54d6badbe43a5490450c3
|
||||
CREATE UNIQUE INDEX "IDX_223de54d6badbe43a5490450c3" ON "sys_role" ("name");
|
||||
query: -- 索引:IDX_9e7164b2f1ea1348bc0eb0a7da
|
||||
CREATE UNIQUE INDEX "IDX_9e7164b2f1ea1348bc0eb0a7da" ON "sys_user" ("username");
|
||||
query: DELETE FROM "flyway_history" WHERE "name" = ? -- PARAMETERS: ["v1__init.sql"]
|
||||
query: INSERT INTO "flyway_history"("id", "name", "hash", "timestamp", "success") VALUES (NULL, ?, ?, ?, ?) -- PARAMETERS: ["v1__init.sql","0c661bd7afebac224bbaa60bc5bb56e9",1624693539781,1]
|
||||
query: SELECT "FlywayHistory"."id" AS "FlywayHistory_id", "FlywayHistory"."success" AS "FlywayHistory_success" FROM "flyway_history" "FlywayHistory" WHERE "FlywayHistory"."id" = ? -- PARAMETERS: [1]
|
||||
query: COMMIT
|
||||
2021-06-26 15:45:39,800 INFO 12245 [ midfly ] end-------------
|
||||
```
|
||||
|
||||
# 注意事项
|
||||
1. 升级sql文件最后一行请不要有注释,应该以一条sql语句的分号结尾。
|
||||
|
||||
# 他们在用
|
||||
* [fs-server-js](https://github.com/fast-crud/fs-server-js)
|
||||
|
||||
# 参考项目
|
||||
* [flyway](https://github.com/flyway/flyway) : java版flyway
|
||||
* [flyway-js](https://github.com/wanglihui/flyway-js) : Sequelize版flyway
|
||||
|
||||
感谢以上项目
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testPathIgnorePatterns: ['<rootDir>/test/fixtures'],
|
||||
coveragePathIgnorePatterns: ['<rootDir>/test/'],
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"type": "sqlite",
|
||||
"database": "./data/db.sqlite",
|
||||
"synchronize": false,
|
||||
"logging": true,
|
||||
"entities": [ "src/**/entity.ts"]
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.25.9",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"scripts": {
|
||||
"before-build": "rimraf dist && rimraf tsconfig.tsbuildinfo && rimraf .rollup.cache",
|
||||
"build": "npm run before-build && tsc --skipLibCheck",
|
||||
"test": "midway-bin test --ts -V",
|
||||
"test1": "midway-bin test --ts -V -f test/blank.test.ts -t 'hash-check'",
|
||||
"cov": "midway-bin cov --ts",
|
||||
"lint": "mwts check",
|
||||
"lint:fix": "mwts fix",
|
||||
"prepublish": "npm run build",
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "greper",
|
||||
"files": [
|
||||
"dist/**/*.js",
|
||||
"dist/**/*.d.ts"
|
||||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/pipeline": "^1.25.9",
|
||||
"@midwayjs/core": "^3",
|
||||
"@midwayjs/i18n": "^3",
|
||||
"@midwayjs/info": "^3",
|
||||
"@midwayjs/koa": "^3",
|
||||
"@midwayjs/logger": "^3",
|
||||
"@midwayjs/typeorm": "^3",
|
||||
"@midwayjs/cache": "^3",
|
||||
"better-sqlite3": "^11.1.2",
|
||||
"typeorm": "^0.3.20",
|
||||
"lodash-es": "^4.17.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mwts": "^1.3.0",
|
||||
"mwtsc": "^1.4.0",
|
||||
"@rollup/plugin-commonjs": "^23.0.4",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@rollup/plugin-terser": "^0.4.3",
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"@types/chai": "^4.3.3",
|
||||
"@types/node": "^18",
|
||||
"@typescript-eslint/eslint-plugin": "^5.38.1",
|
||||
"@typescript-eslint/parser": "^5.38.1",
|
||||
"cross-env": "^6.0.0",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"prettier": "^2.8.8",
|
||||
"rimraf": "^5.0.5",
|
||||
"rollup": "^3.7.4",
|
||||
"rollup-plugin-visualizer": "^5.8.2",
|
||||
"ts-node": "^10.9.1",
|
||||
"tslib": "^2.5.2",
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "afa8155fda10f9a32427b351454b460897295a2c"
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Inject } from '@midwayjs/core';
|
||||
import * as koa from '@midwayjs/koa';
|
||||
import { Constants } from './constants.js';
|
||||
|
||||
export abstract class BaseController {
|
||||
@Inject()
|
||||
ctx: koa.Context;
|
||||
|
||||
/**
|
||||
* 成功返回
|
||||
* @param data 返回数据
|
||||
*/
|
||||
ok(data?: any) {
|
||||
const res = {
|
||||
...Constants.res.success,
|
||||
data: undefined,
|
||||
};
|
||||
if (data) {
|
||||
res.data = data;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* 失败返回
|
||||
* @param msg
|
||||
* @param code
|
||||
*/
|
||||
fail(msg: string, code: any) {
|
||||
return {
|
||||
code: code ? code : Constants.res.error.code,
|
||||
msg: msg ? msg : Constants.res.error.code,
|
||||
};
|
||||
}
|
||||
|
||||
getUserId() {
|
||||
const userId = this.ctx.user?.id;
|
||||
if (userId == null) {
|
||||
throw new Error('Token已过期');
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
import { ValidateException } from './exception/index.js';
|
||||
import * as _ from 'lodash-es';
|
||||
import { PermissionException } from './exception/index.js';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Inject } from '@midwayjs/core';
|
||||
import { TypeORMDataSourceManager } from '@midwayjs/typeorm';
|
||||
import { EntityManager } from 'typeorm/entity-manager/EntityManager.js';
|
||||
|
||||
/**
|
||||
* 服务基类
|
||||
*/
|
||||
export abstract class BaseService<T> {
|
||||
@Inject()
|
||||
dataSourceManager: TypeORMDataSourceManager;
|
||||
|
||||
abstract getRepository(): Repository<T>;
|
||||
|
||||
async transaction(callback: (entityManager: EntityManager) => Promise<any>) {
|
||||
const dataSource = this.dataSourceManager.getDataSource('default');
|
||||
await dataSource.transaction(callback as any);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得单个ID
|
||||
* @param id ID
|
||||
* @param infoIgnoreProperty 忽略返回属性
|
||||
*/
|
||||
async info(id, infoIgnoreProperty?): Promise<T | null> {
|
||||
if (!id) {
|
||||
throw new ValidateException('id不能为空');
|
||||
}
|
||||
const info = await this.getRepository().findOneBy({ id } as any);
|
||||
if (info && infoIgnoreProperty) {
|
||||
for (const property of infoIgnoreProperty) {
|
||||
delete info[property];
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 非分页查询
|
||||
* @param options
|
||||
*/
|
||||
async find(options) {
|
||||
return await this.getRepository().find(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids 删除的ID集合 如:[1,2,3] 或者 1,2,3
|
||||
*/
|
||||
async delete(ids) {
|
||||
if (ids instanceof Array) {
|
||||
await this.getRepository().delete(ids);
|
||||
} else if (typeof ids === 'string') {
|
||||
await this.getRepository().delete(ids.split(','));
|
||||
} else {
|
||||
//ids是一个condition
|
||||
await this.getRepository().delete(ids);
|
||||
}
|
||||
await this.modifyAfter(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增|修改
|
||||
* @param param 数据
|
||||
*/
|
||||
async addOrUpdate(param) {
|
||||
await this.getRepository().save(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增
|
||||
* @param param 数据
|
||||
*/
|
||||
async add(param) {
|
||||
const now = new Date();
|
||||
param.createTime = now;
|
||||
param.updateTime = now;
|
||||
await this.addOrUpdate(param);
|
||||
await this.modifyAfter(param);
|
||||
return {
|
||||
id: param.id,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改
|
||||
* @param param 数据
|
||||
*/
|
||||
async update(param) {
|
||||
if (!param.id) throw new ValidateException('no id');
|
||||
param.updateTime = new Date();
|
||||
await this.addOrUpdate(param);
|
||||
await this.modifyAfter(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增|修改|删除 之后的操作
|
||||
* @param data 对应数据
|
||||
*/
|
||||
async modifyAfter(data) {}
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param query 查询条件 bean
|
||||
* @param page
|
||||
* @param order
|
||||
* @param buildQuery
|
||||
*/
|
||||
async page(query, page = { offset: 0, limit: 20 }, order, buildQuery) {
|
||||
if (page.offset == null) {
|
||||
page.offset = 0;
|
||||
}
|
||||
if (page.limit == null) {
|
||||
page.limit = 20;
|
||||
}
|
||||
const qb = this.getRepository().createQueryBuilder('main');
|
||||
if (order && order.prop) {
|
||||
qb.addOrderBy('main.' + order.prop, order.asc ? 'ASC' : 'DESC');
|
||||
}
|
||||
qb.addOrderBy('id', 'DESC');
|
||||
qb.offset(page.offset).limit(page.limit);
|
||||
//根据bean query
|
||||
if (query) {
|
||||
let whereSql = '';
|
||||
let index = 0;
|
||||
_.forEach(query, (value, key) => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
if (index !== 0) {
|
||||
whereSql += ' and ';
|
||||
}
|
||||
whereSql += ` main.${key} = :${key} `;
|
||||
index++;
|
||||
});
|
||||
if (index > 0) {
|
||||
qb.where(whereSql, query);
|
||||
}
|
||||
}
|
||||
//自定义query
|
||||
if (buildQuery) {
|
||||
buildQuery(qb);
|
||||
}
|
||||
const list = await qb.getMany();
|
||||
const total = await qb.getCount();
|
||||
return {
|
||||
records: list,
|
||||
total,
|
||||
offset: page.offset,
|
||||
limit: page.limit,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param query 查询条件 bean
|
||||
* @param order
|
||||
* @param buildQuery
|
||||
*/
|
||||
async list(query, order, buildQuery) {
|
||||
const qb = this.getRepository().createQueryBuilder('main');
|
||||
if (order && order.prop) {
|
||||
qb.orderBy('main.' + order.prop, order.asc ? 'ASC' : 'DESC');
|
||||
} else {
|
||||
qb.orderBy('id', 'DESC');
|
||||
}
|
||||
//根据bean query
|
||||
if (query) {
|
||||
let whereSql = '';
|
||||
let index = 0;
|
||||
_.forEach(query, (value, key) => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
if (index !== 0) {
|
||||
whereSql += ' and ';
|
||||
}
|
||||
whereSql += ` main.${key} = :${key} `;
|
||||
index++;
|
||||
});
|
||||
if (index > 0) {
|
||||
qb.where(whereSql, query);
|
||||
}
|
||||
}
|
||||
//自定义query
|
||||
if (buildQuery) {
|
||||
buildQuery(qb);
|
||||
}
|
||||
return await qb.getMany();
|
||||
}
|
||||
|
||||
async checkUserId(id: any = 0, userId, userKey = 'userId') {
|
||||
// @ts-ignore
|
||||
const res = await this.getRepository().findOne({
|
||||
// @ts-ignore
|
||||
select: { [userKey]: true },
|
||||
// @ts-ignore
|
||||
where: {
|
||||
// @ts-ignore
|
||||
id,
|
||||
},
|
||||
});
|
||||
// @ts-ignore
|
||||
if (!res || res[userKey] === userId) {
|
||||
return;
|
||||
}
|
||||
throw new PermissionException('权限不足');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
export const Constants = {
|
||||
dataDir: './data',
|
||||
role: {
|
||||
defaultUser: 3,
|
||||
},
|
||||
per: {
|
||||
//无需登录
|
||||
guest: '_guest_',
|
||||
//无需登录
|
||||
anonymous: '_guest_',
|
||||
//仅需要登录
|
||||
authOnly: '_authOnly_',
|
||||
//仅需要登录
|
||||
loginOnly: '_authOnly_',
|
||||
},
|
||||
res: {
|
||||
serverError(message: string) {
|
||||
return {
|
||||
code: 1,
|
||||
message,
|
||||
};
|
||||
},
|
||||
error: {
|
||||
code: 1,
|
||||
message: 'Internal server error',
|
||||
},
|
||||
success: {
|
||||
code: 0,
|
||||
message: 'success',
|
||||
},
|
||||
validation: {
|
||||
code: 10,
|
||||
message: '参数错误',
|
||||
},
|
||||
needvip: {
|
||||
code: 88,
|
||||
message: '需要VIP',
|
||||
},
|
||||
auth: {
|
||||
code: 401,
|
||||
message: '您还未登录或token已过期',
|
||||
},
|
||||
permission: {
|
||||
code: 402,
|
||||
message: '您没有权限',
|
||||
},
|
||||
preview: {
|
||||
code: 10001,
|
||||
message: '对不起,预览环境不允许修改此数据',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
import { ALL, Body, Post, Query } from '@midwayjs/core';
|
||||
import { BaseController } from './base-controller.js';
|
||||
|
||||
export abstract class CrudController<T> extends BaseController {
|
||||
abstract getService<T>();
|
||||
|
||||
@Post('/page')
|
||||
async page(
|
||||
@Body(ALL)
|
||||
body
|
||||
) {
|
||||
const pageRet = await this.getService().page(body?.query, body?.page, body?.sort, null);
|
||||
return this.ok(pageRet);
|
||||
}
|
||||
|
||||
@Post('/list')
|
||||
async list(
|
||||
@Body(ALL)
|
||||
body
|
||||
) {
|
||||
const listRet = await this.getService().list(body, null, null);
|
||||
return this.ok(listRet);
|
||||
}
|
||||
|
||||
@Post('/add')
|
||||
async add(
|
||||
@Body(ALL)
|
||||
bean
|
||||
) {
|
||||
delete bean.id;
|
||||
const id = await this.getService().add(bean);
|
||||
return this.ok(id);
|
||||
}
|
||||
|
||||
@Post('/info')
|
||||
async info(
|
||||
@Query('id')
|
||||
id
|
||||
) {
|
||||
const bean = await this.getService().info(id);
|
||||
return this.ok(bean);
|
||||
}
|
||||
|
||||
@Post('/update')
|
||||
async update(
|
||||
@Body(ALL)
|
||||
bean
|
||||
) {
|
||||
await this.getService().update(bean);
|
||||
return this.ok(null);
|
||||
}
|
||||
|
||||
@Post('/delete')
|
||||
async delete(
|
||||
@Query('id')
|
||||
id
|
||||
) {
|
||||
await this.getService().delete([id]);
|
||||
return this.ok(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export class EnumItem {
|
||||
value: string;
|
||||
label: string;
|
||||
color: string;
|
||||
|
||||
constructor(value, label, color) {
|
||||
this.value = value;
|
||||
this.label = label;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Constants } from '../constants.js';
|
||||
import { BaseException } from './base-exception.js';
|
||||
/**
|
||||
* 授权异常
|
||||
*/
|
||||
export class AuthException extends BaseException {
|
||||
constructor(message) {
|
||||
super(
|
||||
'AuthException',
|
||||
Constants.res.auth.code,
|
||||
message ? message : Constants.res.auth.message
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 异常基类
|
||||
*/
|
||||
export class BaseException extends Error {
|
||||
status: number;
|
||||
constructor(name, code, message) {
|
||||
super(message);
|
||||
this.name = name;
|
||||
this.status = code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Constants } from '../constants.js';
|
||||
import { BaseException } from './base-exception.js';
|
||||
/**
|
||||
* 通用异常
|
||||
*/
|
||||
export class CommonException extends BaseException {
|
||||
constructor(message) {
|
||||
super(
|
||||
'CommonException',
|
||||
Constants.res.error.code,
|
||||
message ? message : Constants.res.error.message
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export * from './auth-exception.js'
|
||||
export * from './base-exception.js'
|
||||
export * from './permission-exception.js'
|
||||
export * from './preview-exception.js'
|
||||
export * from './validation-exception.js'
|
||||
export * from './vip-exception.js'
|
||||
export * from './common-exception.js'
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Constants } from '../constants.js';
|
||||
import { BaseException } from './base-exception.js';
|
||||
/**
|
||||
* 授权异常
|
||||
*/
|
||||
export class PermissionException extends BaseException {
|
||||
constructor(message?: string) {
|
||||
super(
|
||||
'PermissionException',
|
||||
Constants.res.permission.code,
|
||||
message ? message : Constants.res.permission.message
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Constants } from '../constants.js';
|
||||
import { BaseException } from './base-exception.js';
|
||||
/**
|
||||
* 预览模式
|
||||
*/
|
||||
export class PreviewException extends BaseException {
|
||||
constructor(message) {
|
||||
super(
|
||||
'PreviewException',
|
||||
Constants.res.preview.code,
|
||||
message ? message : Constants.res.preview.message
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Constants } from '../constants.js';
|
||||
import { BaseException } from './base-exception.js';
|
||||
/**
|
||||
* 校验异常
|
||||
*/
|
||||
export class ValidateException extends BaseException {
|
||||
constructor(message) {
|
||||
super(
|
||||
'ValidateException',
|
||||
Constants.res.validation.code,
|
||||
message ? message : Constants.res.validation.message
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Constants } from '../constants.js';
|
||||
import { BaseException } from './base-exception.js';
|
||||
/**
|
||||
* 需要vip异常
|
||||
*/
|
||||
export class NeedVIPException extends BaseException {
|
||||
constructor(message) {
|
||||
super('NeedVIPException', Constants.res.needvip.code, message ? message : Constants.res.needvip.message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export * from './base-controller.js';
|
||||
export * from './constants.js';
|
||||
export * from './crud-controller.js';
|
||||
export * from './enum-item.js';
|
||||
export * from './exception/index.js';
|
||||
export * from './result.js';
|
||||
export * from './base-service.js';
|
||||
@@ -0,0 +1,18 @@
|
||||
export class Result<T> {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: T;
|
||||
constructor(code, msg, data?) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
static error(code = 1, msg) {
|
||||
return new Result(code, msg, null);
|
||||
}
|
||||
|
||||
static success(msg, data?) {
|
||||
return new Result(0, msg, data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { IMidwayContainer } from '@midwayjs/core';
|
||||
import { Configuration } from '@midwayjs/core';
|
||||
import { logger } from '@certd/pipeline';
|
||||
@Configuration({
|
||||
namespace: 'lib-server',
|
||||
})
|
||||
export class LibServerConfiguration {
|
||||
async onReady(container: IMidwayContainer) {
|
||||
logger.info('lib start');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { SysSettingsEntity } from './system/index.js';
|
||||
|
||||
export * from './basic/index.js';
|
||||
export * from './system/index.js';
|
||||
export { LibServerConfiguration as Configuration } from './configuration.js';
|
||||
|
||||
export const libServerEntities = [SysSettingsEntity];
|
||||
@@ -0,0 +1 @@
|
||||
export * from './settings/index.js';
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
/**
|
||||
*/
|
||||
@Entity('sys_settings')
|
||||
export class SysSettingsEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
@Column({ comment: 'key', length: 100 })
|
||||
key: string;
|
||||
@Column({ comment: '名称', length: 100 })
|
||||
title: string;
|
||||
|
||||
@Column({ name: 'setting', comment: '设置', length: 1024, nullable: true })
|
||||
setting: string;
|
||||
|
||||
// public 公开读,私有写, private 私有读,私有写
|
||||
@Column({ name: 'access', comment: '访问权限' })
|
||||
access: string;
|
||||
|
||||
@Column({
|
||||
name: 'create_time',
|
||||
comment: '创建时间',
|
||||
default: () => 'CURRENT_TIMESTAMP',
|
||||
})
|
||||
createTime: Date;
|
||||
@Column({
|
||||
name: 'update_time',
|
||||
comment: '修改时间',
|
||||
default: () => 'CURRENT_TIMESTAMP',
|
||||
})
|
||||
updateTime: Date;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './service/sys-settings-service.js';
|
||||
export * from './service/models.js';
|
||||
export * from './entity/sys-settings.js';
|
||||
@@ -0,0 +1,55 @@
|
||||
export class BaseSettings {
|
||||
static __key__: string;
|
||||
static __title__: string;
|
||||
static __access__ = 'private';
|
||||
|
||||
static getCacheKey() {
|
||||
return 'settings.' + this.__key__;
|
||||
}
|
||||
}
|
||||
|
||||
export class SysPublicSettings extends BaseSettings {
|
||||
static __key__ = 'sys.public';
|
||||
static __title__ = '系统公共设置';
|
||||
static __access__ = 'public';
|
||||
registerEnabled = false;
|
||||
managerOtherUserPipeline = false;
|
||||
// triggerOnStartup = false;
|
||||
}
|
||||
|
||||
export class SysPrivateSettings extends BaseSettings {
|
||||
static __title__ = '系统私有设置';
|
||||
static __access__ = 'private';
|
||||
static __key__ = 'sys.private';
|
||||
jwtKey?: string;
|
||||
encryptSecret?: string;
|
||||
}
|
||||
|
||||
export class SysInstallInfo extends BaseSettings {
|
||||
static __title__ = '系统安装信息';
|
||||
static __key__ = 'sys.install';
|
||||
static __access__ = 'private';
|
||||
installTime: number;
|
||||
siteId?: string;
|
||||
bindUserId?: number;
|
||||
bindUrl?: string;
|
||||
accountServerBaseUrl?: string;
|
||||
appKey?: string;
|
||||
}
|
||||
|
||||
export class SysLicenseInfo extends BaseSettings {
|
||||
static __title__ = '授权许可信息';
|
||||
static __key__ = 'sys.license';
|
||||
static __access__ = 'private';
|
||||
license?: string;
|
||||
}
|
||||
|
||||
export class SysSiteInfo extends BaseSettings {
|
||||
static __title__ = '站点信息';
|
||||
static __key__ = 'sys.site';
|
||||
static __access__ = 'public';
|
||||
TITLE?: string;
|
||||
SLOGAN?: string;
|
||||
LOGO?: string;
|
||||
ICP_NO?: string;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { SysSettingsEntity } from '../entity/sys-settings.js';
|
||||
import { CacheManager } from '@midwayjs/cache';
|
||||
import { BaseSettings, SysPrivateSettings, SysPublicSettings } from './models.js';
|
||||
import * as _ from 'lodash-es';
|
||||
import { BaseService } from '../../../basic/index.js';
|
||||
|
||||
/**
|
||||
* 设置
|
||||
*/
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Singleton)
|
||||
export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
@InjectEntityModel(SysSettingsEntity)
|
||||
repository: Repository<SysSettingsEntity>;
|
||||
|
||||
@Inject()
|
||||
cache: CacheManager; // 依赖注入CacheManager
|
||||
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
async getById(id: any): Promise<SysSettingsEntity | null> {
|
||||
const entity = await this.info(id);
|
||||
if (!entity) {
|
||||
return null;
|
||||
}
|
||||
const setting = JSON.parse(entity.setting);
|
||||
return {
|
||||
id: entity.id,
|
||||
...setting,
|
||||
};
|
||||
}
|
||||
|
||||
async getByKey(key: string): Promise<SysSettingsEntity | null> {
|
||||
if (!key) {
|
||||
return null;
|
||||
}
|
||||
return await this.repository.findOne({
|
||||
where: {
|
||||
key,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getSettingByKey(key: string): Promise<any | null> {
|
||||
const entity = await this.getByKey(key);
|
||||
if (!entity) {
|
||||
return null;
|
||||
}
|
||||
return JSON.parse(entity.setting);
|
||||
}
|
||||
|
||||
async save(bean: SysSettingsEntity) {
|
||||
const entity = await this.repository.findOne({
|
||||
where: {
|
||||
key: bean.key,
|
||||
},
|
||||
});
|
||||
if (entity) {
|
||||
entity.setting = bean.setting;
|
||||
await this.repository.save(entity);
|
||||
} else {
|
||||
bean.title = bean.key;
|
||||
await this.repository.save(bean);
|
||||
}
|
||||
}
|
||||
|
||||
async getSetting<T>(type: any): Promise<T> {
|
||||
const key = type.__key__;
|
||||
const cacheKey = type.getCacheKey();
|
||||
const settings: T = await this.cache.get(cacheKey);
|
||||
if (settings) {
|
||||
return settings;
|
||||
}
|
||||
let newSetting: T = new type();
|
||||
const savedSettings = await this.getSettingByKey(key);
|
||||
newSetting = _.merge(newSetting, savedSettings);
|
||||
await this.cache.set(cacheKey, newSetting);
|
||||
return newSetting;
|
||||
}
|
||||
|
||||
async saveSetting<T extends BaseSettings>(bean: T) {
|
||||
const type: any = bean.constructor;
|
||||
const key = type.__key__;
|
||||
const cacheKey = type.getCacheKey();
|
||||
|
||||
const entity = await this.getByKey(key);
|
||||
if (entity) {
|
||||
entity.setting = JSON.stringify(bean);
|
||||
await this.repository.save(entity);
|
||||
} else {
|
||||
const newEntity = new SysSettingsEntity();
|
||||
newEntity.key = key;
|
||||
newEntity.title = type.__title__;
|
||||
newEntity.setting = JSON.stringify(bean);
|
||||
newEntity.access = type.__access__;
|
||||
await this.repository.save(newEntity);
|
||||
}
|
||||
|
||||
await this.cache.set(cacheKey, bean);
|
||||
}
|
||||
|
||||
async getPublicSettings(): Promise<SysPublicSettings> {
|
||||
return await this.getSetting(SysPublicSettings);
|
||||
}
|
||||
|
||||
async savePublicSettings(bean: SysPublicSettings) {
|
||||
await this.saveSetting(bean);
|
||||
}
|
||||
|
||||
async savePrivateSettings(bean: SysPrivateSettings) {
|
||||
this.saveSetting(bean);
|
||||
}
|
||||
|
||||
async updateByKey(key: string, setting: any) {
|
||||
const entity = await this.getByKey(key);
|
||||
if (entity) {
|
||||
entity.setting = JSON.stringify(setting);
|
||||
await this.repository.save(entity);
|
||||
} else {
|
||||
throw new Error('该设置不存在');
|
||||
}
|
||||
await this.cache.del(`settings.${key}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
end -----
|
||||
```
|
||||
# test
|
||||
The last line of the SQL file should be uncommented and should end with a semicolon of the SQL statement.
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"isolatedModules": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"inlineSourceMap":true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"stripInternal": true,
|
||||
"skipLibCheck": true,
|
||||
"pretty": true,
|
||||
"declaration": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"typeRoots": [ "./typings", "./node_modules/@types"],
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"composite": true,
|
||||
"useDefineForClassFields": true,
|
||||
"strict": false,
|
||||
"resolveJsonModule": true,
|
||||
"lib": ["ESNext", "DOM"],
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.json"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.ts",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"test"
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user