@bitstack/ng-query-codegen-openapi 0.0.30 → 0.0.31-alpha.0
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 +8 -1
- package/lib/bin/cli.mjs +70 -57
- package/lib/bin/cli.mjs.map +1 -1
- package/lib/index.d.mts +4 -18
- package/lib/index.d.ts +4 -18
- package/lib/index.js +343 -275
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +343 -275
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/bin/utils.ts +74 -3
- package/src/generators/common-types-generator.ts +6 -2
- package/src/generators/component-schema-generator.ts +40 -7
- package/src/generators/do-not-modify-generator.ts +2 -2
- package/src/generators/rtk-enhance-endpoints-generator.ts +113 -0
- package/src/generators/{query-service-generator.ts → rtk-query-generator.ts} +45 -33
- package/src/generators/tag-types-generator.ts +30 -0
- package/src/generators/types-generator.ts +216 -112
- package/src/generators/utils-generator.ts +2 -4
- package/src/index.ts +6 -3
- package/src/services/api-code-generator.ts +62 -74
- package/src/services/endpoint-info-extractor.ts +66 -14
- package/src/services/file-writer-service.ts +27 -23
- package/src/services/openapi-parser-service.ts +10 -2
- package/src/services/unified-code-generator.ts +55 -26
- package/src/types.ts +19 -45
- package/src/generators/api-service-generator.ts +0 -112
- package/src/generators/cache-keys-generator.ts +0 -43
- package/src/generators/index-generator.ts +0 -11
- package/src/services/api-service-generator.ts +0 -24
- package/src/services/query-code-generator.ts +0 -24
package/src/types.ts
CHANGED
|
@@ -3,22 +3,13 @@ import type { OpenAPIV3 } from 'openapi-types';
|
|
|
3
3
|
import ts from 'typescript';
|
|
4
4
|
|
|
5
5
|
// 重新匯出服務相關類型
|
|
6
|
-
export type {
|
|
7
|
-
GroupConfig,
|
|
8
|
-
GroupInfo
|
|
9
|
-
} from './services/group-service';
|
|
6
|
+
export type { GroupConfig, GroupInfo } from './services/group-service';
|
|
10
7
|
|
|
11
|
-
export type {
|
|
12
|
-
FileWriteResult
|
|
13
|
-
} from './services/file-writer-service';
|
|
14
|
-
|
|
15
|
-
export type {
|
|
16
|
-
EndpointCacheKey
|
|
17
|
-
} from './services/unified-code-generator';
|
|
8
|
+
export type { FileWriteResult } from './services/file-writer-service';
|
|
18
9
|
|
|
19
10
|
export type {
|
|
20
11
|
UnifiedGenerationOptions as EndpointGenerationOptions,
|
|
21
|
-
UnifiedGenerationResult as EndpointGenerationResult
|
|
12
|
+
UnifiedGenerationResult as EndpointGenerationResult,
|
|
22
13
|
} from './services/unified-code-generator';
|
|
23
14
|
|
|
24
15
|
export type OperationDefinition = {
|
|
@@ -69,12 +60,12 @@ export interface CommonOptions {
|
|
|
69
60
|
importName: string;
|
|
70
61
|
};
|
|
71
62
|
/**
|
|
72
|
-
*
|
|
63
|
+
* HTTP client configuration for API calls
|
|
73
64
|
* defaults to { file: "@core/httpClient/webapi/webapi-http-client.providers", importName: "WEBAPI_HTTP_CLIENT" }
|
|
74
65
|
*/
|
|
75
66
|
httpClient?: {
|
|
76
67
|
file: string;
|
|
77
|
-
|
|
68
|
+
importReturnTypeName: string; // 用於指定別名導入,例如 IRestFulEndpointsQueryReturn
|
|
78
69
|
};
|
|
79
70
|
/**
|
|
80
71
|
* defaults to "enhancedApi"
|
|
@@ -94,9 +85,9 @@ export interface CommonOptions {
|
|
|
94
85
|
operationNameSuffix?: string;
|
|
95
86
|
/**
|
|
96
87
|
* defaults to `false`
|
|
97
|
-
* `true` will generate
|
|
88
|
+
* `true` will generate lazy query hooks (useLazy prefix) for query endpoints
|
|
98
89
|
*/
|
|
99
|
-
|
|
90
|
+
useLazyQueries?: boolean;
|
|
100
91
|
/**
|
|
101
92
|
* defaults to false
|
|
102
93
|
* `true` will generate a union type for `undefined` properties like: `{ id?: string | undefined }` instead of `{ id?: string }`
|
|
@@ -151,11 +142,6 @@ export interface CommonOptions {
|
|
|
151
142
|
* File path for importing IRestFulEndpointsQueryReturn type
|
|
152
143
|
*/
|
|
153
144
|
endpointsQueryReturnTypeFile?: string;
|
|
154
|
-
/**
|
|
155
|
-
* defaults to 60 (seconds)
|
|
156
|
-
* Number of seconds to wait before refetching data when component mounts or args change
|
|
157
|
-
*/
|
|
158
|
-
refetchOnMountOrArgChange?: number;
|
|
159
145
|
}
|
|
160
146
|
|
|
161
147
|
export type TextMatcher = string | RegExp | (string | RegExp)[];
|
|
@@ -173,11 +159,6 @@ export interface OutputFileOptions extends Partial<CommonOptions> {
|
|
|
173
159
|
filterEndpoints?: EndpointMatcher;
|
|
174
160
|
endpointOverrides?: EndpointOverrides[];
|
|
175
161
|
queryMatch?: (method: string, path: string) => boolean;
|
|
176
|
-
/**
|
|
177
|
-
* defaults to false
|
|
178
|
-
* If passed as true it will generate TS enums instead of union of strings
|
|
179
|
-
*/
|
|
180
|
-
useEnumType?: boolean;
|
|
181
162
|
sharedTypesFile?: string;
|
|
182
163
|
/**
|
|
183
164
|
* groupKey for service class naming, e.g., "room" -> "RoomService"
|
|
@@ -204,30 +185,23 @@ export type ConfigFile =
|
|
|
204
185
|
| Id<
|
|
205
186
|
Omit<CommonOptions, 'outputFile'> & {
|
|
206
187
|
// outputFiles: { [outputFile: string]: Omit<OutputFileOptions, 'outputFile'> };
|
|
207
|
-
outputFiles: OutputFilesConfig
|
|
188
|
+
outputFiles: OutputFilesConfig;
|
|
208
189
|
}
|
|
209
190
|
>;
|
|
210
191
|
|
|
211
192
|
export type GenerateApiResult = {
|
|
212
193
|
operationNames: string[];
|
|
194
|
+
tags: string[]; // 收集到的所有 tags
|
|
213
195
|
files: {
|
|
214
196
|
types: string;
|
|
215
|
-
|
|
216
|
-
queryService: string;
|
|
197
|
+
queryService: string; // RTK Query generated file
|
|
217
198
|
index: string;
|
|
199
|
+
enhanceEndpoints?: string; // RTK Query enhance endpoints file
|
|
218
200
|
commonTypes?: string;
|
|
219
|
-
cacheKeys?: string;
|
|
220
201
|
componentSchema?: string;
|
|
221
|
-
allEndpointCacheKeys?: Array<{
|
|
222
|
-
operationName: string
|
|
223
|
-
queryKeyName: string
|
|
224
|
-
groupKey: string
|
|
225
|
-
}>;
|
|
226
202
|
};
|
|
227
203
|
};
|
|
228
204
|
|
|
229
|
-
|
|
230
|
-
|
|
231
205
|
export type QueryArgDefinition = {
|
|
232
206
|
name: string;
|
|
233
207
|
originalName: string;
|
|
@@ -236,13 +210,13 @@ export type QueryArgDefinition = {
|
|
|
236
210
|
param?: OpenAPIV3.ParameterObject;
|
|
237
211
|
} & (
|
|
238
212
|
| {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
213
|
+
origin: 'param';
|
|
214
|
+
param: OpenAPIV3.ParameterObject;
|
|
215
|
+
}
|
|
242
216
|
| {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
246
|
-
|
|
217
|
+
origin: 'body';
|
|
218
|
+
body: OpenAPIV3.RequestBodyObject;
|
|
219
|
+
}
|
|
220
|
+
);
|
|
247
221
|
|
|
248
|
-
export type QueryArgDefinitions = Record<string, QueryArgDefinition>;
|
|
222
|
+
export type QueryArgDefinitions = Record<string, QueryArgDefinition>;
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import type { GenerationOptions } from '../types';
|
|
2
|
-
|
|
3
|
-
export function generateApiServiceFile(endpointInfos: Array<{
|
|
4
|
-
operationName: string;
|
|
5
|
-
argTypeName: string;
|
|
6
|
-
responseTypeName: string;
|
|
7
|
-
isQuery: boolean;
|
|
8
|
-
verb: string;
|
|
9
|
-
path: string;
|
|
10
|
-
queryKeyName: string;
|
|
11
|
-
queryParams: any[];
|
|
12
|
-
pathParams: any[];
|
|
13
|
-
isVoidArg: boolean;
|
|
14
|
-
summary: string;
|
|
15
|
-
}>, options: GenerationOptions) {
|
|
16
|
-
|
|
17
|
-
const { apiConfiguration, httpClient, groupKey } = options;
|
|
18
|
-
|
|
19
|
-
// 確定服務名稱,使用業務名稱
|
|
20
|
-
const apiServiceClassName = groupKey ?
|
|
21
|
-
`${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)}ApiService` :
|
|
22
|
-
'ApiService';
|
|
23
|
-
|
|
24
|
-
return `/* eslint-disable */
|
|
25
|
-
// [Warning] Generated automatically - do not edit manually
|
|
26
|
-
|
|
27
|
-
import { ${httpClient!.importName} } from '${httpClient!.file}';
|
|
28
|
-
import { Injectable, inject } from '@angular/core';
|
|
29
|
-
import { Observable } from 'rxjs';
|
|
30
|
-
import { ${apiConfiguration!.importName} } from '${apiConfiguration!.file}';
|
|
31
|
-
import { RequestOptions, IRestFulEndpointsQueryReturn } from '../common-types';
|
|
32
|
-
import { withoutUndefined } from '../utils';
|
|
33
|
-
import {${endpointInfos.map(info => ` ${info.argTypeName}, ${info.responseTypeName}`).join(',')} } from './types';
|
|
34
|
-
|
|
35
|
-
@Injectable({
|
|
36
|
-
providedIn: 'root',
|
|
37
|
-
})
|
|
38
|
-
export class ${apiServiceClassName} {
|
|
39
|
-
private config = inject(${apiConfiguration!.importName});
|
|
40
|
-
private http = inject(${httpClient!.importName});
|
|
41
|
-
|
|
42
|
-
${endpointInfos.map(info => {
|
|
43
|
-
const isGet = info.verb.toUpperCase() === 'GET';
|
|
44
|
-
const hasArgs = info.argTypeName !== 'VoidApiArg';
|
|
45
|
-
|
|
46
|
-
// 生成 URL 模板字面量,直接替換路徑參數
|
|
47
|
-
const generateUrlTemplate = (path: string) => {
|
|
48
|
-
const hasPathParams = path.includes('{');
|
|
49
|
-
if (hasPathParams && hasArgs) {
|
|
50
|
-
// 將 {paramName} 替換為 ${args.variables.paramName}
|
|
51
|
-
const urlTemplate = path.replace(/\{([^}]+)\}/g, '${args.variables.$1}');
|
|
52
|
-
return `\`\${this.config.rootUrl}${urlTemplate}\``;
|
|
53
|
-
} else {
|
|
54
|
-
return `\`\${this.config.rootUrl}${path}\``;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const hasQueryParams = info.queryParams.length > 0;
|
|
59
|
-
const hasBody = !isGet && hasArgs && !info.isVoidArg;
|
|
60
|
-
|
|
61
|
-
// 生成 HTTP 請求選項
|
|
62
|
-
const generateRequestOptions = () => {
|
|
63
|
-
const options = [
|
|
64
|
-
'...args.fetchOptions',
|
|
65
|
-
];
|
|
66
|
-
|
|
67
|
-
// 添加 Content-Type header,特別是對於有 body 的請求
|
|
68
|
-
if (hasBody || !isGet) {
|
|
69
|
-
options.push(`headers: { 'Content-Type': 'application/json', ...args.fetchOptions?.headers }`);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (hasQueryParams && hasArgs) {
|
|
73
|
-
options.push(generateQueryParams(info.queryParams));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (hasBody) {
|
|
77
|
-
options.push('body: args.variables.body');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return options.length > 0 ? `{ ${options.join(', ')} }` : '{}';
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
return `
|
|
84
|
-
/**
|
|
85
|
-
* ${info.summary}
|
|
86
|
-
*/
|
|
87
|
-
${info.operationName}(
|
|
88
|
-
${hasArgs ? `args: IRestFulEndpointsQueryReturn<${info.argTypeName}>, ` : ''}
|
|
89
|
-
): Observable<${info.responseTypeName}> {
|
|
90
|
-
const url = ${generateUrlTemplate(info.path)};
|
|
91
|
-
return this.http.request('${info.verb.toLowerCase()}', url, ${generateRequestOptions()});
|
|
92
|
-
}`;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}).join('')}
|
|
97
|
-
}
|
|
98
|
-
`;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* 產生 QueryParams 參數
|
|
104
|
-
* @param queryParams
|
|
105
|
-
*/
|
|
106
|
-
function generateQueryParams(queryParams: Record<string, string>[]) {
|
|
107
|
-
const paramEntries = queryParams.map(param =>
|
|
108
|
-
`${param.name}: args.variables.${param.name}`
|
|
109
|
-
).join(', ');
|
|
110
|
-
|
|
111
|
-
return `params: withoutUndefined({ ${paramEntries} })`;
|
|
112
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { toCamelCase } from './utils-generator';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export function generateCacheKeysFile(allEndpointInfos: Array<{
|
|
5
|
-
operationName: string;
|
|
6
|
-
queryKeyName: string;
|
|
7
|
-
groupKey: string;
|
|
8
|
-
}>) {
|
|
9
|
-
|
|
10
|
-
// 按 group 分組
|
|
11
|
-
const groupedKeys = allEndpointInfos.reduce((acc, info) => {
|
|
12
|
-
if (!acc[info.groupKey]) {
|
|
13
|
-
acc[info.groupKey] = [];
|
|
14
|
-
}
|
|
15
|
-
acc[info.groupKey].push({
|
|
16
|
-
operationName: info.operationName,
|
|
17
|
-
queryKeyName: info.queryKeyName
|
|
18
|
-
});
|
|
19
|
-
return acc;
|
|
20
|
-
}, {} as Record<string, Array<{operationName: string, queryKeyName: string}>>);
|
|
21
|
-
|
|
22
|
-
// 生成 enum 內容
|
|
23
|
-
const enumEntries = Object.entries(groupedKeys).map(([groupKey, keys]) => {
|
|
24
|
-
const groupComment = ` // ${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)} related cache keys`;
|
|
25
|
-
const keyEntries = keys.map(key =>
|
|
26
|
-
` ${key.queryKeyName} = '${toCamelCase(key.queryKeyName)}',`
|
|
27
|
-
).join('\n');
|
|
28
|
-
|
|
29
|
-
return `${groupComment}\n${keyEntries}`;
|
|
30
|
-
}).join('\n\n');
|
|
31
|
-
|
|
32
|
-
return `// [Warning] Generated automatically - do not edit manually
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Cache keys enum for all API queries
|
|
36
|
-
*/
|
|
37
|
-
export enum ECacheKeys {
|
|
38
|
-
${enumEntries}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export default ECacheKeys;
|
|
42
|
-
`;
|
|
43
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { GenerationOptions } from '../types';
|
|
2
|
-
|
|
3
|
-
export function generateIndexFile(groupKey: string, options: GenerationOptions) {
|
|
4
|
-
const { groupKey: optionsGroupKey } = options;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
return `export * from './types';
|
|
8
|
-
export * from './api.service';
|
|
9
|
-
export * from './query.service';
|
|
10
|
-
`;
|
|
11
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { GenerationOptions } from '../types';
|
|
2
|
-
import { generateApiServiceFile } from '../generators/api-service-generator';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* API 服務程式碼生成器 - 專門負責生成 API Service 相關程式碼
|
|
6
|
-
*/
|
|
7
|
-
export class ApiServiceGenerator {
|
|
8
|
-
constructor(private options: GenerationOptions) {}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 生成 API Service 檔案內容
|
|
12
|
-
*/
|
|
13
|
-
generateApiService(endpointInfos: Array<any>): string {
|
|
14
|
-
const generatorOptions = {
|
|
15
|
-
...this.options,
|
|
16
|
-
apiConfiguration: this.options.apiConfiguration || {
|
|
17
|
-
file: '@/store/webapi',
|
|
18
|
-
importName: 'WebApiConfiguration'
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
return generateApiServiceFile(endpointInfos, generatorOptions);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { GenerationOptions } from '../types';
|
|
2
|
-
import { generateQueryServiceFile } from '../generators/query-service-generator';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Query 服務程式碼生成器 - 專門負責生成 Query Service 相關程式碼
|
|
6
|
-
*/
|
|
7
|
-
export class QueryCodeGenerator {
|
|
8
|
-
constructor(private options: GenerationOptions) {}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 生成 Query Service 檔案內容
|
|
12
|
-
*/
|
|
13
|
-
generateQueryService(endpointInfos: Array<any>): string {
|
|
14
|
-
const generatorOptions = {
|
|
15
|
-
...this.options,
|
|
16
|
-
apiConfiguration: this.options.apiConfiguration || {
|
|
17
|
-
file: '@/store/webapi',
|
|
18
|
-
importName: 'WebApiConfiguration'
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
return generateQueryServiceFile(endpointInfos, generatorOptions);
|
|
23
|
-
}
|
|
24
|
-
}
|