paas-build-package 0.0.1
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/.editorconfig +13 -0
- package/.vscode/extensions.json +13 -0
- package/.vscode/settings.json +19 -0
- package/.vscode/tasks.json +158 -0
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/lerna.json +8 -0
- package/package.json +37 -0
- package/packages/build/CHANGELOG.md +14 -0
- package/packages/build/LICENSE +21 -0
- package/packages/build/README.md +1 -0
- package/packages/build/build.config.ts +22 -0
- package/packages/build/eslint.config.js +8 -0
- package/packages/build/package.json +103 -0
- package/packages/build/prettier.config.js +3 -0
- package/packages/build/src/commitlint/commitlint-config/commitlint-config.ts +37 -0
- package/packages/build/src/commitlint/index.ts +1 -0
- package/packages/build/src/constants/index.ts +70 -0
- package/packages/build/src/eslint/eslint-config/eslint-config.ts +161 -0
- package/packages/build/src/eslint/index.ts +1 -0
- package/packages/build/src/index.ts +8 -0
- package/packages/build/src/prettier/index.ts +1 -0
- package/packages/build/src/prettier/prettier-config/prettier-config.ts +48 -0
- package/packages/build/src/stylelint/index.ts +1 -0
- package/packages/build/src/stylelint/stylelint-config/stylelint-config.ts +39 -0
- package/packages/build/src/types/index.d.ts +1 -0
- package/packages/build/src/unocss/index.ts +1 -0
- package/packages/build/src/unocss/unocss.config.ts +45 -0
- package/packages/build/src/util/env-state/env-state.ts +9 -0
- package/packages/build/src/util/index.ts +52 -0
- package/packages/build/src/util/reg-exp/reg-exp.ts +1 -0
- package/packages/build/src/util/watcher/watcher.ts +114 -0
- package/packages/build/src/vite/index.ts +13 -0
- package/packages/build/src/vite/vite-config/vite-base-config.ts +49 -0
- package/packages/build/src/vite/vite-config/vite-config.ts +74 -0
- package/packages/build/src/vite/vite-config/vite-dev-config.ts +26 -0
- package/packages/build/src/vite/vite-config/vite-pkg-dev-config.ts +123 -0
- package/packages/build/src/vite/vite-config/vite-plugin-config.ts +149 -0
- package/packages/build/src/vite/vite-config/vite-project-config.ts +82 -0
- package/packages/build/src/vite/vite-plugins/imnport-external-plugin.ts +21 -0
- package/packages/build/src/vite/vite-plugins/inject-importmap-plugin.ts +133 -0
- package/packages/build/tsconfig.json +32 -0
- package/packages/cli/CHANGELOG.md +20 -0
- package/packages/cli/LICENSE +21 -0
- package/packages/cli/README.md +1 -0
- package/packages/cli/build.config.ts +22 -0
- package/packages/cli/hbs-temp/api-config.ts.hbs +21 -0
- package/packages/cli/hbs-temp/apis/{{api}}.service.d.ts.hbs +39 -0
- package/packages/cli/hbs-temp/entities.d.ts.hbs +19 -0
- package/packages/cli/hbs-temp/index.d.ts.hbs +9 -0
- package/packages/cli/package.json +72 -0
- package/packages/cli/src/actions/gen-api/api-manage.ts +96 -0
- package/packages/cli/src/actions/gen-api/gen-api.ts +211 -0
- package/packages/cli/src/actions/gen-api/model-manage.ts +269 -0
- package/packages/cli/src/actions/gen-api/special-entities.config.ts +26 -0
- package/packages/cli/src/actions/gen-cdn-lib/gen-cdn-lib.ts +149 -0
- package/packages/cli/src/actions/index.ts +3 -0
- package/packages/cli/src/actions/init-git/init-git.ts +28 -0
- package/packages/cli/src/bin.ts +5 -0
- package/packages/cli/src/commands/gen-api/gen-api.ts +65 -0
- package/packages/cli/src/commands/gen-cdn-lib/gen-cdn-lib.ts +25 -0
- package/packages/cli/src/commands/index.ts +22 -0
- package/packages/cli/src/commands/init-git/init-git.ts +16 -0
- package/packages/cli/src/core/handlebars/constant/index.ts +4 -0
- package/packages/cli/src/core/handlebars/handlebars-engine.ts +143 -0
- package/packages/cli/src/core/handlebars/helpers/and/and.ts +24 -0
- package/packages/cli/src/core/handlebars/helpers/camel-case/camel-case.ts +23 -0
- package/packages/cli/src/core/handlebars/helpers/concat/concat.ts +20 -0
- package/packages/cli/src/core/handlebars/helpers/eq/eq.ts +27 -0
- package/packages/cli/src/core/handlebars/helpers/format-import/format-import.ts +46 -0
- package/packages/cli/src/core/handlebars/helpers/format-import-item/format-import-item.ts +67 -0
- package/packages/cli/src/core/handlebars/helpers/format-js-type/format-js-type.ts +50 -0
- package/packages/cli/src/core/handlebars/helpers/gt/gt.ts +27 -0
- package/packages/cli/src/core/handlebars/helpers/gte/gte.ts +27 -0
- package/packages/cli/src/core/handlebars/helpers/helper-base.ts +27 -0
- package/packages/cli/src/core/handlebars/helpers/includes/includes.ts +25 -0
- package/packages/cli/src/core/handlebars/helpers/index.ts +52 -0
- package/packages/cli/src/core/handlebars/helpers/json/json.ts +23 -0
- package/packages/cli/src/core/handlebars/helpers/lower-case/lower-case.ts +22 -0
- package/packages/cli/src/core/handlebars/helpers/lt/lt.ts +27 -0
- package/packages/cli/src/core/handlebars/helpers/lte/lte.ts +27 -0
- package/packages/cli/src/core/handlebars/helpers/neq/neq.ts +27 -0
- package/packages/cli/src/core/handlebars/helpers/not/not.ts +25 -0
- package/packages/cli/src/core/handlebars/helpers/not-includes/not-includes.ts +25 -0
- package/packages/cli/src/core/handlebars/helpers/or/or.ts +26 -0
- package/packages/cli/src/core/handlebars/helpers/pascal-case/pascal-case.ts +23 -0
- package/packages/cli/src/core/handlebars/helpers/snake-case/snake-case.ts +23 -0
- package/packages/cli/src/core/handlebars/helpers/spinal-case/spinal-case.ts +23 -0
- package/packages/cli/src/core/handlebars/helpers/upper-case/upper-case.ts +22 -0
- package/packages/cli/src/core/handlebars/index.ts +2 -0
- package/packages/cli/src/core/handlebars/utils/helper/helper.ts +67 -0
- package/packages/cli/src/core/handlebars/utils/index.ts +23 -0
- package/packages/cli/src/core/index.ts +2 -0
- package/packages/cli/src/core/interface/index.ts +4 -0
- package/packages/cli/src/index.ts +36 -0
- package/packages/cli/src/interface/i-command/i-command.ts +23 -0
- package/packages/cli/src/interface/i-gen-cdn-lib-options/i-gen-cdn-lib-options.ts +58 -0
- package/packages/cli/src/interface/index.ts +2 -0
- package/packages/cli/src/types/index.d.ts +1 -0
- package/packages/cli/src/utils/index.ts +4 -0
- package/packages/cli/src/utils/local-binaries/local-binaries.ts +16 -0
- package/packages/cli/tsconfig.json +32 -0
- package/pnpm-workspace.yaml +10 -0
- package/tsconfig.app.json +18 -0
- package/tsconfig.json +11 -0
- package/tsconfig.node.json +26 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{{#each entities as |entity|}}
|
|
2
|
+
import type { {{pascalCase (camelCase entity.entityName) }}Service } from './apis/{{entity.entityName}}.service';
|
|
3
|
+
{{/each}}
|
|
4
|
+
|
|
5
|
+
export interface ApiManage {
|
|
6
|
+
{{#each entities as |entity|}}
|
|
7
|
+
readonly {{camelCase entity.entityName}}: {{pascalCase (camelCase entity.entityName)}}Service;
|
|
8
|
+
{{/each}}
|
|
9
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gct-paas/cli",
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "paas 平台核心包",
|
|
6
|
+
"bin": {
|
|
7
|
+
"gct-paas": "es/bin.mjs"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.cjs",
|
|
10
|
+
"module": "es/index.mjs",
|
|
11
|
+
"types": "es/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./es/index.d.ts",
|
|
15
|
+
"import": "./es/index.mjs",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"es",
|
|
22
|
+
"hbs-temp",
|
|
23
|
+
"CHANGELOG.md",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"paas",
|
|
28
|
+
"gct"
|
|
29
|
+
],
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://git.gct-china.com/paas/frontend/paas-package.git"
|
|
33
|
+
},
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"author": "gct",
|
|
36
|
+
"scripts": {
|
|
37
|
+
"run": "tsx src/bin.ts gen-cdn-lib --tag=dev --dir=/Users/zhr/workspace/gct/gct-paas-cdn/extras",
|
|
38
|
+
"build": "unbuild",
|
|
39
|
+
"publish:next": "npm run build && npm publish --access public --tag=next --registry=https://registry.npmjs.org/",
|
|
40
|
+
"publish:dev": "npm run build && npm publish --access public --tag=dev --registry=https://registry.npmjs.org/",
|
|
41
|
+
"publish:alpha": "npm run build && npm publish --access public --tag=alpha --registry=https://registry.npmjs.org/",
|
|
42
|
+
"publish:beta": "npm run build && npm publish --access public --tag=beta --registry=https://registry.npmjs.org/",
|
|
43
|
+
"publish:npm": "npm run build && npm publish --access public --registry=https://registry.npmjs.org/"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@inquirer/prompts": "^8.2.0",
|
|
47
|
+
"commander": "^14.0.2",
|
|
48
|
+
"consola": "^3.4.2",
|
|
49
|
+
"core-js": "^3.48.0",
|
|
50
|
+
"fast-glob": "^3.3.3",
|
|
51
|
+
"fs-extra": "^11.3.3",
|
|
52
|
+
"got": "^14.6.6",
|
|
53
|
+
"handlebars": "^4.7.8",
|
|
54
|
+
"handlebars-helpers": "^0.10.0",
|
|
55
|
+
"listr2": "^10.2.1",
|
|
56
|
+
"lodash-es": "^4.17.23",
|
|
57
|
+
"ora": "^9.1.0",
|
|
58
|
+
"pacote": "^21.5.0",
|
|
59
|
+
"picocolors": "^1.1.1",
|
|
60
|
+
"rimraf": "^6.1.2",
|
|
61
|
+
"simple-git": "^3.33.0"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/fs-extra": "^11.0.4",
|
|
65
|
+
"@types/lodash-es": "^4.17.12",
|
|
66
|
+
"@types/node": "^25.0.10",
|
|
67
|
+
"@types/pacote": "^11.1.8",
|
|
68
|
+
"tsx": "^4.21.0",
|
|
69
|
+
"typescript": "^5.9.3",
|
|
70
|
+
"unbuild": "^3.6.1"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { IObject } from '../../core';
|
|
2
|
+
import { SPECIAL_ENTITIES } from './special-entities.config';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* api 管理
|
|
6
|
+
*
|
|
7
|
+
* @export
|
|
8
|
+
* @class EntityApiManage
|
|
9
|
+
*/
|
|
10
|
+
export class EntityApiManage {
|
|
11
|
+
readonly cache = new Map<string, IObject>();
|
|
12
|
+
|
|
13
|
+
constructor(public readonly name: string) {}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 新增方法
|
|
17
|
+
*
|
|
18
|
+
* @param {string} method 方法名称
|
|
19
|
+
* @param {string} mode 请求方式
|
|
20
|
+
* @param {IObject} cfg 从 swagger 获取的配置
|
|
21
|
+
*/
|
|
22
|
+
add(method: string, mode: string, cfg: IObject): void {
|
|
23
|
+
const tag = `${method}:${mode}`;
|
|
24
|
+
this.cache.set(tag, cfg);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* api 清单管理
|
|
30
|
+
*
|
|
31
|
+
* @export
|
|
32
|
+
* @class ApiManage
|
|
33
|
+
*/
|
|
34
|
+
export class ApiManage {
|
|
35
|
+
readonly cache = new Map<string, EntityApiManage>();
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
this.specialTreatment();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 根据配置文件中的特殊实体映射来处理
|
|
43
|
+
*
|
|
44
|
+
* @protected
|
|
45
|
+
*/
|
|
46
|
+
protected specialTreatment() {
|
|
47
|
+
SPECIAL_ENTITIES.forEach(({ canonical, aliases }) => {
|
|
48
|
+
const manage = new EntityApiManage(canonical);
|
|
49
|
+
aliases.forEach(alias => {
|
|
50
|
+
this.cache.set(alias, manage);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 新增 api
|
|
57
|
+
*
|
|
58
|
+
* @param {string} pathStr 请求路径
|
|
59
|
+
* @param {IObject} cfg swagger 配置
|
|
60
|
+
*/
|
|
61
|
+
add(pathStr: string, cfg: IObject) {
|
|
62
|
+
// 根据路径截取归属标识,例:/gct-apaas/api/app-branch/info 提取出 app-branch
|
|
63
|
+
const splits = pathStr.split('/');
|
|
64
|
+
const entityName = splits[3];
|
|
65
|
+
const method = splits.slice(4).join('_');
|
|
66
|
+
const requestPath = splits.slice(4).join('/');
|
|
67
|
+
if (!this.cache.has(entityName)) {
|
|
68
|
+
this.cache.set(entityName, new EntityApiManage(entityName));
|
|
69
|
+
}
|
|
70
|
+
const entity = this.cache.get(entityName)!;
|
|
71
|
+
const modes = Object.keys(cfg);
|
|
72
|
+
modes.forEach(mode => {
|
|
73
|
+
const _cfg = cfg[mode];
|
|
74
|
+
_cfg.requestPath = requestPath;
|
|
75
|
+
entity.add(method, mode, _cfg);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 结束新增 api 后调用
|
|
81
|
+
*
|
|
82
|
+
*/
|
|
83
|
+
done(): void {
|
|
84
|
+
// 清理特殊实体中的别名,保留标准名称
|
|
85
|
+
SPECIAL_ENTITIES.forEach(({ canonical, aliases }) => {
|
|
86
|
+
if (this.cache.has(canonical)) {
|
|
87
|
+
// 删除所有别名,只保留标准名称
|
|
88
|
+
aliases.forEach(alias => {
|
|
89
|
+
if (alias !== canonical) {
|
|
90
|
+
this.cache.delete(alias);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fse from 'fs-extra';
|
|
3
|
+
import * as rm from 'rimraf';
|
|
4
|
+
import glob from 'fast-glob';
|
|
5
|
+
import log from 'consola';
|
|
6
|
+
import got from 'got';
|
|
7
|
+
import { HandlebarsEngine, IObject, MACRO_FOLDER } from '../../core';
|
|
8
|
+
import { ModelManage } from './model-manage';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 基于 handlebars 模板编写生成 api
|
|
12
|
+
*
|
|
13
|
+
* @export
|
|
14
|
+
* @class GenApiAction
|
|
15
|
+
*/
|
|
16
|
+
export class GenApiAction {
|
|
17
|
+
// private baseUrl = 'http://paas.paasdev.gct-paas.com';
|
|
18
|
+
|
|
19
|
+
private engine = new HandlebarsEngine();
|
|
20
|
+
|
|
21
|
+
private modelManage = new ModelManage();
|
|
22
|
+
|
|
23
|
+
private configs: Record<string, string> = {
|
|
24
|
+
platform:
|
|
25
|
+
'/gct-platform/v2/api-docs?group=%E7%AE%A1%E7%90%86%E5%B9%B3%E5%8F%B0API',
|
|
26
|
+
apaas: '/gct-apaas/v2/api-docs?group=apaas%E5%B9%B3%E5%8F%B0API',
|
|
27
|
+
ipaas: '/gct-ipaas/v2/api-docs?group=ipaas%E5%B9%B3%E5%8F%B0API',
|
|
28
|
+
rag: '/gct-rag/v2/api-docs?group=%E7%AE%A1%E7%90%86%E5%B9%B3%E5%8F%B0API',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 生成 api
|
|
33
|
+
*
|
|
34
|
+
* @param {string} baseUrl swagger 服务地址
|
|
35
|
+
* @param {string} tag 要发布的 api 标识
|
|
36
|
+
* @param {string} template 模板目录
|
|
37
|
+
* @param {string} output 输出目录
|
|
38
|
+
* @param {boolean} clean 是否清理输出目录后再生成
|
|
39
|
+
*/
|
|
40
|
+
async run(
|
|
41
|
+
baseUrl: string,
|
|
42
|
+
tag: string,
|
|
43
|
+
template: string,
|
|
44
|
+
output: string,
|
|
45
|
+
clean: boolean,
|
|
46
|
+
) {
|
|
47
|
+
try {
|
|
48
|
+
const cwd = process.cwd();
|
|
49
|
+
// 模板绝对路径
|
|
50
|
+
const tempPath = path.resolve(cwd, template);
|
|
51
|
+
// 输出绝对路径
|
|
52
|
+
const outPath = path.resolve(cwd, output);
|
|
53
|
+
// 输出目录目录存在时,根据配置清理
|
|
54
|
+
if (clean === true && fse.existsSync(outPath)) {
|
|
55
|
+
rm.sync(outPath);
|
|
56
|
+
}
|
|
57
|
+
await this.registerMacros(tempPath, this.engine);
|
|
58
|
+
await this.registerTempFiles(tempPath, this.engine);
|
|
59
|
+
await this.write(
|
|
60
|
+
tag,
|
|
61
|
+
path.join(baseUrl, this.configs[tag]),
|
|
62
|
+
outPath,
|
|
63
|
+
this.engine,
|
|
64
|
+
);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 基于模型编译输出文件
|
|
72
|
+
*
|
|
73
|
+
* @protected
|
|
74
|
+
* @param {string} url
|
|
75
|
+
* @param {string} outPath
|
|
76
|
+
* @param {HandlebarsEngine} engine
|
|
77
|
+
* @returns {*} {Promise<void>}
|
|
78
|
+
*/
|
|
79
|
+
protected async write(
|
|
80
|
+
tag: string,
|
|
81
|
+
url: string,
|
|
82
|
+
outPath: string,
|
|
83
|
+
engine: HandlebarsEngine,
|
|
84
|
+
): Promise<void> {
|
|
85
|
+
// 从 swagger 获取配置
|
|
86
|
+
const cfg = await got(url).json<IObject>();
|
|
87
|
+
|
|
88
|
+
const model = this.transformModel(cfg);
|
|
89
|
+
|
|
90
|
+
this.modelManage.init(tag, model);
|
|
91
|
+
|
|
92
|
+
const all: Promise<void>[] = [];
|
|
93
|
+
engine.temps.forEach((template, key) => {
|
|
94
|
+
if (key === '') {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const outFilePath = path.join(outPath, key);
|
|
98
|
+
// 解析出模板路径中的所有标识,没有标识表示全局
|
|
99
|
+
const tags = engine.parseContextTags(key);
|
|
100
|
+
if (tags.length === 0) {
|
|
101
|
+
log.info(`生成文件:${outFilePath}`);
|
|
102
|
+
all.push(
|
|
103
|
+
fse.outputFile(
|
|
104
|
+
outFilePath,
|
|
105
|
+
engine.render(template, {
|
|
106
|
+
entities: Array.from(this.modelManage.entities.values()),
|
|
107
|
+
definitions: model.definitions,
|
|
108
|
+
}),
|
|
109
|
+
'utf-8',
|
|
110
|
+
),
|
|
111
|
+
);
|
|
112
|
+
} else {
|
|
113
|
+
if (tags.includes('api')) {
|
|
114
|
+
this.modelManage.entities.forEach(model => {
|
|
115
|
+
const filePath = engine.render(outFilePath, model);
|
|
116
|
+
log.info(`生成文件:${filePath}`);
|
|
117
|
+
all.push(
|
|
118
|
+
fse.outputFile(filePath, engine.render(template, model), 'utf-8'),
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
await Promise.all(all);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 注册所有的宏
|
|
129
|
+
*
|
|
130
|
+
* @protected
|
|
131
|
+
* @param {string} tempPath
|
|
132
|
+
* @param {HandlebarsEngine} engine
|
|
133
|
+
* @returns {*} {Promise<void>}
|
|
134
|
+
*/
|
|
135
|
+
protected async registerMacros(
|
|
136
|
+
tempPath: string,
|
|
137
|
+
engine: HandlebarsEngine,
|
|
138
|
+
): Promise<void> {
|
|
139
|
+
const macroFiles = glob.sync(path.join(MACRO_FOLDER, '**/*.hbs'), {
|
|
140
|
+
cwd: tempPath,
|
|
141
|
+
dot: true,
|
|
142
|
+
absolute: true,
|
|
143
|
+
});
|
|
144
|
+
if (macroFiles.length > 0) {
|
|
145
|
+
await Promise.all(
|
|
146
|
+
macroFiles.map(macroFilePath => {
|
|
147
|
+
return new Promise<void>(resolve => {
|
|
148
|
+
fse.readFile(macroFilePath, 'utf-8').then(file => {
|
|
149
|
+
const key = path.relative(tempPath, macroFilePath);
|
|
150
|
+
log.info(`注册宏:${key}`);
|
|
151
|
+
engine.registerMacro(key, file);
|
|
152
|
+
resolve();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
}),
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 注册所有模板文件
|
|
162
|
+
*
|
|
163
|
+
* @protected
|
|
164
|
+
* @param {string} tempPath
|
|
165
|
+
* @param {HandlebarsEngine} engine
|
|
166
|
+
* @returns {*} {Promise<void>}
|
|
167
|
+
*/
|
|
168
|
+
protected async registerTempFiles(
|
|
169
|
+
tempPath: string,
|
|
170
|
+
engine: HandlebarsEngine,
|
|
171
|
+
): Promise<void> {
|
|
172
|
+
const tempFiles = glob.sync('**/*.hbs', {
|
|
173
|
+
cwd: tempPath,
|
|
174
|
+
dot: true,
|
|
175
|
+
absolute: true,
|
|
176
|
+
ignore: [path.join(MACRO_FOLDER, '**/*.hbs')],
|
|
177
|
+
});
|
|
178
|
+
if (tempFiles.length > 0) {
|
|
179
|
+
await Promise.all(
|
|
180
|
+
tempFiles.map(tempFilePath => {
|
|
181
|
+
return new Promise<void>(resolve => {
|
|
182
|
+
fse.readFile(tempFilePath, 'utf-8').then(file => {
|
|
183
|
+
const key = path.relative(tempPath, tempFilePath);
|
|
184
|
+
log.info(`注册模板:${key}`);
|
|
185
|
+
engine.registerTemp(key, file);
|
|
186
|
+
resolve();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
}),
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 针对加载的配置进行处理
|
|
196
|
+
*
|
|
197
|
+
* @protected
|
|
198
|
+
* @param {IObject} model
|
|
199
|
+
* @returns {*} {IObject}
|
|
200
|
+
*/
|
|
201
|
+
protected transformModel(model: IObject): IObject {
|
|
202
|
+
const keys = Object.keys(model.definitions);
|
|
203
|
+
keys.forEach(key => {
|
|
204
|
+
const item = model.definitions[key];
|
|
205
|
+
if (item.properties) {
|
|
206
|
+
item.propertySize = Object.keys(item.properties).length;
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
return model;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { IObject } from '../../core';
|
|
2
|
+
import { ApiManage } from './api-manage';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 实体方法模型
|
|
6
|
+
*
|
|
7
|
+
* @export
|
|
8
|
+
* @interface IMethodModel
|
|
9
|
+
*/
|
|
10
|
+
export interface IMethodModel {
|
|
11
|
+
/**
|
|
12
|
+
* 方法名称
|
|
13
|
+
*
|
|
14
|
+
* @type {string}
|
|
15
|
+
*/
|
|
16
|
+
name: string;
|
|
17
|
+
/**
|
|
18
|
+
* 请求方式
|
|
19
|
+
*
|
|
20
|
+
* @type {string}
|
|
21
|
+
*/
|
|
22
|
+
mode: string;
|
|
23
|
+
/**
|
|
24
|
+
* 方法模型
|
|
25
|
+
*
|
|
26
|
+
* @type {IObject}
|
|
27
|
+
*/
|
|
28
|
+
model: IObject;
|
|
29
|
+
/**
|
|
30
|
+
* 请求实体
|
|
31
|
+
*
|
|
32
|
+
* @type {IObject}
|
|
33
|
+
*/
|
|
34
|
+
requestEntity?: IObject;
|
|
35
|
+
/**
|
|
36
|
+
* 响应实体
|
|
37
|
+
*
|
|
38
|
+
* @type {IObject}
|
|
39
|
+
*/
|
|
40
|
+
responseEntity?: IObject;
|
|
41
|
+
/**
|
|
42
|
+
* 查询参数
|
|
43
|
+
*
|
|
44
|
+
* @type {IObject[]}
|
|
45
|
+
*/
|
|
46
|
+
queries: IObject[];
|
|
47
|
+
/**
|
|
48
|
+
* 路径参数, 路径示例:/gct-apaas/api/model-comprehensive/model/{key}/{mode}/{modelCategory}
|
|
49
|
+
*
|
|
50
|
+
* @type {string[]}
|
|
51
|
+
*/
|
|
52
|
+
pathParams?: string[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 实体模型
|
|
57
|
+
*
|
|
58
|
+
* @export
|
|
59
|
+
* @interface IEntityModel
|
|
60
|
+
*/
|
|
61
|
+
export interface IEntityModel {
|
|
62
|
+
/**
|
|
63
|
+
* 实体名称
|
|
64
|
+
*
|
|
65
|
+
* @type {string}
|
|
66
|
+
*/
|
|
67
|
+
entityName: string;
|
|
68
|
+
/**
|
|
69
|
+
* 平台标识 apaas, platform
|
|
70
|
+
*
|
|
71
|
+
* @type {string}
|
|
72
|
+
*/
|
|
73
|
+
tag: string;
|
|
74
|
+
/**
|
|
75
|
+
* 实体名称(同name)
|
|
76
|
+
*
|
|
77
|
+
* @type {string}
|
|
78
|
+
*/
|
|
79
|
+
api: string;
|
|
80
|
+
/**
|
|
81
|
+
* 实体模型
|
|
82
|
+
*
|
|
83
|
+
* @type {IObject}
|
|
84
|
+
*/
|
|
85
|
+
model: IObject;
|
|
86
|
+
/**
|
|
87
|
+
* 实体方法模型
|
|
88
|
+
*
|
|
89
|
+
* @type {IMethodModel[]}
|
|
90
|
+
*/
|
|
91
|
+
methods: IMethodModel[];
|
|
92
|
+
/**
|
|
93
|
+
* 实体引用实体名称集合
|
|
94
|
+
*
|
|
95
|
+
* @type {string[]}
|
|
96
|
+
*/
|
|
97
|
+
entityRefs: string[];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 模型管理
|
|
102
|
+
*
|
|
103
|
+
* @export
|
|
104
|
+
* @class ModelManage
|
|
105
|
+
*/
|
|
106
|
+
export class ModelManage {
|
|
107
|
+
/**
|
|
108
|
+
* 所有实体模型
|
|
109
|
+
*
|
|
110
|
+
* @type {Map<string, IEntityModel>}
|
|
111
|
+
*/
|
|
112
|
+
readonly entities = new Map<string, IEntityModel>();
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 所有用到的实体定义
|
|
116
|
+
*
|
|
117
|
+
* @type {Map<string, IObject>}
|
|
118
|
+
*/
|
|
119
|
+
readonly definitions = new Map<string, IObject>();
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 目前接口中的基础数据类型
|
|
123
|
+
*
|
|
124
|
+
* @protected
|
|
125
|
+
*/
|
|
126
|
+
protected basicDataType = [
|
|
127
|
+
'any',
|
|
128
|
+
'number',
|
|
129
|
+
'string',
|
|
130
|
+
'null',
|
|
131
|
+
'boolean',
|
|
132
|
+
'Void',
|
|
133
|
+
'object',
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
init(tag: string, cfg: IObject): void {
|
|
137
|
+
const apiManage = new ApiManage();
|
|
138
|
+
// 从 swagger 配置生成 api 管理类
|
|
139
|
+
const paths = Object.keys(cfg.paths).filter(pathStr => {
|
|
140
|
+
// 过滤 external 开头,但是 /external/api/tenant/info/byPortOrDomain 需要保留
|
|
141
|
+
return (
|
|
142
|
+
!pathStr.startsWith('/external') ||
|
|
143
|
+
pathStr === '/external/api/tenant/info/byPortOrDomain'
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
paths.forEach((pathStr: string) => {
|
|
147
|
+
const pathCfg = cfg.paths[pathStr];
|
|
148
|
+
apiManage.add(pathStr, pathCfg);
|
|
149
|
+
});
|
|
150
|
+
apiManage.done();
|
|
151
|
+
// 遍历所有实体
|
|
152
|
+
const entityNames = apiManage.cache.keys();
|
|
153
|
+
for (const entityName of entityNames) {
|
|
154
|
+
const entitySet = new Set<string>();
|
|
155
|
+
const entityManage = apiManage.cache.get(entityName)!;
|
|
156
|
+
const methods: IMethodModel[] = [];
|
|
157
|
+
if (entityManage.cache.size > 0) {
|
|
158
|
+
// 遍历所有方法,tags 拼接规则:方法名-请求方式
|
|
159
|
+
const tags = entityManage.cache.keys();
|
|
160
|
+
for (const tag of tags) {
|
|
161
|
+
// 方法名称、请求方式
|
|
162
|
+
const [methodName, mode] = tag.split(':');
|
|
163
|
+
const config = entityManage.cache.get(tag)!;
|
|
164
|
+
// 请求实体对象
|
|
165
|
+
let requestEntity: IObject | undefined = undefined;
|
|
166
|
+
// 获取 body 参数
|
|
167
|
+
const param = config.parameters.find((param: IObject) => {
|
|
168
|
+
if (param.in === 'body') {
|
|
169
|
+
return param;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
if (param && param.schema) {
|
|
173
|
+
// 后端通用接口特殊处理,名称为 requestBody 的参数,直接定义为 IObject
|
|
174
|
+
if (param.name === 'requestBody') {
|
|
175
|
+
requestEntity = { title: 'IObject' };
|
|
176
|
+
} else if (param.name === 'file') {
|
|
177
|
+
requestEntity = { title: 'UploadFileData' };
|
|
178
|
+
} else {
|
|
179
|
+
const refKey = this.getOriginRef(param.schema);
|
|
180
|
+
// 根据 body 参数获取引用的实体
|
|
181
|
+
requestEntity = cfg.definitions[refKey];
|
|
182
|
+
if (requestEntity && Object.keys(requestEntity).length > 0) {
|
|
183
|
+
this.definitions.set(refKey, requestEntity);
|
|
184
|
+
entitySet.add(refKey);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// 响应实体对象
|
|
189
|
+
let responseEntity: IObject | undefined = undefined;
|
|
190
|
+
if (config.responses['200'].schema) {
|
|
191
|
+
const refKey = this.getOriginRef(config.responses['200'].schema);
|
|
192
|
+
// 根据 body 参数获取引用的实体
|
|
193
|
+
responseEntity = cfg.definitions[refKey];
|
|
194
|
+
if (responseEntity && Object.keys(responseEntity).length > 0) {
|
|
195
|
+
this.definitions.set(refKey, responseEntity);
|
|
196
|
+
entitySet.add(refKey);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const queries: IObject[] = config.parameters.filter(
|
|
200
|
+
(param: IObject) => {
|
|
201
|
+
if (param.in === 'query') {
|
|
202
|
+
return param;
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
);
|
|
206
|
+
// 2026 年 2 月 3 日 去掉此逻辑,已经支持了 pathParams 的处理,不再需要特殊处理
|
|
207
|
+
// {
|
|
208
|
+
// // 当put方法需要在url中拼接主键时,默认补充query查询参数
|
|
209
|
+
// if (methodName === '{id}') {
|
|
210
|
+
// queries.push({
|
|
211
|
+
// name: 'id',
|
|
212
|
+
// in: 'query',
|
|
213
|
+
// description: '数据主键',
|
|
214
|
+
// required: true,
|
|
215
|
+
// type: 'string',
|
|
216
|
+
// });
|
|
217
|
+
// }
|
|
218
|
+
// }
|
|
219
|
+
// 请求路径 config.requestPath
|
|
220
|
+
const matches = [...config.requestPath.matchAll(/\{([^}]*)\}/g)].map(
|
|
221
|
+
m => m[1],
|
|
222
|
+
);
|
|
223
|
+
methods.push({
|
|
224
|
+
name: methodName !== 'undefined' ? methodName : '',
|
|
225
|
+
mode,
|
|
226
|
+
model: config,
|
|
227
|
+
requestEntity,
|
|
228
|
+
responseEntity,
|
|
229
|
+
queries,
|
|
230
|
+
pathParams: matches,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
this.entities.set(entityName, {
|
|
234
|
+
tag,
|
|
235
|
+
entityName: entityName,
|
|
236
|
+
api: entityName,
|
|
237
|
+
model: cfg.definitions[entityName],
|
|
238
|
+
methods,
|
|
239
|
+
entityRefs: Array.from(entitySet.values()).filter(item => {
|
|
240
|
+
// 过滤掉基础类型的导入
|
|
241
|
+
return (
|
|
242
|
+
this.basicDataType.findIndex(type => {
|
|
243
|
+
return item.indexOf(`«${type}»`) !== -1;
|
|
244
|
+
}) === -1 && !this.basicDataType.includes(item)
|
|
245
|
+
);
|
|
246
|
+
}),
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* 获取接口的引用对象
|
|
254
|
+
*
|
|
255
|
+
* @protected
|
|
256
|
+
* @param {IObject} data
|
|
257
|
+
* @returns {*} {string}
|
|
258
|
+
*/
|
|
259
|
+
protected getOriginRef(data: IObject): string {
|
|
260
|
+
const { $ref, originalRef, type } = data;
|
|
261
|
+
if (type) return type;
|
|
262
|
+
if (originalRef) return originalRef;
|
|
263
|
+
if ($ref) {
|
|
264
|
+
const _refs_ = $ref.split('/');
|
|
265
|
+
return _refs_[_refs_.length - 1];
|
|
266
|
+
}
|
|
267
|
+
return 'any';
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 特殊实体映射配置
|
|
3
|
+
* 用于处理 swagger 中存在的特殊命名或映射规则
|
|
4
|
+
*/
|
|
5
|
+
export interface SpecialEntityMapping {
|
|
6
|
+
/** 标准实体名称 */
|
|
7
|
+
canonical: string;
|
|
8
|
+
/** 别名映射列表 */
|
|
9
|
+
aliases: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 特殊实体配置列表
|
|
14
|
+
* 当后续有类似的特殊处理需求时,直接在此列表中添加新条目即可
|
|
15
|
+
*/
|
|
16
|
+
export const SPECIAL_ENTITIES: SpecialEntityMapping[] = [
|
|
17
|
+
{
|
|
18
|
+
canonical: 'med-pro',
|
|
19
|
+
aliases: ['medpro', 'medPro', 'med-pro'],
|
|
20
|
+
},
|
|
21
|
+
// 示例:如果后续有其他特殊映射,按照下面的格式添加
|
|
22
|
+
// {
|
|
23
|
+
// canonical: 'some-entity',
|
|
24
|
+
// aliases: ['someEntity', 'someentity', 'some-entity'],
|
|
25
|
+
// },
|
|
26
|
+
];
|