@bitstack/ng-query-codegen-openapi 0.0.30
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 +77 -0
- package/lib/bin/cli.mjs +186 -0
- package/lib/bin/cli.mjs.map +1 -0
- package/lib/index.d.mts +191 -0
- package/lib/index.d.ts +191 -0
- package/lib/index.js +1392 -0
- package/lib/index.js.map +1 -0
- package/lib/index.mjs +1376 -0
- package/lib/index.mjs.map +1 -0
- package/package.json +91 -0
- package/src/bin/cli.ts +77 -0
- package/src/bin/utils.ts +85 -0
- package/src/generators/api-service-generator.ts +112 -0
- package/src/generators/cache-keys-generator.ts +43 -0
- package/src/generators/common-types-generator.ts +33 -0
- package/src/generators/component-schema-generator.ts +25 -0
- package/src/generators/do-not-modify-generator.ts +27 -0
- package/src/generators/index-generator.ts +11 -0
- package/src/generators/query-service-generator.ts +108 -0
- package/src/generators/types-generator.ts +285 -0
- package/src/generators/utils-generator.ts +33 -0
- package/src/index.ts +21 -0
- package/src/services/api-code-generator.ts +157 -0
- package/src/services/api-service-generator.ts +24 -0
- package/src/services/endpoint-info-extractor.ts +119 -0
- package/src/services/file-writer-service.ts +148 -0
- package/src/services/group-service.ts +84 -0
- package/src/services/openapi-parser-service.ts +72 -0
- package/src/services/openapi-service.ts +61 -0
- package/src/services/query-code-generator.ts +24 -0
- package/src/services/unified-code-generator.ts +353 -0
- package/src/types.ts +248 -0
- package/src/utils/capitalize.ts +3 -0
- package/src/utils/directory.ts +75 -0
- package/src/utils/downloadSchema.ts +33 -0
- package/src/utils/factory.ts +29 -0
- package/src/utils/getOperationDefinitions.ts +20 -0
- package/src/utils/getV3Doc.ts +24 -0
- package/src/utils/http.ts +86 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/isQuery.ts +16 -0
- package/src/utils/isValidUrl.ts +9 -0
- package/src/utils/messages.ts +7 -0
- package/src/utils/prettier.ts +51 -0
- package/src/utils/removeUndefined.ts +3 -0
package/lib/index.mjs
ADDED
|
@@ -0,0 +1,1376 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __esm = (fn, res) => function __init() {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
};
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// node_modules/tsup/assets/esm_shims.js
|
|
23
|
+
var init_esm_shims = __esm({
|
|
24
|
+
"node_modules/tsup/assets/esm_shims.js"() {
|
|
25
|
+
"use strict";
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// src/utils/http.ts
|
|
30
|
+
var http_exports = {};
|
|
31
|
+
__export(http_exports, {
|
|
32
|
+
argumentMatches: () => argumentMatches,
|
|
33
|
+
defaultIsDataResponse: () => defaultIsDataResponse,
|
|
34
|
+
getOperationName: () => getOperationName,
|
|
35
|
+
getOverrides: () => getOverrides,
|
|
36
|
+
getTags: () => getTags,
|
|
37
|
+
operationMatches: () => operationMatches
|
|
38
|
+
});
|
|
39
|
+
import {
|
|
40
|
+
getOperationName as _getOperationName
|
|
41
|
+
} from "oazapfts/generate";
|
|
42
|
+
function defaultIsDataResponse(code, includeDefault) {
|
|
43
|
+
if (includeDefault && code === "default") {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
const parsedCode = Number(code);
|
|
47
|
+
return !Number.isNaN(parsedCode) && parsedCode >= 200 && parsedCode < 300;
|
|
48
|
+
}
|
|
49
|
+
function getOperationName({ verb, path: path5 }) {
|
|
50
|
+
return _getOperationName(verb, path5, void 0);
|
|
51
|
+
}
|
|
52
|
+
function getTags({ verb, pathItem }) {
|
|
53
|
+
return verb ? pathItem[verb]?.tags || [] : [];
|
|
54
|
+
}
|
|
55
|
+
function patternMatches(pattern) {
|
|
56
|
+
const filters = Array.isArray(pattern) ? pattern : [pattern];
|
|
57
|
+
return function matcher(operationName) {
|
|
58
|
+
if (!pattern) return true;
|
|
59
|
+
return filters.some(
|
|
60
|
+
(filter) => typeof filter === "string" ? filter === operationName : filter?.test(operationName)
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function operationMatches(pattern) {
|
|
65
|
+
const checkMatch = typeof pattern === "function" ? pattern : patternMatches(pattern);
|
|
66
|
+
return function matcher(operationDefinition) {
|
|
67
|
+
if (!pattern) return true;
|
|
68
|
+
const operationName = getOperationName(operationDefinition);
|
|
69
|
+
return checkMatch(operationName, operationDefinition);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function argumentMatches(pattern) {
|
|
73
|
+
const checkMatch = typeof pattern === "function" ? pattern : patternMatches(pattern);
|
|
74
|
+
return function matcher(argumentDefinition) {
|
|
75
|
+
if (!pattern || argumentDefinition.in === "path") return true;
|
|
76
|
+
const argumentName = argumentDefinition.name;
|
|
77
|
+
return checkMatch(argumentName, argumentDefinition);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function getOverrides(operation, endpointOverrides) {
|
|
81
|
+
return endpointOverrides?.find((override) => operationMatches(override.pattern)(operation));
|
|
82
|
+
}
|
|
83
|
+
var init_http = __esm({
|
|
84
|
+
"src/utils/http.ts"() {
|
|
85
|
+
"use strict";
|
|
86
|
+
init_esm_shims();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// src/index.ts
|
|
91
|
+
init_esm_shims();
|
|
92
|
+
|
|
93
|
+
// src/services/unified-code-generator.ts
|
|
94
|
+
init_esm_shims();
|
|
95
|
+
import path4 from "node:path";
|
|
96
|
+
import ts3 from "typescript";
|
|
97
|
+
|
|
98
|
+
// src/services/openapi-service.ts
|
|
99
|
+
init_esm_shims();
|
|
100
|
+
|
|
101
|
+
// src/utils/capitalize.ts
|
|
102
|
+
init_esm_shims();
|
|
103
|
+
function capitalize(str) {
|
|
104
|
+
return str.replace(str[0], str[0].toUpperCase());
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/utils/downloadSchema.ts
|
|
108
|
+
init_esm_shims();
|
|
109
|
+
import fs from "node:fs";
|
|
110
|
+
import path from "node:path";
|
|
111
|
+
|
|
112
|
+
// src/utils/isValidUrl.ts
|
|
113
|
+
init_esm_shims();
|
|
114
|
+
function isValidUrl(string) {
|
|
115
|
+
try {
|
|
116
|
+
new URL(string);
|
|
117
|
+
} catch (_) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/utils/downloadSchema.ts
|
|
124
|
+
async function downloadSchemaFile(remoteFile, targetPath) {
|
|
125
|
+
if (!isValidUrl(remoteFile)) {
|
|
126
|
+
throw new Error(`remoteFile must be a valid URL: ${remoteFile}`);
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
const dir = path.dirname(targetPath);
|
|
130
|
+
if (!fs.existsSync(dir)) {
|
|
131
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
132
|
+
}
|
|
133
|
+
const response = await fetch(remoteFile);
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
throw new Error(`Failed to download schema from ${remoteFile}: ${response.statusText}`);
|
|
136
|
+
}
|
|
137
|
+
const content = await response.text();
|
|
138
|
+
await fs.promises.writeFile(targetPath, content, "utf-8");
|
|
139
|
+
console.log(`Schema downloaded from ${remoteFile} to ${targetPath}`);
|
|
140
|
+
return targetPath;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error(`Error downloading schema from ${remoteFile}:`, error);
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/utils/getOperationDefinitions.ts
|
|
148
|
+
init_esm_shims();
|
|
149
|
+
|
|
150
|
+
// src/types.ts
|
|
151
|
+
init_esm_shims();
|
|
152
|
+
var operationKeys = ["get", "put", "post", "delete", "options", "head", "patch", "trace"];
|
|
153
|
+
|
|
154
|
+
// src/utils/getOperationDefinitions.ts
|
|
155
|
+
function getOperationDefinitions(v3Doc) {
|
|
156
|
+
return Object.entries(v3Doc.paths).flatMap(
|
|
157
|
+
([path5, pathItem]) => !pathItem ? [] : Object.entries(pathItem).filter(
|
|
158
|
+
(arg) => operationKeys.includes(arg[0])
|
|
159
|
+
).map(([verb, operation]) => ({
|
|
160
|
+
path: path5,
|
|
161
|
+
verb,
|
|
162
|
+
pathItem,
|
|
163
|
+
operation
|
|
164
|
+
}))
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/utils/getV3Doc.ts
|
|
169
|
+
init_esm_shims();
|
|
170
|
+
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
171
|
+
import converter from "swagger2openapi";
|
|
172
|
+
async function getV3Doc(spec, httpResolverOptions) {
|
|
173
|
+
const doc = await SwaggerParser.bundle(spec, {
|
|
174
|
+
resolve: {
|
|
175
|
+
http: httpResolverOptions
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
const isOpenApiV3 = "openapi" in doc && doc.openapi.startsWith("3");
|
|
179
|
+
if (isOpenApiV3) {
|
|
180
|
+
return doc;
|
|
181
|
+
} else {
|
|
182
|
+
const result = await converter.convertObj(doc, {});
|
|
183
|
+
return result.openapi;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/utils/isQuery.ts
|
|
188
|
+
init_esm_shims();
|
|
189
|
+
function isQuery(verb, path5, overrides, queryMatch) {
|
|
190
|
+
if (queryMatch) {
|
|
191
|
+
return queryMatch(verb, path5);
|
|
192
|
+
}
|
|
193
|
+
if (overrides?.type) {
|
|
194
|
+
return overrides.type === "query";
|
|
195
|
+
}
|
|
196
|
+
return verb === "get";
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/services/openapi-service.ts
|
|
200
|
+
var OpenApiService = class {
|
|
201
|
+
docCache = {};
|
|
202
|
+
/**
|
|
203
|
+
* 獲取 OpenAPI 文檔
|
|
204
|
+
* @param schemaLocation - Schema 位置 (URL 或本地路徑)
|
|
205
|
+
* @param httpResolverOptions - HTTP 解析選項
|
|
206
|
+
*/
|
|
207
|
+
async getDocument(schemaLocation, httpResolverOptions) {
|
|
208
|
+
if (this.docCache[schemaLocation]) {
|
|
209
|
+
return this.docCache[schemaLocation];
|
|
210
|
+
}
|
|
211
|
+
const doc = await getV3Doc(schemaLocation, httpResolverOptions);
|
|
212
|
+
this.docCache[schemaLocation] = doc;
|
|
213
|
+
return doc;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* 下載遠程 Schema 文件
|
|
217
|
+
* @param remoteUrl - 遠程 URL
|
|
218
|
+
* @param localPath - 本地儲存路徑
|
|
219
|
+
*/
|
|
220
|
+
async downloadSchema(remoteUrl, localPath) {
|
|
221
|
+
return downloadSchemaFile(remoteUrl, localPath);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* 獲取所有 API 路徑
|
|
225
|
+
* @param doc - OpenAPI 文檔
|
|
226
|
+
*/
|
|
227
|
+
getPaths(doc) {
|
|
228
|
+
return Object.keys(doc.paths || {});
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* 清除快取
|
|
232
|
+
*/
|
|
233
|
+
clearCache() {
|
|
234
|
+
this.docCache = {};
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// src/services/group-service.ts
|
|
239
|
+
init_esm_shims();
|
|
240
|
+
import camelCase from "lodash.camelcase";
|
|
241
|
+
var GroupService = class {
|
|
242
|
+
/**
|
|
243
|
+
* 根據配置對路徑進行分組
|
|
244
|
+
* @param paths - API 路徑陣列
|
|
245
|
+
* @param config - 群組配置
|
|
246
|
+
*/
|
|
247
|
+
groupPaths(paths, config) {
|
|
248
|
+
const { groupKeyMatch, outputDir } = config;
|
|
249
|
+
const groupedPaths = paths.reduce((acc, path5) => {
|
|
250
|
+
const rawGroupKey = groupKeyMatch(path5);
|
|
251
|
+
const groupKey = rawGroupKey ? camelCase(rawGroupKey) : "_common";
|
|
252
|
+
if (!acc[groupKey]) {
|
|
253
|
+
acc[groupKey] = [];
|
|
254
|
+
}
|
|
255
|
+
acc[groupKey].push(path5);
|
|
256
|
+
return acc;
|
|
257
|
+
}, {});
|
|
258
|
+
const result = {};
|
|
259
|
+
for (const [groupKey, paths2] of Object.entries(groupedPaths)) {
|
|
260
|
+
result[groupKey] = {
|
|
261
|
+
groupKey,
|
|
262
|
+
paths: paths2,
|
|
263
|
+
outputPath: `${outputDir}/${groupKey}/query.service.ts`
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* 為特定群組建立篩選函數
|
|
270
|
+
* @param groupKey - 群組鍵
|
|
271
|
+
* @param config - 群組配置
|
|
272
|
+
*/
|
|
273
|
+
createGroupFilter(groupKey, config) {
|
|
274
|
+
return (operationName, operationDefinition) => {
|
|
275
|
+
const path5 = operationDefinition.path;
|
|
276
|
+
const pathGroupKey = camelCase(config.groupKeyMatch(path5) || "");
|
|
277
|
+
if (pathGroupKey !== groupKey && (pathGroupKey || "_common") !== groupKey) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
if (config.filterEndpoint) {
|
|
281
|
+
return config.filterEndpoint(operationName, path5, groupKey);
|
|
282
|
+
}
|
|
283
|
+
return true;
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// src/services/file-writer-service.ts
|
|
289
|
+
init_esm_shims();
|
|
290
|
+
import fs3 from "node:fs";
|
|
291
|
+
import path3 from "node:path";
|
|
292
|
+
|
|
293
|
+
// src/utils/directory.ts
|
|
294
|
+
init_esm_shims();
|
|
295
|
+
import path2 from "node:path";
|
|
296
|
+
import fs2 from "node:fs";
|
|
297
|
+
async function ensureDirectoryExists(filePath) {
|
|
298
|
+
const dirname = path2.dirname(filePath);
|
|
299
|
+
if (!fs2.existsSync(dirname)) {
|
|
300
|
+
await fs2.promises.mkdir(dirname, { recursive: true });
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/services/file-writer-service.ts
|
|
305
|
+
var FileWriterService = class {
|
|
306
|
+
/**
|
|
307
|
+
* 寫入單一檔案
|
|
308
|
+
* @param filePath - 檔案路徑
|
|
309
|
+
* @param content - 檔案內容
|
|
310
|
+
*/
|
|
311
|
+
async writeFile(filePath, content) {
|
|
312
|
+
try {
|
|
313
|
+
const resolvedPath = path3.resolve(process.cwd(), filePath);
|
|
314
|
+
await ensureDirectoryExists(resolvedPath);
|
|
315
|
+
fs3.writeFileSync(resolvedPath, content);
|
|
316
|
+
return {
|
|
317
|
+
path: resolvedPath,
|
|
318
|
+
success: true
|
|
319
|
+
};
|
|
320
|
+
} catch (error) {
|
|
321
|
+
return {
|
|
322
|
+
path: filePath,
|
|
323
|
+
success: false,
|
|
324
|
+
error
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* 批次寫入多個檔案
|
|
330
|
+
* @param files - 檔案路徑與內容的對應表
|
|
331
|
+
*/
|
|
332
|
+
async writeFiles(files) {
|
|
333
|
+
const results = [];
|
|
334
|
+
for (const [filePath, content] of Object.entries(files)) {
|
|
335
|
+
const result = await this.writeFile(filePath, content);
|
|
336
|
+
results.push(result);
|
|
337
|
+
}
|
|
338
|
+
return results;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* 為群組寫入標準檔案結構
|
|
342
|
+
* @param groupOutputDir - 群組輸出目錄
|
|
343
|
+
* @param files - 檔案內容
|
|
344
|
+
*/
|
|
345
|
+
async writeGroupFiles(groupOutputDir, files) {
|
|
346
|
+
const filesToWrite = {};
|
|
347
|
+
if (files.types) {
|
|
348
|
+
filesToWrite[path3.join(groupOutputDir, "types.ts")] = files.types;
|
|
349
|
+
}
|
|
350
|
+
if (files.apiService) {
|
|
351
|
+
filesToWrite[path3.join(groupOutputDir, "api.service.ts")] = files.apiService;
|
|
352
|
+
}
|
|
353
|
+
if (files.queryService) {
|
|
354
|
+
filesToWrite[path3.join(groupOutputDir, "query.service.ts")] = files.queryService;
|
|
355
|
+
}
|
|
356
|
+
if (files.index) {
|
|
357
|
+
filesToWrite[path3.join(groupOutputDir, "index.ts")] = files.index;
|
|
358
|
+
}
|
|
359
|
+
return this.writeFiles(filesToWrite);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* 寫入共享檔案
|
|
363
|
+
* @param outputDir - 輸出目錄
|
|
364
|
+
* @param sharedFiles - 共享檔案內容
|
|
365
|
+
*/
|
|
366
|
+
async writeSharedFiles(outputDir, sharedFiles) {
|
|
367
|
+
const filesToWrite = {};
|
|
368
|
+
if (sharedFiles.commonTypes) {
|
|
369
|
+
filesToWrite[path3.join(outputDir, "common-types.ts")] = sharedFiles.commonTypes;
|
|
370
|
+
}
|
|
371
|
+
if (sharedFiles.cacheKeys) {
|
|
372
|
+
filesToWrite[path3.join(outputDir, "cache-keys.ts")] = sharedFiles.cacheKeys;
|
|
373
|
+
}
|
|
374
|
+
if (sharedFiles.doNotModify) {
|
|
375
|
+
filesToWrite[path3.join(outputDir, "DO_NOT_MODIFY.md")] = sharedFiles.doNotModify;
|
|
376
|
+
}
|
|
377
|
+
if (sharedFiles.utils) {
|
|
378
|
+
filesToWrite[path3.join(outputDir, "utils.ts")] = sharedFiles.utils;
|
|
379
|
+
}
|
|
380
|
+
return this.writeFiles(filesToWrite);
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* 寫入共享檔案
|
|
384
|
+
* @param outputDir - 輸出目錄
|
|
385
|
+
* @param schema
|
|
386
|
+
*/
|
|
387
|
+
async writeSchemaFile(outputDir, schema) {
|
|
388
|
+
const filesToWrite = {};
|
|
389
|
+
filesToWrite[path3.join(outputDir, "schema.ts")] = schema;
|
|
390
|
+
return this.writeFiles(filesToWrite);
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// src/services/openapi-parser-service.ts
|
|
395
|
+
init_esm_shims();
|
|
396
|
+
import ApiGenerator from "oazapfts/generate";
|
|
397
|
+
var OpenApiParserService = class {
|
|
398
|
+
constructor(v3Doc, options) {
|
|
399
|
+
this.v3Doc = v3Doc;
|
|
400
|
+
this.apiGen = new ApiGenerator(v3Doc, {
|
|
401
|
+
unionUndefined: options.unionUndefined,
|
|
402
|
+
useEnumType: options.useEnumType,
|
|
403
|
+
mergeReadWriteOnly: options.mergeReadWriteOnly
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
apiGen;
|
|
407
|
+
/**
|
|
408
|
+
* 初始化 - 預處理組件
|
|
409
|
+
*/
|
|
410
|
+
initialize() {
|
|
411
|
+
if (this.apiGen.spec.components?.schemas) {
|
|
412
|
+
this.apiGen.preprocessComponents(this.apiGen.spec.components.schemas);
|
|
413
|
+
Object.keys(this.apiGen.spec.components.schemas).forEach((schemaName) => {
|
|
414
|
+
try {
|
|
415
|
+
this.apiGen.getRefAlias({ $ref: `#/components/schemas/${schemaName}` });
|
|
416
|
+
} catch (error) {
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* 獲取操作定義列表
|
|
423
|
+
* @param filterEndpoints - 端點過濾函數
|
|
424
|
+
*/
|
|
425
|
+
getOperationDefinitions(filterEndpoints) {
|
|
426
|
+
const { operationMatches: operationMatches2 } = (init_http(), __toCommonJS(http_exports));
|
|
427
|
+
return getOperationDefinitions(this.v3Doc).filter(operationMatches2(filterEndpoints));
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* 獲取 API 生成器實例
|
|
431
|
+
*/
|
|
432
|
+
getApiGenerator() {
|
|
433
|
+
return this.apiGen;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* 獲取 OpenAPI 文檔
|
|
437
|
+
*/
|
|
438
|
+
getDocument() {
|
|
439
|
+
return this.v3Doc;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* 獲取所有 schema 類型名稱
|
|
443
|
+
*/
|
|
444
|
+
getSchemaTypeNames() {
|
|
445
|
+
const schemeTypeNames = /* @__PURE__ */ new Set();
|
|
446
|
+
return schemeTypeNames;
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
// src/generators/cache-keys-generator.ts
|
|
451
|
+
init_esm_shims();
|
|
452
|
+
|
|
453
|
+
// src/generators/utils-generator.ts
|
|
454
|
+
init_esm_shims();
|
|
455
|
+
function generateUtilsFile() {
|
|
456
|
+
return `/* eslint-disable */
|
|
457
|
+
// [Warning] Generated automatically - do not edit manually
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Clear undefined in object
|
|
461
|
+
*/
|
|
462
|
+
export function withoutUndefined(obj?: Record<string, any>) {
|
|
463
|
+
if(typeof obj === 'undefined') return;
|
|
464
|
+
return Object.fromEntries(
|
|
465
|
+
Object.entries(obj).filter(([_, v]) => v !== undefined && v !== null)
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
`;
|
|
470
|
+
}
|
|
471
|
+
function toCamelCase(str) {
|
|
472
|
+
return str.toLowerCase().replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// src/generators/cache-keys-generator.ts
|
|
476
|
+
function generateCacheKeysFile(allEndpointInfos) {
|
|
477
|
+
const groupedKeys = allEndpointInfos.reduce((acc, info) => {
|
|
478
|
+
if (!acc[info.groupKey]) {
|
|
479
|
+
acc[info.groupKey] = [];
|
|
480
|
+
}
|
|
481
|
+
acc[info.groupKey].push({
|
|
482
|
+
operationName: info.operationName,
|
|
483
|
+
queryKeyName: info.queryKeyName
|
|
484
|
+
});
|
|
485
|
+
return acc;
|
|
486
|
+
}, {});
|
|
487
|
+
const enumEntries = Object.entries(groupedKeys).map(([groupKey, keys]) => {
|
|
488
|
+
const groupComment = ` // ${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)} related cache keys`;
|
|
489
|
+
const keyEntries = keys.map(
|
|
490
|
+
(key) => ` ${key.queryKeyName} = '${toCamelCase(key.queryKeyName)}',`
|
|
491
|
+
).join("\n");
|
|
492
|
+
return `${groupComment}
|
|
493
|
+
${keyEntries}`;
|
|
494
|
+
}).join("\n\n");
|
|
495
|
+
return `// [Warning] Generated automatically - do not edit manually
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Cache keys enum for all API queries
|
|
499
|
+
*/
|
|
500
|
+
export enum ECacheKeys {
|
|
501
|
+
${enumEntries}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
export default ECacheKeys;
|
|
505
|
+
`;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/generators/common-types-generator.ts
|
|
509
|
+
init_esm_shims();
|
|
510
|
+
function generateCommonTypesFile() {
|
|
511
|
+
return `/* eslint-disable */
|
|
512
|
+
// [Warning] Generated automatically - do not edit manually
|
|
513
|
+
|
|
514
|
+
export interface RequestOptions {
|
|
515
|
+
headers?: Record<string, string>;
|
|
516
|
+
observe?: 'body' | 'events' | 'response';
|
|
517
|
+
responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';
|
|
518
|
+
reportProgress?: boolean;
|
|
519
|
+
withCredentials?: boolean;
|
|
520
|
+
timeout?: number;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export interface QueryConfig {
|
|
524
|
+
refetchOnMountOrArgChange?: boolean|number,
|
|
525
|
+
keepUnusedDataFor?: number,
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
export type IRestFulEndpointsQueryReturn<TVariables> = TVariables extends void ?
|
|
529
|
+
void | {fetchOptions?: RequestOptions;config?: QueryConfig;}:
|
|
530
|
+
{
|
|
531
|
+
variables: TVariables;
|
|
532
|
+
fetchOptions?: RequestOptions;
|
|
533
|
+
config?: QueryConfig;
|
|
534
|
+
};
|
|
535
|
+
`;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// src/generators/component-schema-generator.ts
|
|
539
|
+
init_esm_shims();
|
|
540
|
+
import ts from "typescript";
|
|
541
|
+
function generateComponentSchemaFile(interfaces) {
|
|
542
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
543
|
+
const resultFile = ts.createSourceFile(
|
|
544
|
+
"component-schema.ts",
|
|
545
|
+
"",
|
|
546
|
+
ts.ScriptTarget.Latest,
|
|
547
|
+
false,
|
|
548
|
+
ts.ScriptKind.TS
|
|
549
|
+
);
|
|
550
|
+
return `/* eslint-disable */
|
|
551
|
+
// [Warning] Generated automatically - do not edit manually
|
|
552
|
+
|
|
553
|
+
${Object.values(interfaces).map((i) => printer.printNode(ts.EmitHint.Unspecified, i, resultFile)).join("\n")}
|
|
554
|
+
`;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// src/generators/do-not-modify-generator.ts
|
|
558
|
+
init_esm_shims();
|
|
559
|
+
function generateDoNotModifyFile() {
|
|
560
|
+
return `# \u8ACB\u52FF\u4FEE\u6539\u6B64\u8CC7\u6599\u593E
|
|
561
|
+
|
|
562
|
+
\u26A0\uFE0F **\u91CD\u8981\u63D0\u9192\uFF1A\u8ACB\u52FF\u4FEE\u6539\u6B64\u8CC7\u6599\u593E\u4E2D\u7684\u4EFB\u4F55\u6A94\u6848**
|
|
563
|
+
|
|
564
|
+
\u6B64\u8CC7\u6599\u593E\u4E2D\u7684\u6240\u6709\u6A94\u6848\u90FD\u662F\u900F\u904E\u7A0B\u5F0F\u78BC\u7522\u751F\u5668\u81EA\u52D5\u7522\u751F\u7684\u3002\u4EFB\u4F55\u624B\u52D5\u4FEE\u6539\u7684\u5167\u5BB9\u5728\u4E0B\u6B21\u91CD\u65B0\u7522\u751F\u6642\u90FD\u5C07\u6703\u88AB\u8986\u84CB\u3002
|
|
565
|
+
|
|
566
|
+
## \u5982\u4F55\u4FEE\u6539\u9019\u4E9B\u6A94\u6848\uFF1F
|
|
567
|
+
|
|
568
|
+
\u5982\u679C\u60A8\u9700\u8981\u4FEE\u6539\u9019\u4E9B\u6A94\u6848\u7684\u5167\u5BB9\uFF0C\u8ACB\uFF1A
|
|
569
|
+
|
|
570
|
+
1. \u4FEE\u6539\u76F8\u5C0D\u61C9\u7684\u8A2D\u5B9A\u6A94\u6848\u6216\u6A21\u677F
|
|
571
|
+
2. \u91CD\u65B0\u57F7\u884C\u7A0B\u5F0F\u78BC\u7522\u751F\u5668
|
|
572
|
+
3. \u8B93\u7522\u751F\u5668\u81EA\u52D5\u66F4\u65B0\u9019\u4E9B\u6A94\u6848
|
|
573
|
+
|
|
574
|
+
## \u7522\u751F\u5668\u76F8\u95DC\u8CC7\u8A0A
|
|
575
|
+
|
|
576
|
+
\u9019\u4E9B\u6A94\u6848\u662F\u7531 @bitstack/ng-query-codegen-openapi \u7522\u751F\u5668\u6240\u5EFA\u7ACB\u3002
|
|
577
|
+
|
|
578
|
+
\u5982\u6709\u7591\u554F\uFF0C\u8ACB\u53C3\u8003\u5C08\u6848\u6587\u4EF6\u6216\u806F\u7E6B\u958B\u767C\u5718\u968A\u3002
|
|
579
|
+
`;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// src/services/api-code-generator.ts
|
|
583
|
+
init_esm_shims();
|
|
584
|
+
import ts2 from "typescript";
|
|
585
|
+
|
|
586
|
+
// src/services/endpoint-info-extractor.ts
|
|
587
|
+
init_esm_shims();
|
|
588
|
+
init_http();
|
|
589
|
+
import { supportDeepObjects } from "oazapfts/generate";
|
|
590
|
+
var EndpointInfoExtractor = class {
|
|
591
|
+
constructor(options) {
|
|
592
|
+
this.options = options;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* 從操作定義列表提取端點資訊
|
|
596
|
+
* @param operationDefinitions - 操作定義列表
|
|
597
|
+
*/
|
|
598
|
+
extractEndpointInfos(operationDefinitions) {
|
|
599
|
+
return operationDefinitions.map((operationDefinition) => {
|
|
600
|
+
return this.extractSingleEndpointInfo(operationDefinition);
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* 從單一操作定義提取端點資訊
|
|
605
|
+
* @param operationDefinition - 操作定義
|
|
606
|
+
*/
|
|
607
|
+
extractSingleEndpointInfo(operationDefinition) {
|
|
608
|
+
const { verb, path: path5, operation } = operationDefinition;
|
|
609
|
+
const { operationNameSuffix = "", argSuffix = "Req", responseSuffix = "Res", queryMatch, endpointOverrides } = this.options;
|
|
610
|
+
const operationName = getOperationName({ verb, path: path5 });
|
|
611
|
+
const finalOperationName = operationNameSuffix ? capitalize(operationName + operationNameSuffix) : operationName;
|
|
612
|
+
const argTypeName = capitalize(operationName + operationNameSuffix + argSuffix);
|
|
613
|
+
const responseTypeName = capitalize(operationName + operationNameSuffix + responseSuffix);
|
|
614
|
+
const isQuery2 = isQuery(verb, path5, getOverrides(operationDefinition, endpointOverrides), queryMatch);
|
|
615
|
+
const queryKeyName = `${operationName.replace(/([A-Z])/g, "_$1").toUpperCase()}`;
|
|
616
|
+
const summary = operation.summary || `${verb.toUpperCase()} ${path5}`;
|
|
617
|
+
const { queryParams, pathParams, isVoidArg } = this.extractParameters(operationDefinition);
|
|
618
|
+
return {
|
|
619
|
+
operationName: finalOperationName,
|
|
620
|
+
argTypeName,
|
|
621
|
+
responseTypeName,
|
|
622
|
+
isQuery: isQuery2,
|
|
623
|
+
verb: verb.toUpperCase(),
|
|
624
|
+
path: path5,
|
|
625
|
+
queryKeyName,
|
|
626
|
+
queryParams,
|
|
627
|
+
pathParams,
|
|
628
|
+
isVoidArg,
|
|
629
|
+
summary
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* 提取操作的參數資訊
|
|
634
|
+
* @param operationDefinition - 操作定義
|
|
635
|
+
*/
|
|
636
|
+
extractParameters(operationDefinition) {
|
|
637
|
+
const { operation, pathItem } = operationDefinition;
|
|
638
|
+
const operationParameters = this.resolveArray(operation.parameters);
|
|
639
|
+
const pathItemParameters = this.resolveArray(pathItem.parameters).filter((pp) => !operationParameters.some((op) => op.name === pp.name && op.in === pp.in));
|
|
640
|
+
const allParameters = supportDeepObjects([...pathItemParameters, ...operationParameters]).filter((param) => param.in !== "header");
|
|
641
|
+
const queryParams = allParameters.filter((param) => param.in === "query");
|
|
642
|
+
const pathParams = allParameters.filter((param) => param.in === "path");
|
|
643
|
+
const isVoidArg = queryParams.length === 0 && pathParams.length === 0 && !operation.requestBody;
|
|
644
|
+
return {
|
|
645
|
+
queryParams,
|
|
646
|
+
pathParams,
|
|
647
|
+
isVoidArg
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* 解析參數陣列 (模擬 apiGen.resolveArray)
|
|
652
|
+
*/
|
|
653
|
+
resolveArray(parameters) {
|
|
654
|
+
if (!parameters) return [];
|
|
655
|
+
return Array.isArray(parameters) ? parameters : [parameters];
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
// src/generators/types-generator.ts
|
|
660
|
+
init_esm_shims();
|
|
661
|
+
function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationDefinitions) {
|
|
662
|
+
let importStatement = `/* eslint-disable */
|
|
663
|
+
// [Warning] Generated automatically - do not edit manually
|
|
664
|
+
|
|
665
|
+
`;
|
|
666
|
+
const hasSchemaTypes = schemaInterfaces && Object.keys(schemaInterfaces).length > 0;
|
|
667
|
+
if (hasSchemaTypes) {
|
|
668
|
+
importStatement += `import * as Schema from "../schema";
|
|
669
|
+
`;
|
|
670
|
+
}
|
|
671
|
+
importStatement += "\n";
|
|
672
|
+
const typeDefinitions = [];
|
|
673
|
+
const endpointTypes = [];
|
|
674
|
+
endpointInfos.forEach((endpoint) => {
|
|
675
|
+
const reqTypeName = endpoint.argTypeName;
|
|
676
|
+
const resTypeName = endpoint.responseTypeName;
|
|
677
|
+
if (reqTypeName) {
|
|
678
|
+
const requestTypeContent = generateRequestTypeContent(endpoint, operationDefinitions);
|
|
679
|
+
if (requestTypeContent.trim() === "" || requestTypeContent.includes("TODO") || requestTypeContent.includes("[key: string]: any")) {
|
|
680
|
+
endpointTypes.push(
|
|
681
|
+
`export type ${reqTypeName} = void;`,
|
|
682
|
+
``
|
|
683
|
+
);
|
|
684
|
+
} else {
|
|
685
|
+
endpointTypes.push(
|
|
686
|
+
`export type ${reqTypeName} = {`,
|
|
687
|
+
requestTypeContent,
|
|
688
|
+
`};`,
|
|
689
|
+
``
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
if (resTypeName) {
|
|
694
|
+
const responseTypeContent = generateResponseTypeContent(endpoint, operationDefinitions);
|
|
695
|
+
if (responseTypeContent.trim() === "" || responseTypeContent.includes("TODO") || responseTypeContent.includes("[key: string]: any")) {
|
|
696
|
+
endpointTypes.push(
|
|
697
|
+
`export type ${resTypeName} = void;`,
|
|
698
|
+
``
|
|
699
|
+
);
|
|
700
|
+
} else {
|
|
701
|
+
endpointTypes.push(
|
|
702
|
+
`export type ${resTypeName} = {`,
|
|
703
|
+
responseTypeContent,
|
|
704
|
+
`};`,
|
|
705
|
+
``
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
if (endpointTypes.length > 0) {
|
|
711
|
+
typeDefinitions.push(endpointTypes.join("\n"));
|
|
712
|
+
}
|
|
713
|
+
if (typeDefinitions.length === 0) {
|
|
714
|
+
typeDefinitions.push(
|
|
715
|
+
`// \u6B64\u6A94\u6848\u7528\u65BC\u5B9A\u7FA9 API \u76F8\u95DC\u7684\u985E\u578B`,
|
|
716
|
+
`// \u985E\u578B\u5B9A\u7FA9\u6703\u6839\u64DA OpenAPI Schema \u81EA\u52D5\u751F\u6210`,
|
|
717
|
+
``
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
return importStatement + typeDefinitions.join("\n\n");
|
|
721
|
+
}
|
|
722
|
+
function generateRequestTypeContent(endpoint, operationDefinitions) {
|
|
723
|
+
const properties = [];
|
|
724
|
+
if (endpoint.queryParams && endpoint.queryParams.length > 0) {
|
|
725
|
+
endpoint.queryParams.forEach((param) => {
|
|
726
|
+
const optional = param.required ? "" : "?";
|
|
727
|
+
const paramType = getTypeFromParameter(param);
|
|
728
|
+
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
if (endpoint.pathParams && endpoint.pathParams.length > 0) {
|
|
732
|
+
endpoint.pathParams.forEach((param) => {
|
|
733
|
+
const optional = param.required ? "" : "?";
|
|
734
|
+
const paramType = getTypeFromParameter(param);
|
|
735
|
+
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
const operationDef = operationDefinitions?.find((op) => {
|
|
739
|
+
return op.operation?.operationId === endpoint.operationName || op.operation?.operationId === endpoint.operationName.toLowerCase() || // 也嘗試匹配 verb + path 組合
|
|
740
|
+
op.verb === endpoint.verb.toLowerCase() && op.path === endpoint.path;
|
|
741
|
+
});
|
|
742
|
+
if (operationDef?.operation?.requestBody) {
|
|
743
|
+
const requestBody = operationDef.operation.requestBody;
|
|
744
|
+
const content = requestBody.content;
|
|
745
|
+
const jsonContent = content["application/json"];
|
|
746
|
+
const formContent = content["multipart/form-data"] || content["application/x-www-form-urlencoded"];
|
|
747
|
+
if (jsonContent?.schema) {
|
|
748
|
+
const bodyType = getTypeFromSchema(jsonContent.schema);
|
|
749
|
+
properties.push(` body: ${bodyType};`);
|
|
750
|
+
} else if (formContent?.schema) {
|
|
751
|
+
const bodyType = getTypeFromSchema(formContent.schema);
|
|
752
|
+
properties.push(` body: ${bodyType};`);
|
|
753
|
+
} else {
|
|
754
|
+
properties.push(` body?: any; // Request body from OpenAPI`);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (properties.length === 0) {
|
|
758
|
+
return "";
|
|
759
|
+
}
|
|
760
|
+
return properties.join("\n");
|
|
761
|
+
}
|
|
762
|
+
function generateResponseTypeContent(endpoint, operationDefinitions) {
|
|
763
|
+
const properties = [];
|
|
764
|
+
const operationDef = operationDefinitions?.find((op) => {
|
|
765
|
+
return op.operation?.operationId === endpoint.operationName || op.operation?.operationId === endpoint.operationName.toLowerCase() || // 也嘗試匹配 verb + path 組合
|
|
766
|
+
op.verb === endpoint.verb.toLowerCase() && op.path === endpoint.path;
|
|
767
|
+
});
|
|
768
|
+
if (operationDef?.operation?.responses) {
|
|
769
|
+
const successResponse = operationDef.operation.responses["200"] || operationDef.operation.responses["201"];
|
|
770
|
+
if (successResponse?.content) {
|
|
771
|
+
const jsonContent = successResponse.content["application/json"];
|
|
772
|
+
if (jsonContent?.schema) {
|
|
773
|
+
const responseProps = parseSchemaProperties(jsonContent.schema);
|
|
774
|
+
properties.push(...responseProps);
|
|
775
|
+
} else {
|
|
776
|
+
properties.push(` // Success response from OpenAPI`);
|
|
777
|
+
properties.push(` data?: any;`);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
if (properties.length === 0) {
|
|
782
|
+
return "";
|
|
783
|
+
}
|
|
784
|
+
return properties.join("\n");
|
|
785
|
+
}
|
|
786
|
+
function parseSchemaProperties(schema) {
|
|
787
|
+
const properties = [];
|
|
788
|
+
if (schema.type === "object" && schema.properties) {
|
|
789
|
+
const required = schema.required || [];
|
|
790
|
+
Object.entries(schema.properties).forEach(([propName, propSchema]) => {
|
|
791
|
+
const isRequired = required.includes(propName);
|
|
792
|
+
const optional = isRequired ? "" : "?";
|
|
793
|
+
const propType = getTypeFromSchema(propSchema);
|
|
794
|
+
const description = propSchema.description ? ` // ${propSchema.description}` : "";
|
|
795
|
+
properties.push(` ${propName}${optional}: ${propType};${description}`);
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
return properties;
|
|
799
|
+
}
|
|
800
|
+
function getTypeFromSchema(schema) {
|
|
801
|
+
if (!schema) return "any";
|
|
802
|
+
if (schema.$ref) {
|
|
803
|
+
const refPath = schema.$ref;
|
|
804
|
+
if (refPath.startsWith("#/components/schemas/")) {
|
|
805
|
+
const typeName = refPath.replace("#/components/schemas/", "");
|
|
806
|
+
return `Schema.${typeName}`;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
switch (schema.type) {
|
|
810
|
+
case "string":
|
|
811
|
+
if (schema.enum) {
|
|
812
|
+
return schema.enum.map((val) => `"${val}"`).join(" | ");
|
|
813
|
+
}
|
|
814
|
+
return "string";
|
|
815
|
+
case "number":
|
|
816
|
+
case "integer":
|
|
817
|
+
return "number";
|
|
818
|
+
case "boolean":
|
|
819
|
+
return "boolean";
|
|
820
|
+
case "array":
|
|
821
|
+
const itemType = schema.items ? getTypeFromSchema(schema.items) : "any";
|
|
822
|
+
return `${itemType}[]`;
|
|
823
|
+
case "object":
|
|
824
|
+
if (schema.properties) {
|
|
825
|
+
const props = Object.entries(schema.properties).map(([key, propSchema]) => {
|
|
826
|
+
const required = schema.required || [];
|
|
827
|
+
const optional = required.includes(key) ? "" : "?";
|
|
828
|
+
const type = getTypeFromSchema(propSchema);
|
|
829
|
+
return `${key}${optional}: ${type}`;
|
|
830
|
+
}).join("; ");
|
|
831
|
+
return `{ ${props} }`;
|
|
832
|
+
}
|
|
833
|
+
return "any";
|
|
834
|
+
default:
|
|
835
|
+
return "any";
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
function getTypeFromParameter(param) {
|
|
839
|
+
if (!param.schema) return "any";
|
|
840
|
+
return getTypeFromSchema(param.schema);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// src/generators/index-generator.ts
|
|
844
|
+
init_esm_shims();
|
|
845
|
+
function generateIndexFile(groupKey, options) {
|
|
846
|
+
const { groupKey: optionsGroupKey } = options;
|
|
847
|
+
return `export * from './types';
|
|
848
|
+
export * from './api.service';
|
|
849
|
+
export * from './query.service';
|
|
850
|
+
`;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// src/services/query-code-generator.ts
|
|
854
|
+
init_esm_shims();
|
|
855
|
+
|
|
856
|
+
// src/generators/query-service-generator.ts
|
|
857
|
+
init_esm_shims();
|
|
858
|
+
function generateQueryServiceFile(endpointInfos, options) {
|
|
859
|
+
const { groupKey, refetchOnMountOrArgChange = 60 } = options;
|
|
860
|
+
const queryServiceName = groupKey ? `${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)}QueryService` : "QueryService";
|
|
861
|
+
const apiServiceName = groupKey ? `${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)}ApiService` : "ApiService";
|
|
862
|
+
const queryMethods = endpointInfos.filter((info) => info.isQuery).map((info) => `
|
|
863
|
+
/**
|
|
864
|
+
* ${info.summary}
|
|
865
|
+
*/
|
|
866
|
+
${info.operationName}Query(${info.argTypeName !== "VoidApiArg" ? `args: IRestFulEndpointsQueryReturn<${info.argTypeName}>` : ""}): Observable<QueryState<${info.responseTypeName}>> {
|
|
867
|
+
return this.ntkQuery.query<${info.responseTypeName}, ${info.argTypeName !== "VoidApiArg" ? `IRestFulEndpointsQueryReturn<${info.argTypeName}>` : "void"}>({
|
|
868
|
+
queryKey: [ECacheKeys.${info.queryKeyName}${info.argTypeName !== "VoidApiArg" ? ", args.variables" : ""}],
|
|
869
|
+
queryFn: () => {
|
|
870
|
+
return this.apiService.${info.operationName}(${info.argTypeName !== "VoidApiArg" ? "args" : ""});
|
|
871
|
+
},
|
|
872
|
+
fetchOptions: args?.fetchOptions,
|
|
873
|
+
config: args?.config,
|
|
874
|
+
})${info.argTypeName !== "VoidApiArg" ? "(args)" : "()"};
|
|
875
|
+
}`).join("");
|
|
876
|
+
const mutationMethods = endpointInfos.filter((info) => !info.isQuery).map((info) => `
|
|
877
|
+
/**
|
|
878
|
+
* ${info.summary}
|
|
879
|
+
*/
|
|
880
|
+
${info.operationName}Mutation(): MutationResponse<${info.responseTypeName}, {
|
|
881
|
+
variables: ${info.argTypeName !== "VoidApiArg" ? info.argTypeName : "void"};
|
|
882
|
+
fetchOptions?: RequestOptions;
|
|
883
|
+
}, HttpErrorResponse> {
|
|
884
|
+
return this.ntkQuery.mutation<${info.responseTypeName}, ${info.argTypeName !== "VoidApiArg" ? `IRestFulEndpointsQueryReturn<${info.argTypeName}>` : "void"}, HttpErrorResponse>({
|
|
885
|
+
endpointName: '${info.operationName}',
|
|
886
|
+
mutationFn: (${info.argTypeName !== "VoidApiArg" ? "args" : ""}) => {
|
|
887
|
+
return this.apiService.${info.operationName}(${info.argTypeName !== "VoidApiArg" ? "args" : ""});
|
|
888
|
+
},
|
|
889
|
+
});
|
|
890
|
+
}`).join("");
|
|
891
|
+
const lazyQueryMethods = endpointInfos.filter((info) => info.isQuery).map((info) => `
|
|
892
|
+
/**
|
|
893
|
+
* ${info.summary}
|
|
894
|
+
*/
|
|
895
|
+
${info.operationName}LazyQuery(): {
|
|
896
|
+
trigger: (${info.argTypeName !== "VoidApiArg" ? `args: IRestFulEndpointsQueryReturn<${info.argTypeName}>, ` : ""}options?: { skipCache?: boolean }) => Observable<${info.responseTypeName}>
|
|
897
|
+
} {
|
|
898
|
+
return {
|
|
899
|
+
trigger: (${info.argTypeName !== "VoidApiArg" ? "args, " : ""}options = {}) => {
|
|
900
|
+
const { skipCache = true } = options;
|
|
901
|
+
if (!skipCache) {
|
|
902
|
+
const cachedResult = this.ntkQuery.getQueryCache<${info.responseTypeName}>([ECacheKeys.${info.queryKeyName}${info.argTypeName !== "VoidApiArg" ? ", args.variables" : ""}]);
|
|
903
|
+
if (cachedResult) {
|
|
904
|
+
return cachedResult;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
return this.apiService.${info.operationName}(${info.argTypeName !== "VoidApiArg" ? "args" : ""});
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
}`).join("");
|
|
911
|
+
return `/* eslint-disable */
|
|
912
|
+
// [Warning] Generated automatically - do not edit manually
|
|
913
|
+
|
|
914
|
+
import {Injectable, inject} from '@angular/core';
|
|
915
|
+
import {Observable} from 'rxjs';
|
|
916
|
+
import {HttpErrorResponse} from '@angular/common/http';
|
|
917
|
+
import {NtkQueryService, MutationState, QueryState, MutationResponse} from '@core/ntk-query';
|
|
918
|
+
import {ECacheKeys} from '../cache-keys';
|
|
919
|
+
import {${apiServiceName}} from './api.service';
|
|
920
|
+
import {IRestFulEndpointsQueryReturn, RequestOptions} from '../common-types';
|
|
921
|
+
import {${endpointInfos.map((info) => ` ${info.argTypeName}, ${info.responseTypeName}`).join(",")}} from './types';
|
|
922
|
+
|
|
923
|
+
@Injectable({
|
|
924
|
+
providedIn: 'root',
|
|
925
|
+
})
|
|
926
|
+
export class ${queryServiceName} {
|
|
927
|
+
private apiService = inject(${apiServiceName});
|
|
928
|
+
private ntkQuery = inject(NtkQueryService);
|
|
929
|
+
${queryMethods}${mutationMethods}${lazyQueryMethods}
|
|
930
|
+
}
|
|
931
|
+
`;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// src/services/query-code-generator.ts
|
|
935
|
+
var QueryCodeGenerator = class {
|
|
936
|
+
constructor(options) {
|
|
937
|
+
this.options = options;
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* 生成 Query Service 檔案內容
|
|
941
|
+
*/
|
|
942
|
+
generateQueryService(endpointInfos) {
|
|
943
|
+
const generatorOptions = {
|
|
944
|
+
...this.options,
|
|
945
|
+
apiConfiguration: this.options.apiConfiguration || {
|
|
946
|
+
file: "@/store/webapi",
|
|
947
|
+
importName: "WebApiConfiguration"
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
return generateQueryServiceFile(endpointInfos, generatorOptions);
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
// src/services/api-service-generator.ts
|
|
955
|
+
init_esm_shims();
|
|
956
|
+
|
|
957
|
+
// src/generators/api-service-generator.ts
|
|
958
|
+
init_esm_shims();
|
|
959
|
+
function generateApiServiceFile(endpointInfos, options) {
|
|
960
|
+
const { apiConfiguration, httpClient, groupKey } = options;
|
|
961
|
+
const apiServiceClassName = groupKey ? `${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)}ApiService` : "ApiService";
|
|
962
|
+
return `/* eslint-disable */
|
|
963
|
+
// [Warning] Generated automatically - do not edit manually
|
|
964
|
+
|
|
965
|
+
import { ${httpClient.importName} } from '${httpClient.file}';
|
|
966
|
+
import { Injectable, inject } from '@angular/core';
|
|
967
|
+
import { Observable } from 'rxjs';
|
|
968
|
+
import { ${apiConfiguration.importName} } from '${apiConfiguration.file}';
|
|
969
|
+
import { RequestOptions, IRestFulEndpointsQueryReturn } from '../common-types';
|
|
970
|
+
import { withoutUndefined } from '../utils';
|
|
971
|
+
import {${endpointInfos.map((info) => ` ${info.argTypeName}, ${info.responseTypeName}`).join(",")} } from './types';
|
|
972
|
+
|
|
973
|
+
@Injectable({
|
|
974
|
+
providedIn: 'root',
|
|
975
|
+
})
|
|
976
|
+
export class ${apiServiceClassName} {
|
|
977
|
+
private config = inject(${apiConfiguration.importName});
|
|
978
|
+
private http = inject(${httpClient.importName});
|
|
979
|
+
|
|
980
|
+
${endpointInfos.map((info) => {
|
|
981
|
+
const isGet = info.verb.toUpperCase() === "GET";
|
|
982
|
+
const hasArgs = info.argTypeName !== "VoidApiArg";
|
|
983
|
+
const generateUrlTemplate = (path5) => {
|
|
984
|
+
const hasPathParams = path5.includes("{");
|
|
985
|
+
if (hasPathParams && hasArgs) {
|
|
986
|
+
const urlTemplate = path5.replace(/\{([^}]+)\}/g, "${args.variables.$1}");
|
|
987
|
+
return `\`\${this.config.rootUrl}${urlTemplate}\``;
|
|
988
|
+
} else {
|
|
989
|
+
return `\`\${this.config.rootUrl}${path5}\``;
|
|
990
|
+
}
|
|
991
|
+
};
|
|
992
|
+
const hasQueryParams = info.queryParams.length > 0;
|
|
993
|
+
const hasBody = !isGet && hasArgs && !info.isVoidArg;
|
|
994
|
+
const generateRequestOptions = () => {
|
|
995
|
+
const options2 = [
|
|
996
|
+
"...args.fetchOptions"
|
|
997
|
+
];
|
|
998
|
+
if (hasBody || !isGet) {
|
|
999
|
+
options2.push(`headers: { 'Content-Type': 'application/json', ...args.fetchOptions?.headers }`);
|
|
1000
|
+
}
|
|
1001
|
+
if (hasQueryParams && hasArgs) {
|
|
1002
|
+
options2.push(generateQueryParams(info.queryParams));
|
|
1003
|
+
}
|
|
1004
|
+
if (hasBody) {
|
|
1005
|
+
options2.push("body: args.variables.body");
|
|
1006
|
+
}
|
|
1007
|
+
return options2.length > 0 ? `{ ${options2.join(", ")} }` : "{}";
|
|
1008
|
+
};
|
|
1009
|
+
return `
|
|
1010
|
+
/**
|
|
1011
|
+
* ${info.summary}
|
|
1012
|
+
*/
|
|
1013
|
+
${info.operationName}(
|
|
1014
|
+
${hasArgs ? `args: IRestFulEndpointsQueryReturn<${info.argTypeName}>, ` : ""}
|
|
1015
|
+
): Observable<${info.responseTypeName}> {
|
|
1016
|
+
const url = ${generateUrlTemplate(info.path)};
|
|
1017
|
+
return this.http.request('${info.verb.toLowerCase()}', url, ${generateRequestOptions()});
|
|
1018
|
+
}`;
|
|
1019
|
+
}).join("")}
|
|
1020
|
+
}
|
|
1021
|
+
`;
|
|
1022
|
+
}
|
|
1023
|
+
function generateQueryParams(queryParams) {
|
|
1024
|
+
const paramEntries = queryParams.map(
|
|
1025
|
+
(param) => `${param.name}: args.variables.${param.name}`
|
|
1026
|
+
).join(", ");
|
|
1027
|
+
return `params: withoutUndefined({ ${paramEntries} })`;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// src/services/api-service-generator.ts
|
|
1031
|
+
var ApiServiceGenerator = class {
|
|
1032
|
+
constructor(options) {
|
|
1033
|
+
this.options = options;
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* 生成 API Service 檔案內容
|
|
1037
|
+
*/
|
|
1038
|
+
generateApiService(endpointInfos) {
|
|
1039
|
+
const generatorOptions = {
|
|
1040
|
+
...this.options,
|
|
1041
|
+
apiConfiguration: this.options.apiConfiguration || {
|
|
1042
|
+
file: "@/store/webapi",
|
|
1043
|
+
importName: "WebApiConfiguration"
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
return generateApiServiceFile(endpointInfos, generatorOptions);
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1049
|
+
|
|
1050
|
+
// src/services/api-code-generator.ts
|
|
1051
|
+
var ApiCodeGenerator = class {
|
|
1052
|
+
constructor(parserService, options) {
|
|
1053
|
+
this.parserService = parserService;
|
|
1054
|
+
this.options = options;
|
|
1055
|
+
this.infoExtractor = new EndpointInfoExtractor(options);
|
|
1056
|
+
this.queryGenerator = new QueryCodeGenerator(options);
|
|
1057
|
+
this.apiServiceGenerator = new ApiServiceGenerator(options);
|
|
1058
|
+
}
|
|
1059
|
+
infoExtractor;
|
|
1060
|
+
queryGenerator;
|
|
1061
|
+
apiServiceGenerator;
|
|
1062
|
+
/**
|
|
1063
|
+
* 生成完整的 API 程式碼
|
|
1064
|
+
*/
|
|
1065
|
+
async generate() {
|
|
1066
|
+
const operationDefinitions = this.parserService.getOperationDefinitions(this.options.filterEndpoints);
|
|
1067
|
+
const endpointInfos = this.infoExtractor.extractEndpointInfos(operationDefinitions);
|
|
1068
|
+
const typesContent = this.generateTypes(endpointInfos);
|
|
1069
|
+
const apiServiceContent = this.generateApiService(endpointInfos);
|
|
1070
|
+
const queryServiceContent = this.generateQueryService(endpointInfos);
|
|
1071
|
+
const indexContent = this.generateIndex();
|
|
1072
|
+
const allEndpointCacheKeys = endpointInfos.filter((info) => info.isQuery).map((info) => ({
|
|
1073
|
+
operationName: info.operationName,
|
|
1074
|
+
queryKeyName: info.queryKeyName,
|
|
1075
|
+
groupKey: this.options.groupKey || "_common"
|
|
1076
|
+
}));
|
|
1077
|
+
const operationNames = endpointInfos.map((info) => info.operationName);
|
|
1078
|
+
return {
|
|
1079
|
+
operationNames,
|
|
1080
|
+
files: {
|
|
1081
|
+
types: typesContent,
|
|
1082
|
+
apiService: apiServiceContent,
|
|
1083
|
+
queryService: queryServiceContent,
|
|
1084
|
+
index: indexContent,
|
|
1085
|
+
allEndpointCacheKeys
|
|
1086
|
+
}
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* 生成 Types 檔案內容
|
|
1091
|
+
*/
|
|
1092
|
+
generateTypes(endpointInfos) {
|
|
1093
|
+
const generatorOptions = {
|
|
1094
|
+
...this.options,
|
|
1095
|
+
apiConfiguration: this.options.apiConfiguration || {
|
|
1096
|
+
file: "@/store/webapi",
|
|
1097
|
+
importName: "WebApiConfiguration"
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
const apiGen = this.parserService.getApiGenerator();
|
|
1101
|
+
const schemaInterfaces = apiGen.aliases.reduce((curr, alias) => {
|
|
1102
|
+
if (ts2.isInterfaceDeclaration(alias) || ts2.isTypeAliasDeclaration(alias)) {
|
|
1103
|
+
const name = alias.name.text;
|
|
1104
|
+
return {
|
|
1105
|
+
...curr,
|
|
1106
|
+
[name]: alias
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
return curr;
|
|
1110
|
+
}, {});
|
|
1111
|
+
const operationDefinitions = this.parserService.getOperationDefinitions(this.options.filterEndpoints);
|
|
1112
|
+
return generateTypesFile(endpointInfos, generatorOptions, schemaInterfaces, operationDefinitions);
|
|
1113
|
+
}
|
|
1114
|
+
/**
|
|
1115
|
+
* 生成 API Service 檔案內容
|
|
1116
|
+
*/
|
|
1117
|
+
generateApiService(endpointInfos) {
|
|
1118
|
+
return this.apiServiceGenerator.generateApiService(endpointInfos);
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* 生成 Query Service 檔案內容
|
|
1122
|
+
*/
|
|
1123
|
+
generateQueryService(endpointInfos) {
|
|
1124
|
+
return this.queryGenerator.generateQueryService(endpointInfos);
|
|
1125
|
+
}
|
|
1126
|
+
/**
|
|
1127
|
+
* 生成 Index 檔案內容
|
|
1128
|
+
*/
|
|
1129
|
+
generateIndex() {
|
|
1130
|
+
const generatorOptions = {
|
|
1131
|
+
...this.options,
|
|
1132
|
+
apiConfiguration: this.options.apiConfiguration || {
|
|
1133
|
+
file: "@/store/webapi",
|
|
1134
|
+
importName: "WebApiConfiguration"
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
return generateIndexFile(this.options.groupKey || "", generatorOptions);
|
|
1138
|
+
}
|
|
1139
|
+
// /**
|
|
1140
|
+
// * 獲取已解析的 parser service(供外部使用)
|
|
1141
|
+
// */
|
|
1142
|
+
// getParserService(): OpenApiParserService {
|
|
1143
|
+
// return this.parserService;
|
|
1144
|
+
// }
|
|
1145
|
+
//
|
|
1146
|
+
// /**
|
|
1147
|
+
// * 獲取端點資訊提取器(供外部使用)
|
|
1148
|
+
// */
|
|
1149
|
+
// getInfoExtractor(): EndpointInfoExtractor {
|
|
1150
|
+
// return this.infoExtractor;
|
|
1151
|
+
// }
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
// src/services/unified-code-generator.ts
|
|
1155
|
+
var UnifiedCodeGenerator = class {
|
|
1156
|
+
_options;
|
|
1157
|
+
openApiService = new OpenApiService();
|
|
1158
|
+
groupService = new GroupService();
|
|
1159
|
+
fileWriterService = new FileWriterService();
|
|
1160
|
+
// 內部狀態存儲
|
|
1161
|
+
openApiDoc = null;
|
|
1162
|
+
parserService = null;
|
|
1163
|
+
schemaInterfaces = {};
|
|
1164
|
+
allEndpointCacheKeys = [];
|
|
1165
|
+
actualSchemaFile = "";
|
|
1166
|
+
// 生成內容存儲
|
|
1167
|
+
generatedContent = {
|
|
1168
|
+
groups: [],
|
|
1169
|
+
cacheKeys: null,
|
|
1170
|
+
commonTypes: "",
|
|
1171
|
+
componentSchema: "",
|
|
1172
|
+
doNotModify: "",
|
|
1173
|
+
utils: ""
|
|
1174
|
+
};
|
|
1175
|
+
constructor(options) {
|
|
1176
|
+
this._options = options;
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* 一次性生成(整合所有階段)
|
|
1180
|
+
*/
|
|
1181
|
+
async generateAll() {
|
|
1182
|
+
await this.prepare();
|
|
1183
|
+
await this.generateApi();
|
|
1184
|
+
this.generateCacheKeysContent();
|
|
1185
|
+
this.generateCommonTypesContent();
|
|
1186
|
+
this.generateSchemaContent();
|
|
1187
|
+
this.generateUtilsContent();
|
|
1188
|
+
this.generateDoNotModifyContent();
|
|
1189
|
+
return await this.release();
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* 準備階段:解析 schema 並初始化所有服務
|
|
1193
|
+
*/
|
|
1194
|
+
async prepare() {
|
|
1195
|
+
this.actualSchemaFile = this._options.schemaFile;
|
|
1196
|
+
if (this._options.remoteFile) {
|
|
1197
|
+
this.actualSchemaFile = await this.openApiService.downloadSchema(
|
|
1198
|
+
this._options.remoteFile,
|
|
1199
|
+
this._options.schemaFile
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
this.openApiDoc = await this.openApiService.getDocument(
|
|
1203
|
+
this.actualSchemaFile,
|
|
1204
|
+
this._options.httpResolverOptions
|
|
1205
|
+
);
|
|
1206
|
+
this.parserService = new OpenApiParserService(this.openApiDoc, this._options);
|
|
1207
|
+
this.parserService.initialize();
|
|
1208
|
+
const apiGen = this.parserService.getApiGenerator();
|
|
1209
|
+
this.schemaInterfaces = apiGen.aliases.reduce((curr, alias) => {
|
|
1210
|
+
if (ts3.isInterfaceDeclaration(alias) || ts3.isTypeAliasDeclaration(alias)) {
|
|
1211
|
+
const name = alias.name.text;
|
|
1212
|
+
return {
|
|
1213
|
+
...curr,
|
|
1214
|
+
[name]: alias
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
return curr;
|
|
1218
|
+
}, {});
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* 生成階段:產生所有內容但不寫檔
|
|
1222
|
+
*/
|
|
1223
|
+
async generateApi() {
|
|
1224
|
+
if (!this.openApiDoc || !this.parserService) {
|
|
1225
|
+
throw new Error("\u8ACB\u5148\u8ABF\u7528 prepare() \u65B9\u6CD5");
|
|
1226
|
+
}
|
|
1227
|
+
const paths = this.openApiService.getPaths(this.openApiDoc);
|
|
1228
|
+
const groupInfos = this.groupService.groupPaths(paths, this._options.outputFiles);
|
|
1229
|
+
for (const groupInfo of Object.values(groupInfos)) {
|
|
1230
|
+
try {
|
|
1231
|
+
const groupContent = await this.generateApiGroupContent(
|
|
1232
|
+
this._options,
|
|
1233
|
+
groupInfo
|
|
1234
|
+
);
|
|
1235
|
+
if (groupContent.operationNames.length > 0) {
|
|
1236
|
+
this.generatedContent.groups.push({
|
|
1237
|
+
groupKey: groupInfo.groupKey,
|
|
1238
|
+
outputPath: groupInfo.outputPath,
|
|
1239
|
+
content: groupContent
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
} catch (error) {
|
|
1243
|
+
throw new Error(`\u7FA4\u7D44 ${groupInfo.groupKey} \u751F\u6210\u5931\u6557: ${error}`);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* 生成 cache keys
|
|
1249
|
+
*/
|
|
1250
|
+
async generateCacheKeysContent() {
|
|
1251
|
+
this.generatedContent.cacheKeys = generateCacheKeysFile(this.allEndpointCacheKeys);
|
|
1252
|
+
}
|
|
1253
|
+
/**
|
|
1254
|
+
* 生成 common types
|
|
1255
|
+
*/
|
|
1256
|
+
async generateCommonTypesContent() {
|
|
1257
|
+
this.generatedContent.commonTypes = generateCommonTypesFile();
|
|
1258
|
+
}
|
|
1259
|
+
/**
|
|
1260
|
+
* 生成Schema
|
|
1261
|
+
*/
|
|
1262
|
+
async generateSchemaContent() {
|
|
1263
|
+
this.generatedContent.componentSchema = generateComponentSchemaFile(this.schemaInterfaces);
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* 生成 DO_NOT_MODIFY.md
|
|
1267
|
+
*/
|
|
1268
|
+
async generateDoNotModifyContent() {
|
|
1269
|
+
this.generatedContent.doNotModify = generateDoNotModifyFile();
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* 生成 Utils Function
|
|
1273
|
+
*/
|
|
1274
|
+
async generateUtilsContent() {
|
|
1275
|
+
this.generatedContent.utils = generateUtilsFile();
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* 發佈階段:統一寫入所有檔案
|
|
1279
|
+
*/
|
|
1280
|
+
async release() {
|
|
1281
|
+
const results = [];
|
|
1282
|
+
const errors = [];
|
|
1283
|
+
const generatedGroups = [];
|
|
1284
|
+
try {
|
|
1285
|
+
for (const group of this.generatedContent.groups) {
|
|
1286
|
+
try {
|
|
1287
|
+
if (group.content?.files) {
|
|
1288
|
+
const groupOutputDir = path4.dirname(group.outputPath);
|
|
1289
|
+
const groupResults = await this.fileWriterService.writeGroupFiles(
|
|
1290
|
+
groupOutputDir,
|
|
1291
|
+
{
|
|
1292
|
+
types: group.content.files.types,
|
|
1293
|
+
apiService: group.content.files.apiService,
|
|
1294
|
+
queryService: group.content.files.queryService,
|
|
1295
|
+
index: group.content.files.index
|
|
1296
|
+
}
|
|
1297
|
+
);
|
|
1298
|
+
results.push(...groupResults);
|
|
1299
|
+
generatedGroups.push(group.groupKey);
|
|
1300
|
+
}
|
|
1301
|
+
} catch (error) {
|
|
1302
|
+
errors.push(new Error(`\u5BEB\u5165\u7FA4\u7D44 ${group.groupKey} \u5931\u6557: ${error}`));
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
const outputDir = this.generatedContent.groups[0] ? path4.dirname(path4.dirname(this.generatedContent.groups[0].outputPath)) : "./generated";
|
|
1306
|
+
if (this.generatedContent.cacheKeys || this.generatedContent.commonTypes || this.generatedContent.doNotModify || this.generatedContent.utils) {
|
|
1307
|
+
const sharedResults = await this.fileWriterService.writeSharedFiles(
|
|
1308
|
+
outputDir,
|
|
1309
|
+
{
|
|
1310
|
+
cacheKeys: this.generatedContent.cacheKeys || void 0,
|
|
1311
|
+
commonTypes: this.generatedContent.commonTypes || void 0,
|
|
1312
|
+
doNotModify: this.generatedContent.doNotModify || void 0,
|
|
1313
|
+
utils: this.generatedContent.utils || void 0
|
|
1314
|
+
}
|
|
1315
|
+
);
|
|
1316
|
+
results.push(...sharedResults);
|
|
1317
|
+
}
|
|
1318
|
+
if (this.generatedContent.componentSchema) {
|
|
1319
|
+
const schemaResults = await this.fileWriterService.writeSchemaFile(
|
|
1320
|
+
outputDir,
|
|
1321
|
+
this.generatedContent.componentSchema
|
|
1322
|
+
);
|
|
1323
|
+
results.push(...schemaResults);
|
|
1324
|
+
}
|
|
1325
|
+
} catch (error) {
|
|
1326
|
+
errors.push(error);
|
|
1327
|
+
}
|
|
1328
|
+
return {
|
|
1329
|
+
success: errors.length === 0,
|
|
1330
|
+
writtenFiles: results,
|
|
1331
|
+
errors,
|
|
1332
|
+
generatedGroups
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* 為單一群組生成內容
|
|
1337
|
+
*/
|
|
1338
|
+
async generateApiGroupContent(options, groupInfo) {
|
|
1339
|
+
const { outputFiles, ...commonConfig } = options;
|
|
1340
|
+
const groupOptions = {
|
|
1341
|
+
...commonConfig,
|
|
1342
|
+
schemaFile: this.actualSchemaFile,
|
|
1343
|
+
outputFile: groupInfo.outputPath,
|
|
1344
|
+
sharedTypesFile: `${outputFiles.outputDir}/common-types.ts`,
|
|
1345
|
+
filterEndpoints: this.groupService.createGroupFilter(groupInfo.groupKey, outputFiles),
|
|
1346
|
+
queryMatch: outputFiles.queryMatch,
|
|
1347
|
+
groupKey: groupInfo.groupKey
|
|
1348
|
+
};
|
|
1349
|
+
if (!this.openApiDoc || !this.parserService) {
|
|
1350
|
+
throw new Error("OpenAPI \u6587\u6A94\u672A\u521D\u59CB\u5316\uFF0C\u8ACB\u5148\u8ABF\u7528 prepare()");
|
|
1351
|
+
}
|
|
1352
|
+
const apiGenerator = new ApiCodeGenerator(this.parserService, groupOptions);
|
|
1353
|
+
const result = await apiGenerator.generate();
|
|
1354
|
+
if (result.files && "allEndpointCacheKeys" in result.files) {
|
|
1355
|
+
const cacheKeys = result.files.allEndpointCacheKeys;
|
|
1356
|
+
this.allEndpointCacheKeys.push(...cacheKeys);
|
|
1357
|
+
}
|
|
1358
|
+
return result;
|
|
1359
|
+
}
|
|
1360
|
+
};
|
|
1361
|
+
|
|
1362
|
+
// src/index.ts
|
|
1363
|
+
async function generateEndpoints(options) {
|
|
1364
|
+
const generator = new UnifiedCodeGenerator(options);
|
|
1365
|
+
const result = await generator.generateAll();
|
|
1366
|
+
if (!result.success) {
|
|
1367
|
+
if (result.errors.length > 0) {
|
|
1368
|
+
throw result.errors[0];
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
export {
|
|
1374
|
+
generateEndpoints
|
|
1375
|
+
};
|
|
1376
|
+
//# sourceMappingURL=index.mjs.map
|