fx-spec-hub 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/README.md +66 -0
- package/bin/swagger-admin.js +5 -0
- package/dist/bootstrap.d.ts +1 -0
- package/dist/bootstrap.js +24 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/bootstrap.mjs +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +109 -0
- package/dist/cli.js.map +1 -0
- package/dist/data/admin-backend-api.json +46845 -0
- package/dist/data/strapi-backend-api.json +10002 -0
- package/dist/data/strapi-enum-options.json +11890 -0
- package/dist/data/web-backend-api.json +19943 -0
- package/dist/env/admin/.env.common +13 -0
- package/dist/env/admin/.env.dev +14 -0
- package/dist/env/admin/.env.prod +0 -0
- package/dist/env/admin/.env.test +13 -0
- package/dist/env/admin/.env.uat +14 -0
- package/dist/env/user/.env.common +13 -0
- package/dist/env/user/.env.dev +12 -0
- package/dist/env/user/.env.prod +0 -0
- package/dist/env/user/.env.test +11 -0
- package/dist/env/user/.env.uat +11 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +6 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +14 -0
- package/dist/logger.js.map +1 -0
- package/dist/strapi-enums.d.ts +17 -0
- package/dist/strapi-enums.js +143 -0
- package/dist/strapi-enums.js.map +1 -0
- package/dist/swagger.d.ts +43 -0
- package/dist/swagger.js +96 -0
- package/dist/swagger.js.map +1 -0
- package/package.json +56 -0
- package/scripts/postbuild.mjs +32 -0
- package/swagger-template/api.ejs +30 -0
- package/swagger-template/data-contract-jsdoc.ejs +37 -0
- package/swagger-template/data-contracts.ejs +49 -0
- package/swagger-template/enum-data-contract.ejs +12 -0
- package/swagger-template/index-axios.ejs +14 -0
- package/swagger-template/index-fetch.ejs +14 -0
- package/swagger-template/interface-data-contract.ejs +10 -0
- package/swagger-template/object-field-jsdoc.ejs +28 -0
- package/swagger-template/procedure-call.ejs +102 -0
- package/swagger-template/route-docs.ejs +30 -0
- package/swagger-template/route-name.ejs +43 -0
- package/swagger-template/route-type.ejs +23 -0
- package/swagger-template/route-types.ejs +18 -0
- package/swagger-template/type-data-contract.ejs +15 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# sentry 团队slug
|
|
2
|
+
VITE_SENTRY_ORG=sentry
|
|
3
|
+
# sentry 地址
|
|
4
|
+
VITE_SENTRY_URL=https://sentry.finex18.com
|
|
5
|
+
# sentry 认证token
|
|
6
|
+
VITE_SENTRY_AUTH_TOKEN=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
|
|
7
|
+
VITE_SENTRY_PROJECT=exchange-admin-frontend
|
|
8
|
+
|
|
9
|
+
# dev 分支有的环境变量
|
|
10
|
+
# EDITOR=vscode
|
|
11
|
+
# FALLBACK_LNG=en
|
|
12
|
+
# SENTRY_DISABLED=true
|
|
13
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
VITE_OTEL_EXPORTER_OTLP_ENDPOINT =
|
|
2
|
+
VITE_SENTRY_DSN =
|
|
3
|
+
|
|
4
|
+
# SERVER_BASE_URL=http://10.1.9.121/api
|
|
5
|
+
ACCESS_CONTROL_ALLOW_ORIGIN=https://www.894568.xyz
|
|
6
|
+
STRAPI_INTERNAL_DOMAIN=https://cms.894568.xyz
|
|
7
|
+
SENTRY_DISABLED=true
|
|
8
|
+
|
|
9
|
+
VITE_APP_BASE_URL=https://api-admin.894568.xyz
|
|
10
|
+
VITE_APP_CMS_URL=https://cms.894568.xyz/api
|
|
11
|
+
VITE_APP_MOCK_URL=https://api-admin.894568.xyz
|
|
12
|
+
VITE_APP_TPS_URL =
|
|
13
|
+
VITE_APP_CPU_URL =
|
|
14
|
+
VITE_APP_GRAFANA_URL = https://grafana.894568.xyz/d/eeet5hhf3xszkc/cpu-memory
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
VITE_OTEL_EXPORTER_OTLP_ENDPOINT = https://otel.finex-test.com/v1/traces
|
|
2
|
+
VITE_SENTRY_DSN = https://4f08e4744edf25ca7b9cb2e1eae2b6bb@sentry.finex18.com/12
|
|
3
|
+
|
|
4
|
+
# API 地址
|
|
5
|
+
VITE_APP_BASE_URL = https://api-admin.finex-test.com
|
|
6
|
+
VITE_APP_CMS_URL = https://cms.finex-test.com/api
|
|
7
|
+
VITE_APP_MOCK_URL = https://api-admin.finex-test.com
|
|
8
|
+
VITE_API_PROXY_TARGET = https://api-admin.finex-test.com
|
|
9
|
+
# Grafana 地址
|
|
10
|
+
VITE_APP_TPS_URL =
|
|
11
|
+
VITE_APP_CPU_URL =
|
|
12
|
+
VITE_APP_GRAFANA_URL = https://grafana.finex-test.com/d/eeet5hhf3xszkc/cpu-memory
|
|
13
|
+
VITE_IS_TEST_ENVIRONMENT = true
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
VITE_OTEL_EXPORTER_OTLP_ENDPOINT =
|
|
2
|
+
VITE_SENTRY_DSN =
|
|
3
|
+
|
|
4
|
+
# API 地址
|
|
5
|
+
VITE_APP_BASE_URL = https://api-admin.finex-uat.com
|
|
6
|
+
VITE_APP_CMS_URL = https://cms.finex-uat.com/api
|
|
7
|
+
VITE_APP_MOCK_URL = https://api-admin.finex-uat.com
|
|
8
|
+
VITE_API_PROXY_TARGET = https://api-admin.finex-uat.com
|
|
9
|
+
# Grafana 地址
|
|
10
|
+
VITE_APP_TPS_URL = https://grafana.finex-uat.com/d/aeet5otmhyd4wc/spotclearing?orgId=1&from=now-24h&to=now&timezone=browser&refresh=5s&kiosk&theme=light&kiosk
|
|
11
|
+
VITE_APP_CPU_URL = https://grafana.finex-uat.com/d/beet5sfiedr0gc/cpu-memory?orgId=1&from=now-24h&to=now&timezone=browser&refresh=5s&kiosk&theme=light&kiosk
|
|
12
|
+
VITE_APP_GRAFANA_URL = https://grafana.894577.com/d/eeet5hhf3xszkc/cpu-memory
|
|
13
|
+
VITE_IS_TEST_ENVIRONMENT = false
|
|
14
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
EDITOR=vscode
|
|
2
|
+
FALLBACK_LNG=en
|
|
3
|
+
|
|
4
|
+
SENTRY_DISABLED=true
|
|
5
|
+
|
|
6
|
+
# sentry 团队slug
|
|
7
|
+
SENTRY_ORG=sentry
|
|
8
|
+
# sentry 地址
|
|
9
|
+
SENTRY_URL=https://sentry.finex18.com
|
|
10
|
+
# sentry 认证token
|
|
11
|
+
SENTRY_AUTH_TOKEN=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
|
|
12
|
+
SENTRY_PROJECT=exchange-user-frontend
|
|
13
|
+
SENTRY_DSN=https://81c5d8bcda525c50c97758448b545dc8@sentry.finex18.com/4
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
ACCESS_CONTROL_ALLOW_ORIGIN=https://www.894568.xyz
|
|
2
|
+
SENTRY_DISABLED=true
|
|
3
|
+
|
|
4
|
+
BASE_URL=https://web-api-service.894568.xyz
|
|
5
|
+
APP_BASE_URL=https://app-api-service.894568.xyz
|
|
6
|
+
SERVER_BASE_URL=http:2000-exchange-web-api-service-http.apisix:9080
|
|
7
|
+
WS_URL=wss://ws.894568.xyz
|
|
8
|
+
STRAPI_BASE_DOMAIN=https://cms.894568.xyz
|
|
9
|
+
STATIC_DOMAIN=https://static.894568.xyz
|
|
10
|
+
GA_ID=
|
|
11
|
+
CAPTCHA_ID=8d57f6d065f143e645d86ed6ff7206f5
|
|
12
|
+
REOWN_PROJECT_ID=1f5038de5b4e29414710cb53ccfd92f0
|
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
ACCESS_CONTROL_ALLOW_ORIGIN=https://www.finex-test.com
|
|
2
|
+
|
|
3
|
+
BASE_URL=https://web-api.finex-test.com
|
|
4
|
+
SERVER_BASE_URL=http:exchange-web-api-service:9000
|
|
5
|
+
APP_BASE_URL=https://app-api.finex-test.com
|
|
6
|
+
WS_URL=wss://ws.finex-test.com
|
|
7
|
+
STRAPI_BASE_DOMAIN=https://cms.finex-test.com
|
|
8
|
+
STATIC_DOMAIN=https://static.finex-test.com
|
|
9
|
+
GA_ID=
|
|
10
|
+
CAPTCHA_ID=8d57f6d065f143e645d86ed6ff7206f5
|
|
11
|
+
REOWN_PROJECT_ID=1f5038de5b4e29414710cb53ccfd92f0
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
ACCESS_CONTROL_ALLOW_ORIGIN=https://www.finex-uat.com
|
|
2
|
+
|
|
3
|
+
BASE_URL=https://web-api.finex-uat.com
|
|
4
|
+
SERVER_BASE_URL=http:exchange-web-api-service:9000
|
|
5
|
+
APP_BASE_URL=https://app-api.finex-uat.com
|
|
6
|
+
WS_URL=wss://ws.finex-uat.com
|
|
7
|
+
STRAPI_BASE_DOMAIN=https://cms.finex-uat.com
|
|
8
|
+
STATIC_DOMAIN=https://static.finex-uat.com
|
|
9
|
+
GA_ID=
|
|
10
|
+
CAPTCHA_ID=8d57f6d065f143e645d86ed6ff7206f5
|
|
11
|
+
REOWN_PROJECT_ID=1f5038de5b4e29414710cb53ccfd92f0
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { generateSwaggerApi } from './swagger';
|
|
2
|
+
export type { SwaggerGenerateOptions, SwaggerGenerateResult, SwaggerHttpClientType, } from './swagger';
|
|
3
|
+
export { generateStrapiEnums } from './strapi-enums';
|
|
4
|
+
export type { StrapiEnumsGenerateOptions } from './strapi-enums';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateStrapiEnums = exports.generateSwaggerApi = void 0;
|
|
4
|
+
var swagger_1 = require("./swagger");
|
|
5
|
+
Object.defineProperty(exports, "generateSwaggerApi", { enumerable: true, get: function () { return swagger_1.generateSwaggerApi; } });
|
|
6
|
+
var strapi_enums_1 = require("./strapi-enums");
|
|
7
|
+
Object.defineProperty(exports, "generateStrapiEnums", { enumerable: true, get: function () { return strapi_enums_1.generateStrapiEnums; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qCAA+C;AAAtC,6GAAA,kBAAkB,OAAA;AAO3B,+CAAqD;AAA5C,mHAAA,mBAAmB,OAAA"}
|
package/dist/index.mjs
ADDED
package/dist/logger.d.ts
ADDED
package/dist/logger.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.log = log;
|
|
4
|
+
exports.logError = logError;
|
|
5
|
+
function log(message) {
|
|
6
|
+
// eslint-disable-next-line no-console
|
|
7
|
+
console.log(`[swagger-admin] ${message}`);
|
|
8
|
+
}
|
|
9
|
+
function logError(error) {
|
|
10
|
+
const message = error instanceof Error ? `${error.message}\n${error.stack ?? ''}` : String(error);
|
|
11
|
+
// eslint-disable-next-line no-console
|
|
12
|
+
console.error(`[swagger-admin] ${message}`);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";;AAAA,kBAGC;AAED,4BAKC;AAVD,SAAgB,GAAG,CAAC,OAAe;IACjC,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,SAAgB,QAAQ,CAAC,KAAc;IACrC,MAAM,OAAO,GACX,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACpF,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface StrapiEnumsGenerateOptions {
|
|
2
|
+
/**
|
|
3
|
+
* 输入:
|
|
4
|
+
* - URL(https://.../api/options 或完整带 query 的 URL)
|
|
5
|
+
* - 本地 JSON 文件路径(用于离线生成)
|
|
6
|
+
*/
|
|
7
|
+
input?: string;
|
|
8
|
+
/** 输出文件路径(相对/绝对) */
|
|
9
|
+
output: string;
|
|
10
|
+
/** pageSize(当 input 不含 query 时才会自动拼默认 query) */
|
|
11
|
+
pageSize?: number;
|
|
12
|
+
/** locale(当 input 不含 query 时才会自动拼默认 query) */
|
|
13
|
+
locale?: string;
|
|
14
|
+
/** 指定 prettier 配置文件路径(可选) */
|
|
15
|
+
prettierConfig?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function generateStrapiEnums(options: StrapiEnumsGenerateOptions): Promise<void>;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateStrapiEnums = generateStrapiEnums;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const prettier_1 = __importDefault(require("prettier"));
|
|
10
|
+
const qs_1 = __importDefault(require("qs"));
|
|
11
|
+
const defaultStrapiEnumOptionsPath = node_path_1.default.resolve(__dirname, './data/strapi-enum-options.json');
|
|
12
|
+
function resolveFromCwd(maybePath) {
|
|
13
|
+
return node_path_1.default.isAbsolute(maybePath) ? maybePath : node_path_1.default.resolve(process.cwd(), maybePath);
|
|
14
|
+
}
|
|
15
|
+
function isURL(str) {
|
|
16
|
+
return (/^https?:\/\/([a-z0-9-]{1,63}\.){1,}[a-z]{2,63}(:\d{1,5})?(\/[^\s]*)?$/i.test(str) || /^https?:\/\/(\d{1,3}\.){3}\d{1,3}(:\d{1,5})?(\/[^\s]*)?$/i.test(str));
|
|
17
|
+
}
|
|
18
|
+
async function fetchJson(url) {
|
|
19
|
+
const response = await fetch(url);
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
throw new Error(`请求失败:${response.status} ${response.statusText}`);
|
|
22
|
+
}
|
|
23
|
+
return response.json();
|
|
24
|
+
}
|
|
25
|
+
function toValidIdentifier(raw) {
|
|
26
|
+
let identifier = '';
|
|
27
|
+
for (const char of String(raw ?? '')) {
|
|
28
|
+
const isLower = char >= 'a' && char <= 'z';
|
|
29
|
+
const isUpper = char >= 'A' && char <= 'Z';
|
|
30
|
+
const isDigit = char >= '0' && char <= '9';
|
|
31
|
+
const isUnderscore = char === '_';
|
|
32
|
+
identifier += isLower || isUpper || isDigit || isUnderscore ? char : '_';
|
|
33
|
+
}
|
|
34
|
+
if (/^\d/.test(identifier)) {
|
|
35
|
+
identifier = 'V_' + identifier;
|
|
36
|
+
}
|
|
37
|
+
let prev = '';
|
|
38
|
+
while (prev !== identifier) {
|
|
39
|
+
prev = identifier;
|
|
40
|
+
identifier = identifier.replace('__', '_');
|
|
41
|
+
}
|
|
42
|
+
let start = 0;
|
|
43
|
+
let end = identifier.length;
|
|
44
|
+
while (start < identifier.length && identifier[start] === '_')
|
|
45
|
+
start++;
|
|
46
|
+
while (end > start && identifier[end - 1] === '_')
|
|
47
|
+
end--;
|
|
48
|
+
identifier = identifier.slice(start, end);
|
|
49
|
+
return identifier || 'UNKNOWN';
|
|
50
|
+
}
|
|
51
|
+
function generateEnumCode(rows) {
|
|
52
|
+
const grouped = new Map();
|
|
53
|
+
for (const item of rows) {
|
|
54
|
+
const typeName = item.options_type?.name;
|
|
55
|
+
const typeRemark = item.options_type?.remark ?? '';
|
|
56
|
+
if (!typeName)
|
|
57
|
+
continue;
|
|
58
|
+
const bucket = grouped.get(typeName) ??
|
|
59
|
+
(() => {
|
|
60
|
+
const next = { remark: typeRemark, options: [] };
|
|
61
|
+
grouped.set(typeName, next);
|
|
62
|
+
return next;
|
|
63
|
+
})();
|
|
64
|
+
bucket.options.push({
|
|
65
|
+
value: item.value,
|
|
66
|
+
label_cn: item.label_cn,
|
|
67
|
+
sort: item.sort,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
let enumCode = '';
|
|
71
|
+
const optionsTypeParts = [];
|
|
72
|
+
for (const [typeName, typeData] of grouped.entries()) {
|
|
73
|
+
typeData.options.sort((a, b) => a.sort - b.sort);
|
|
74
|
+
enumCode += `/**\n * ${typeData.remark}\n */\n`;
|
|
75
|
+
enumCode += `export enum ${typeName} {\n`;
|
|
76
|
+
for (const option of typeData.options) {
|
|
77
|
+
enumCode += ` /**\n * ${option.label_cn}\n */\n`;
|
|
78
|
+
const enumKey = toValidIdentifier(option.value);
|
|
79
|
+
enumCode += ` ${enumKey} = '${option.value}',\n`;
|
|
80
|
+
}
|
|
81
|
+
enumCode += '}\n\n';
|
|
82
|
+
optionsTypeParts.push(`'${typeName}'`);
|
|
83
|
+
}
|
|
84
|
+
enumCode += `export type OptionsType = ${optionsTypeParts.join(' | ')}`;
|
|
85
|
+
return enumCode.trim();
|
|
86
|
+
}
|
|
87
|
+
function normalizeRows(json) {
|
|
88
|
+
if (Array.isArray(json))
|
|
89
|
+
return json;
|
|
90
|
+
if (json && typeof json === 'object') {
|
|
91
|
+
const code = json.code;
|
|
92
|
+
if (typeof code === 'string' && code !== 'OK') {
|
|
93
|
+
throw new Error(`接口返回非 OK:${code}`);
|
|
94
|
+
}
|
|
95
|
+
const data = json.data;
|
|
96
|
+
if (Array.isArray(data))
|
|
97
|
+
return data;
|
|
98
|
+
}
|
|
99
|
+
throw new Error('输入数据格式不正确:需要 Array 或包含 data:Array 的对象');
|
|
100
|
+
}
|
|
101
|
+
function buildDefaultQuery(pageSize, locale) {
|
|
102
|
+
return qs_1.default.stringify({
|
|
103
|
+
'pagination[pageSize]': pageSize,
|
|
104
|
+
locale,
|
|
105
|
+
populate: {
|
|
106
|
+
options_type: {
|
|
107
|
+
fields: ['name', 'remark'],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
}, { encodeValuesOnly: true });
|
|
111
|
+
}
|
|
112
|
+
function withDefaultQueryIfNeeded(url, pageSize, locale) {
|
|
113
|
+
if (url.includes('?'))
|
|
114
|
+
return url;
|
|
115
|
+
return `${url}?${buildDefaultQuery(pageSize, locale)}`;
|
|
116
|
+
}
|
|
117
|
+
async function formatWithPrettier(code, outputPath, configPath) {
|
|
118
|
+
const config = await prettier_1.default
|
|
119
|
+
.resolveConfig(outputPath, configPath ? { config: resolveFromCwd(configPath) } : undefined)
|
|
120
|
+
.catch(() => null);
|
|
121
|
+
return prettier_1.default.format(code, {
|
|
122
|
+
parser: 'typescript',
|
|
123
|
+
...(config ?? {}),
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
async function generateStrapiEnums(options) {
|
|
127
|
+
const { input, output, pageSize = 1000, locale = 'zh-CN', prettierConfig } = options;
|
|
128
|
+
const outputPath = resolveFromCwd(output);
|
|
129
|
+
const outputDir = node_path_1.default.dirname(outputPath);
|
|
130
|
+
await node_fs_1.default.promises.mkdir(outputDir, { recursive: true });
|
|
131
|
+
const resolvedInput = input ?? defaultStrapiEnumOptionsPath;
|
|
132
|
+
if (!input && !node_fs_1.default.existsSync(resolvedInput)) {
|
|
133
|
+
throw new Error(`未找到默认 Strapi 枚举数据文件:${resolvedInput}`);
|
|
134
|
+
}
|
|
135
|
+
const json = isURL(resolvedInput)
|
|
136
|
+
? await fetchJson(withDefaultQueryIfNeeded(resolvedInput, pageSize, locale))
|
|
137
|
+
: JSON.parse(await node_fs_1.default.promises.readFile(resolveFromCwd(resolvedInput), 'utf-8'));
|
|
138
|
+
const rows = normalizeRows(json);
|
|
139
|
+
const code = generateEnumCode(rows);
|
|
140
|
+
const formatted = await formatWithPrettier(code, outputPath, prettierConfig);
|
|
141
|
+
await node_fs_1.default.promises.writeFile(outputPath, formatted, 'utf-8');
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=strapi-enums.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strapi-enums.js","sourceRoot":"","sources":["../src/strapi-enums.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type SwaggerHttpClientType = 'axios' | 'fetch';
|
|
2
|
+
export interface SwaggerGenerateResult {
|
|
3
|
+
outputDir: string;
|
|
4
|
+
templatesDir: string;
|
|
5
|
+
modules: {
|
|
6
|
+
name: string;
|
|
7
|
+
}[];
|
|
8
|
+
indexPath: string;
|
|
9
|
+
dataContractsPath: string;
|
|
10
|
+
files: unknown[];
|
|
11
|
+
}
|
|
12
|
+
export interface SwaggerGenerateOptions {
|
|
13
|
+
/**
|
|
14
|
+
* OpenAPI 输入:
|
|
15
|
+
* - URL(https://...)
|
|
16
|
+
* - 本地文件路径(相对/绝对)
|
|
17
|
+
* - 已解析的 JSON 对象(spec)
|
|
18
|
+
*/
|
|
19
|
+
input?: string | Record<string, unknown>;
|
|
20
|
+
/** 输出目录(相对/绝对) */
|
|
21
|
+
output: string;
|
|
22
|
+
/** swagger-typescript-api 模板目录(默认使用本包自带 swagger-template) */
|
|
23
|
+
templateDir?: string;
|
|
24
|
+
/** 生成的 index.ts 中的 baseURL(字符串字面量),例如:https://api.example.com */
|
|
25
|
+
baseURL: string;
|
|
26
|
+
/** 生成的 index.ts 中 HttpClient 的 import 路径 */
|
|
27
|
+
httpClientPath?: string;
|
|
28
|
+
/** swagger-typescript-api 的客户端类型 */
|
|
29
|
+
httpClientType?: SwaggerHttpClientType;
|
|
30
|
+
/** 是否拆分模块输出 */
|
|
31
|
+
modular?: boolean;
|
|
32
|
+
/** 生成前清空输出目录 */
|
|
33
|
+
cleanOutput?: boolean;
|
|
34
|
+
/** 是否解包响应体(依赖模板实现) */
|
|
35
|
+
unwrapResponseData?: boolean;
|
|
36
|
+
/** 是否提取 enum */
|
|
37
|
+
extractEnums?: boolean;
|
|
38
|
+
/** 是否生成联合类型枚举 */
|
|
39
|
+
generateUnionEnums?: boolean;
|
|
40
|
+
/** 生成成功后的回调(在 index.ts 写入完成后触发) */
|
|
41
|
+
onSuccess?: (result: SwaggerGenerateResult) => void | Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
export declare function generateSwaggerApi(options: SwaggerGenerateOptions, isStrapi?: boolean): Promise<SwaggerGenerateResult>;
|
package/dist/swagger.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateSwaggerApi = generateSwaggerApi;
|
|
7
|
+
const ejs_1 = __importDefault(require("ejs"));
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const swagger_typescript_api_1 = require("swagger-typescript-api");
|
|
11
|
+
const webBackendApiPath = node_path_1.default.resolve(__dirname, './data/web-backend-api.json');
|
|
12
|
+
const adminBackendApiPath = node_path_1.default.resolve(__dirname, './data/admin-backend-api.json');
|
|
13
|
+
const strapiBackendApiPath = node_path_1.default.resolve(__dirname, './data/strapi-backend-api.json');
|
|
14
|
+
function isURL(str) {
|
|
15
|
+
return (/^https?:\/\/([a-z0-9-]{1,63}\.){1,}[a-z]{2,63}(:\d{1,5})?(\/[^\s]*)?$/i.test(str) || /^https?:\/\/(\d{1,3}\.){3}\d{1,3}(:\d{1,5})?(\/[^\s]*)?$/i.test(str));
|
|
16
|
+
}
|
|
17
|
+
function isJSONObject(data) {
|
|
18
|
+
return typeof data === 'object' && data !== null && !Array.isArray(data);
|
|
19
|
+
}
|
|
20
|
+
function resolveFromCwd(maybePath) {
|
|
21
|
+
return node_path_1.default.isAbsolute(maybePath) ? maybePath : node_path_1.default.resolve(process.cwd(), maybePath);
|
|
22
|
+
}
|
|
23
|
+
function getDefaultTemplateDir() {
|
|
24
|
+
// 源码在 src/,构建后在 dist/,两者都能通过 ../swagger-template 指向包根目录模板
|
|
25
|
+
return node_path_1.default.resolve(__dirname, '../swagger-template');
|
|
26
|
+
}
|
|
27
|
+
async function generateSwaggerApi(options, isStrapi = false) {
|
|
28
|
+
const { input, output, templateDir = getDefaultTemplateDir(), baseURL, httpClientPath = '@/utils/request', httpClientType = 'axios', modular = true, cleanOutput = true, unwrapResponseData = true, extractEnums = true, generateUnionEnums = false, onSuccess, } = options;
|
|
29
|
+
if (typeof baseURL !== 'string' || baseURL.length === 0) {
|
|
30
|
+
throw new Error('baseURL 必须是非空字符串');
|
|
31
|
+
}
|
|
32
|
+
const outputDir = resolveFromCwd(output);
|
|
33
|
+
const templatesDir = resolveFromCwd(templateDir);
|
|
34
|
+
let apiConfig = {};
|
|
35
|
+
if (!input) {
|
|
36
|
+
const inputPath = isStrapi ? strapiBackendApiPath : process.env.CLIENT_TYPE === 'admin' ? adminBackendApiPath : webBackendApiPath;
|
|
37
|
+
if (!node_fs_1.default.existsSync(inputPath)) {
|
|
38
|
+
throw new Error(`未找到默认 OpenAPI 文件:${inputPath}`);
|
|
39
|
+
}
|
|
40
|
+
apiConfig = { input: inputPath };
|
|
41
|
+
}
|
|
42
|
+
else if (isJSONObject(input)) {
|
|
43
|
+
apiConfig = { spec: input };
|
|
44
|
+
}
|
|
45
|
+
else if (isURL(input)) {
|
|
46
|
+
apiConfig = { url: input };
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
apiConfig = { input: resolveFromCwd(input) };
|
|
50
|
+
}
|
|
51
|
+
const { files } = await (0, swagger_typescript_api_1.generateApi)({
|
|
52
|
+
output: outputDir,
|
|
53
|
+
...apiConfig,
|
|
54
|
+
httpClientType,
|
|
55
|
+
modular,
|
|
56
|
+
cleanOutput,
|
|
57
|
+
unwrapResponseData,
|
|
58
|
+
extractEnums,
|
|
59
|
+
generateUnionEnums,
|
|
60
|
+
templates: templatesDir,
|
|
61
|
+
// @ts-expect-error swagger-typescript-api 的类型声明对 httpClient 扩展不完整
|
|
62
|
+
httpClient: {
|
|
63
|
+
path: httpClientPath,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
const modules = files
|
|
67
|
+
.filter((file) => !file.fileName.includes('-'))
|
|
68
|
+
.map((file) => ({ name: file.fileName }));
|
|
69
|
+
// 后处理:移除 data-contracts.ts 中的 @ts-nocheck(模板可能会插入)
|
|
70
|
+
const dataContractsPath = node_path_1.default.join(outputDir, 'data-contracts.ts');
|
|
71
|
+
if (node_fs_1.default.existsSync(dataContractsPath)) {
|
|
72
|
+
const content = await node_fs_1.default.promises.readFile(dataContractsPath, 'utf-8');
|
|
73
|
+
const cleaned = content.replace(/\/\/ @ts-nocheck\n?/, '');
|
|
74
|
+
await node_fs_1.default.promises.writeFile(dataContractsPath, cleaned, 'utf-8');
|
|
75
|
+
}
|
|
76
|
+
const indexTemplate = httpClientType === 'fetch' ? 'index-fetch.ejs' : 'index-axios.ejs';
|
|
77
|
+
const baseURLCode = JSON.stringify(baseURL);
|
|
78
|
+
const indexSource = await ejs_1.default.renderFile(node_path_1.default.join(templatesDir, indexTemplate), {
|
|
79
|
+
modules,
|
|
80
|
+
baseURL: baseURLCode,
|
|
81
|
+
httpClientPath,
|
|
82
|
+
});
|
|
83
|
+
const indexPath = node_path_1.default.join(outputDir, 'index.ts');
|
|
84
|
+
await node_fs_1.default.promises.writeFile(indexPath, indexSource, 'utf-8');
|
|
85
|
+
const result = {
|
|
86
|
+
outputDir,
|
|
87
|
+
templatesDir,
|
|
88
|
+
modules,
|
|
89
|
+
indexPath,
|
|
90
|
+
dataContractsPath,
|
|
91
|
+
files: files,
|
|
92
|
+
};
|
|
93
|
+
await onSuccess?.(result);
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=swagger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swagger.js","sourceRoot":"","sources":["../src/swagger.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fx-spec-hub",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "API 规范中心/控制台",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./bootstrap": {
|
|
15
|
+
"types": "./dist/bootstrap.d.ts",
|
|
16
|
+
"import": "./dist/bootstrap.mjs",
|
|
17
|
+
"require": "./dist/bootstrap.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"swagger-admin": "./bin/swagger-admin.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"bin",
|
|
25
|
+
"dist",
|
|
26
|
+
"scripts",
|
|
27
|
+
"swagger-template",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "rimraf dist && tsc -p tsconfig.json && node scripts/postbuild.mjs",
|
|
32
|
+
"dev": "tsx src/cli.ts",
|
|
33
|
+
"prepare": "npm run build",
|
|
34
|
+
"prepublishOnly": "npm run build"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"dotenv": "^17.3.1",
|
|
41
|
+
"ejs": "^3.1.10",
|
|
42
|
+
"minimist": "^1.2.8",
|
|
43
|
+
"prettier": "^3.6.0",
|
|
44
|
+
"qs": "^6.14.0",
|
|
45
|
+
"swagger-typescript-api": "^13.2.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/ejs": "^3.1.5",
|
|
49
|
+
"@types/minimist": "^1.2.5",
|
|
50
|
+
"@types/node": "^22.13.0",
|
|
51
|
+
"@types/qs": "^6.9.18",
|
|
52
|
+
"rimraf": "^6.0.1",
|
|
53
|
+
"tsx": "^4.19.3",
|
|
54
|
+
"typescript": "^5.8.2"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
const distDir = path.resolve(process.cwd(), 'dist');
|
|
5
|
+
const srcEnvDir = path.resolve(process.cwd(), 'src/env');
|
|
6
|
+
const srcDataDir = path.resolve(process.cwd(), 'src/data');
|
|
7
|
+
|
|
8
|
+
// 为 ESM 使用场景提供真正的 ESM 入口(命名导出可用)。
|
|
9
|
+
// 运行时依然复用 CommonJS 构建产物(dist/index.js)。
|
|
10
|
+
const indexMjs = `
|
|
11
|
+
import cjs from './index.js';
|
|
12
|
+
|
|
13
|
+
export const generateSwaggerApi = cjs.generateSwaggerApi;
|
|
14
|
+
export const generateStrapiEnums = cjs.generateStrapiEnums;
|
|
15
|
+
|
|
16
|
+
export default cjs;
|
|
17
|
+
`.trimStart();
|
|
18
|
+
|
|
19
|
+
await fs.writeFile(path.join(distDir, 'index.mjs'), indexMjs, 'utf-8');
|
|
20
|
+
|
|
21
|
+
// 为 bootstrap 提供 ESM 入口(用于 import 'swagger-admin/bootstrap' 场景)。
|
|
22
|
+
const bootstrapMjs = `
|
|
23
|
+
import './bootstrap.js';
|
|
24
|
+
`.trimStart();
|
|
25
|
+
|
|
26
|
+
await fs.writeFile(path.join(distDir, 'bootstrap.mjs'), bootstrapMjs, 'utf-8');
|
|
27
|
+
|
|
28
|
+
// 将 env 文件复制到 dist/env,供 bootstrap 在运行时读取。
|
|
29
|
+
await fs.cp(srcEnvDir, path.join(distDir, 'env'), { recursive: true });
|
|
30
|
+
|
|
31
|
+
// 将默认 OpenAPI JSON 复制到 dist/data,供 generateSwaggerApi 在未传 input 时使用。
|
|
32
|
+
await fs.cp(srcDataDir, path.join(distDir, 'data'), { recursive: true });
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const { utils, route, config, modelTypes } = it;
|
|
3
|
+
const { _, pascalCase, require } = utils;
|
|
4
|
+
const apiClassName = pascalCase(route.moduleName);
|
|
5
|
+
const routes = route.routes;
|
|
6
|
+
const dataContracts = _.map(modelTypes, "name");
|
|
7
|
+
%>
|
|
8
|
+
|
|
9
|
+
<% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %>
|
|
10
|
+
import { useRequest } from 'ahooks';
|
|
11
|
+
import { Options } from '@/types/useRequest';
|
|
12
|
+
import type { AxiosRequestConfig, AxiosResponse } from "axios"; <% } %>
|
|
13
|
+
import { HttpClient, RequestParams, ContentType, HttpResponse } from "<%= config.httpClient.path %>";
|
|
14
|
+
<% if (dataContracts.length) { %>
|
|
15
|
+
import { <%~ dataContracts.join(", ") %>, DataType, DataTypeWrap } from "./<%~ config.fileNames.dataContracts %>"
|
|
16
|
+
<% } %>
|
|
17
|
+
|
|
18
|
+
export class <%= apiClassName %><SecurityDataType = unknown><% if (!config.singleHttpClient) { %> extends HttpClient<SecurityDataType> <% } %> {
|
|
19
|
+
<% if(config.singleHttpClient) { %>
|
|
20
|
+
http: HttpClient<SecurityDataType>;
|
|
21
|
+
|
|
22
|
+
constructor (http: HttpClient<SecurityDataType>) {
|
|
23
|
+
this.http = http;
|
|
24
|
+
}
|
|
25
|
+
<% } %>
|
|
26
|
+
|
|
27
|
+
<% for (const route of routes) { %>
|
|
28
|
+
<%~ includeFile('./procedure-call.ejs', { ...it, route }) %>
|
|
29
|
+
<% } %>
|
|
30
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const { data, utils } = it;
|
|
3
|
+
const { formatDescription, require, _ } = utils;
|
|
4
|
+
|
|
5
|
+
const stringify = (value) => _.isObject(value) ? JSON.stringify(value) : _.isString(value) ? `"${value}"` : value
|
|
6
|
+
|
|
7
|
+
const jsDocLines = _.compact([
|
|
8
|
+
data.title,
|
|
9
|
+
data.description && formatDescription(data.description),
|
|
10
|
+
!_.isUndefined(data.deprecated) && data.deprecated && '@deprecated',
|
|
11
|
+
!_.isUndefined(data.format) && `@format ${data.format}`,
|
|
12
|
+
!_.isUndefined(data.minimum) && `@min ${data.minimum}`,
|
|
13
|
+
!_.isUndefined(data.multipleOf) && `@multipleOf ${data.multipleOf}`,
|
|
14
|
+
!_.isUndefined(data.exclusiveMinimum) && `@exclusiveMin ${data.exclusiveMinimum}`,
|
|
15
|
+
!_.isUndefined(data.maximum) && `@max ${data.maximum}`,
|
|
16
|
+
!_.isUndefined(data.minLength) && `@minLength ${data.minLength}`,
|
|
17
|
+
!_.isUndefined(data.maxLength) && `@maxLength ${data.maxLength}`,
|
|
18
|
+
!_.isUndefined(data.exclusiveMaximum) && `@exclusiveMax ${data.exclusiveMaximum}`,
|
|
19
|
+
!_.isUndefined(data.maxItems) && `@maxItems ${data.maxItems}`,
|
|
20
|
+
!_.isUndefined(data.minItems) && `@minItems ${data.minItems}`,
|
|
21
|
+
!_.isUndefined(data.uniqueItems) && `@uniqueItems ${data.uniqueItems}`,
|
|
22
|
+
!_.isUndefined(data.default) && `@default ${stringify(data.default)}`,
|
|
23
|
+
!_.isUndefined(data.pattern) && `@pattern ${data.pattern}`,
|
|
24
|
+
!_.isUndefined(data.example) && `@example ${stringify(data.example)}`
|
|
25
|
+
]).join('\n').split('\n');
|
|
26
|
+
%>
|
|
27
|
+
<% if (jsDocLines.every(_.isEmpty)) { %>
|
|
28
|
+
<% } else if (jsDocLines.length === 1) { %>
|
|
29
|
+
/** <%~ jsDocLines[0] %> */
|
|
30
|
+
<% } else if (jsDocLines.length) { %>
|
|
31
|
+
/**
|
|
32
|
+
<% for (jsDocLine of jsDocLines) { %>
|
|
33
|
+
* <%~ jsDocLine %>
|
|
34
|
+
|
|
35
|
+
<% } %>
|
|
36
|
+
*/
|
|
37
|
+
<% } %>
|