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