@acrool/rtk-query-codegen-openapi 0.0.2-test.8 → 0.0.2

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/src/generate.ts CHANGED
@@ -38,8 +38,8 @@ function defaultIsDataResponse(code: string, includeDefault: boolean) {
38
38
  return !Number.isNaN(parsedCode) && parsedCode >= 200 && parsedCode < 300;
39
39
  }
40
40
 
41
- function getOperationName({ verb, path }: Pick<OperationDefinition, 'verb' | 'path' >) {
42
- return _getOperationName(verb, path, undefined);
41
+ function getOperationName({ verb, path, operation }: Pick<OperationDefinition, 'verb' | 'path' | 'operation'>) {
42
+ return _getOperationName(verb, path, operation.operationId);
43
43
  }
44
44
 
45
45
  function getTags({ verb, pathItem }: Pick<OperationDefinition, 'verb' | 'pathItem'>): string[] {
@@ -128,72 +128,49 @@ export async function generateApi(
128
128
  mergeReadWriteOnly,
129
129
  });
130
130
 
131
- const schemeTypeNames = new Set<string>();
132
-
133
- function addSchemeTypeName(name: string) {
134
- schemeTypeNames.add(name);
135
- schemeTypeNames.add(camelCase(name));
136
- schemeTypeNames.add(capitalize(camelCase(name)));
137
- }
138
-
131
+ // 如果提供了 sharedTypesFile,則將 components 輸出到該文件
139
132
  if (sharedTypesFile) {
140
- const resultFile = ts.createSourceFile(
141
- 'sharedTypes.ts',
142
- '',
143
- ts.ScriptTarget.Latest,
144
- /*setParentNodes*/ false,
145
- ts.ScriptKind.TS
146
- );
147
- const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
148
-
149
- const allTypeDefinitions: ts.Statement[] = [];
150
-
151
133
  const components = v3Doc.components;
152
134
  if (components) {
153
- const componentDefinitions = Object.entries(components).map(([componentType, componentDefs]) => {
154
- const typeEntries = Object.entries(componentDefs as Record<string, unknown>).map(([name, def]) => {
155
- addSchemeTypeName(name);
156
-
157
- const typeName = capitalize(camelCase(name));
158
- const typeNode = wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(def as OpenAPIV3.SchemaObject));
135
+ const resultFile = ts.createSourceFile(
136
+ 'sharedTypes.ts',
137
+ '',
138
+ ts.ScriptTarget.Latest,
139
+ /*setParentNodes*/ false,
140
+ ts.ScriptKind.TS
141
+ );
142
+ const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
143
+
144
+ // 將 components 轉換為 TypeScript 類型定義
145
+ const typeDefinitions = Object.entries(components).flatMap(([_, componentDefs]) => {
146
+ return Object.entries(componentDefs as Record<string, unknown>).map(([name, def]) => {
147
+ const typeNode = apiGen.getTypeFromSchema(def as OpenAPIV3.SchemaObject);
159
148
  return factory.createTypeAliasDeclaration(
160
149
  [factory.createModifier(ts.SyntaxKind.ExportKeyword)],
161
- factory.createIdentifier(typeName),
150
+ factory.createIdentifier(name),
162
151
  undefined,
163
152
  typeNode
164
153
  );
165
154
  });
166
-
167
- return factory.createModuleDeclaration(
168
- [factory.createModifier(ts.SyntaxKind.ExportKeyword)],
169
- factory.createIdentifier('Scheme'),
170
- factory.createModuleBlock(typeEntries),
171
- ts.NodeFlags.Namespace
172
- );
173
155
  });
174
- allTypeDefinitions.push(...componentDefinitions);
175
- }
176
156
 
177
- if (useEnumType) {
178
- allTypeDefinitions.push(...apiGen.enumAliases);
179
- }
180
-
181
- allTypeDefinitions.push(...apiGen.aliases);
182
-
183
- const output = printer.printNode(
184
- ts.EmitHint.Unspecified,
185
- factory.createSourceFile(
186
- allTypeDefinitions,
187
- factory.createToken(ts.SyntaxKind.EndOfFileToken),
188
- ts.NodeFlags.None
189
- ),
190
- resultFile
191
- );
157
+ const output = printer.printNode(
158
+ ts.EmitHint.Unspecified,
159
+ factory.createSourceFile(
160
+ typeDefinitions,
161
+ factory.createToken(ts.SyntaxKind.EndOfFileToken),
162
+ ts.NodeFlags.None
163
+ ),
164
+ resultFile
165
+ );
192
166
 
193
- const fs = await import('node:fs/promises');
194
- await fs.writeFile(sharedTypesFile, output, 'utf-8');
167
+ // 寫入文件
168
+ const fs = await import('node:fs/promises');
169
+ await fs.writeFile(sharedTypesFile, output, 'utf-8');
170
+ }
195
171
  }
196
172
 
173
+ // temporary workaround for https://github.com/oazapfts/oazapfts/issues/491
197
174
  if (apiGen.spec.components?.schemas) {
198
175
  apiGen.preprocessComponents(apiGen.spec.components.schemas);
199
176
  }
@@ -226,18 +203,17 @@ export async function generateApi(
226
203
  apiFile = apiFile.replace(/\\/g, '/');
227
204
  if (!apiFile.startsWith('.')) apiFile = `./${apiFile}`;
228
205
  }
206
+ // 處理 sharedTypesFile 的路徑
207
+ if (sharedTypesFile && sharedTypesFile.startsWith('.')) {
208
+ sharedTypesFile = path.relative(path.dirname(outputFile), sharedTypesFile);
209
+ sharedTypesFile = sharedTypesFile.replace(/\\/g, '/');
210
+ if (!sharedTypesFile.startsWith('.')) sharedTypesFile = `./${sharedTypesFile}`;
211
+ }
229
212
  }
230
213
  apiFile = apiFile.replace(/\.[jt]sx?$/, '');
231
-
232
- const sharedTypesImportPath = sharedTypesFile && outputFile
233
- ? (() => {
234
- let rel = path.relative(path.dirname(outputFile), sharedTypesFile)
235
- .replace(/\\/g, '/')
236
- .replace(/\.[jt]sx?$/, '');
237
- if (!rel.startsWith('.')) rel = './' + rel;
238
- return rel;
239
- })()
240
- : './shared-types';
214
+ if (sharedTypesFile) {
215
+ sharedTypesFile = sharedTypesFile.replace(/\.[jt]sx?$/, '');
216
+ }
241
217
 
242
218
  return printer.printNode(
243
219
  ts.EmitHint.Unspecified,
@@ -245,7 +221,18 @@ export async function generateApi(
245
221
  [
246
222
  generateImportNode(apiFile, { [apiImport]: 'api' }),
247
223
  generateImportNode('@acrool/react-fetcher', { IRestFulEndpointsQueryReturn: 'IRestFulEndpointsQueryReturn' }),
248
- ...(sharedTypesFile ? [generateImportNode(sharedTypesImportPath, { Scheme: 'Scheme' })] : []),
224
+ ...(sharedTypesFile ? [
225
+ factory.createImportDeclaration(
226
+ undefined,
227
+ factory.createImportClause(
228
+ false,
229
+ undefined,
230
+ factory.createNamespaceImport(factory.createIdentifier('SharedTypes'))
231
+ ),
232
+ factory.createStringLiteral(sharedTypesFile),
233
+ undefined
234
+ )
235
+ ] : []),
249
236
  ...(tag ? [generateTagTypes({ addTagTypes: extractAllTagTypes({ operationDefinitions }) })] : []),
250
237
  generateCreateApiCall({
251
238
  tag,
@@ -254,7 +241,6 @@ export async function generateApi(
254
241
  generateEndpoint({
255
242
  operationDefinition,
256
243
  overrides: getOverrides(operationDefinition, endpointOverrides),
257
- sharedTypesFile: !!sharedTypesFile,
258
244
  })
259
245
  ),
260
246
  true
@@ -299,11 +285,9 @@ export async function generateApi(
299
285
  function generateEndpoint({
300
286
  operationDefinition,
301
287
  overrides,
302
- sharedTypesFile,
303
288
  }: {
304
289
  operationDefinition: OperationDefinition;
305
290
  overrides?: EndpointOverrides;
306
- sharedTypesFile: boolean;
307
291
  }) {
308
292
  const {
309
293
  verb,
@@ -312,56 +296,73 @@ export async function generateApi(
312
296
  operation,
313
297
  operation: { responses, requestBody },
314
298
  } = operationDefinition;
315
- const operationName = getOperationName({ verb, path });
299
+ const operationName = getOperationName({ verb, path, operation });
316
300
  const tags = tag ? getTags({ verb, pathItem }) : [];
317
301
  const isQuery = testIsQuery(verb, overrides);
318
302
 
319
303
  const returnsJson = apiGen.getResponseType(responses) === 'json';
320
304
  let ResponseType: ts.TypeNode = factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
305
+
306
+ function replaceReferences(schema: any): ts.TypeNode {
307
+ if (!schema) return factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
308
+
309
+ const refName = getReferenceName(schema);
310
+ if (refName && sharedTypesFile) {
311
+ return factory.createTypeReferenceNode(
312
+ factory.createQualifiedName(
313
+ factory.createIdentifier('SharedTypes'),
314
+ factory.createIdentifier(refName)
315
+ ),
316
+ undefined
317
+ );
318
+ }
319
+
320
+ if (schema.type === 'object' && schema.properties) {
321
+ const members = Object.entries(schema.properties).map(([key, value]: [string, any]) => {
322
+ return factory.createPropertySignature(
323
+ undefined,
324
+ factory.createIdentifier(key),
325
+ schema.required?.includes(key) ? undefined : factory.createToken(ts.SyntaxKind.QuestionToken),
326
+ replaceReferences(value)
327
+ );
328
+ });
329
+ return factory.createTypeLiteralNode(members);
330
+ }
331
+
332
+ if (schema.type === 'array' && schema.items) {
333
+ return factory.createArrayTypeNode(replaceReferences(schema.items));
334
+ }
335
+
336
+ return apiGen.getTypeFromSchema(schema);
337
+ }
338
+
321
339
  if (returnsJson) {
322
340
  const returnTypes = Object.entries(responses || {})
323
341
  .map(
324
- ([code, response]) =>
325
- [
326
- code,
327
- apiGen.resolve(response),
328
- wrapWithSchemeIfComponent(
329
- apiGen.getTypeFromResponse(response, 'readOnly') ||
330
- factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword)
331
- ),
332
- ] as const
342
+ ([code, response]) => {
343
+ const resolvedResponse = apiGen.resolve(response);
344
+ if (!resolvedResponse.content?.['application/json']?.schema) {
345
+ return [code, resolvedResponse, factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword)] as const;
346
+ }
347
+
348
+ const schema = resolvedResponse.content['application/json'].schema;
349
+ const type = replaceReferences(schema);
350
+
351
+ return [code, resolvedResponse, type] as const;
352
+ }
333
353
  )
334
354
  .filter(([status, response]) =>
335
355
  isDataResponse(status, includeDefault, apiGen.resolve(response), responses || {})
336
356
  )
337
357
  .filter(([_1, _2, type]) => type !== keywordType.void)
338
- .map(([code, response, type]) => {
339
- if (sharedTypesFile && ts.isTypeReferenceNode(type) && type.typeName) {
340
- if (ts.isIdentifier(type.typeName)) {
341
- const typeName = type.typeName.text;
342
- if (typeName in apiGen.aliases || typeName in apiGen.enumAliases) {
343
- return ts.addSyntheticLeadingComment(
344
- factory.createTypeReferenceNode(
345
- factory.createQualifiedName(
346
- factory.createIdentifier('sharedTypes'),
347
- factory.createIdentifier(camelCase(typeName))
348
- ),
349
- type.typeArguments
350
- ),
351
- ts.SyntaxKind.MultiLineCommentTrivia,
352
- `* status ${code} ${response.description} `,
353
- false
354
- );
355
- }
356
- }
357
- }
358
- return ts.addSyntheticLeadingComment(
359
- type,
358
+ .map(([code, response, type]) =>
359
+ ts.addSyntheticLeadingComment(
360
+ { ...type },
360
361
  ts.SyntaxKind.MultiLineCommentTrivia,
361
362
  `* status ${code} ${response.description} `,
362
363
  false
363
- );
364
- });
364
+ )
365
+ );
365
366
  if (returnTypes.length > 0) {
366
367
  ResponseType = factory.createUnionTypeNode(returnTypes);
367
368
  }
@@ -391,36 +392,28 @@ export async function generateApi(
391
392
  const queryArg: QueryArgDefinitions = {};
392
393
  function generateName(name: string, potentialPrefix: string) {
393
394
  const isPureSnakeCase = /^[a-zA-Z][a-zA-Z0-9_]*$/.test(name);
395
+ // prefix with `query`, `path` or `body` if there are multiple paramters with the same name
394
396
  const hasNamingConflict = allNames.filter((n) => n === name).length > 1;
395
397
  if (hasNamingConflict) {
396
398
  name = `${potentialPrefix}_${name}`;
397
399
  }
400
+ // convert to camelCase if the name is pure snake_case and there are no naming conflicts
398
401
  const camelCaseName = camelCase(name);
399
402
  if (isPureSnakeCase && !allNames.includes(camelCaseName)) {
400
403
  name = camelCaseName;
401
404
  }
405
+ // if there are still any naming conflicts, prepend with underscore
402
406
  while (name in queryArg) {
403
407
  name = `_${name}`;
404
408
  }
405
409
  return name;
406
410
  }
407
411
 
408
- for (const param of parameters) {
409
- const name = generateName(param.name, param.in);
410
- queryArg[name] = {
411
- origin: 'param',
412
- name,
413
- originalName: param.name,
414
- type: wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(isReference(param) ? param : param.schema, undefined, 'writeOnly')),
415
- required: param.required,
416
- param,
417
- };
418
- }
419
-
420
412
  if (requestBody) {
421
413
  const body = apiGen.resolve(requestBody);
422
414
  const schema = apiGen.getSchemaFromContent(body.content);
423
- const type = wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(schema));
415
+ const type = replaceReferences(schema);
416
+
424
417
  const schemaName = camelCase(
425
418
  (type as any).name ||
426
419
  getReferenceName(schema) ||
@@ -433,12 +426,27 @@ export async function generateApi(
433
426
  origin: 'body',
434
427
  name,
435
428
  originalName: schemaName,
436
- type: wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(schema, undefined, 'writeOnly')),
429
+ type,
437
430
  required: true,
438
431
  body,
439
432
  };
440
433
  }
441
434
 
435
+ for (const param of parameters) {
436
+ const name = generateName(param.name, param.in);
437
+ const paramSchema = isReference(param) ? param : param.schema;
438
+ const type = replaceReferences(paramSchema);
439
+
440
+ queryArg[name] = {
441
+ origin: 'param',
442
+ name,
443
+ originalName: param.name,
444
+ type,
445
+ required: param.required,
446
+ param,
447
+ };
448
+ }
449
+
442
450
  const propertyName = (name: string | ts.PropertyName): ts.PropertyName => {
443
451
  if (typeof name === 'string') {
444
452
  return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
@@ -609,56 +617,14 @@ export async function generateApi(
609
617
  );
610
618
  }
611
619
 
620
+ // eslint-disable-next-line no-empty-pattern
612
621
  function generateQueryEndpointProps({}: { operationDefinition: OperationDefinition }): ObjectPropertyDefinitions {
613
- return {};
622
+ return {}; /* TODO needs implementation - skip for now */
614
623
  }
615
624
 
625
+ // eslint-disable-next-line no-empty-pattern
616
626
  function generateMutationEndpointProps({}: { operationDefinition: OperationDefinition }): ObjectPropertyDefinitions {
617
- return {};
618
- }
619
-
620
- function wrapWithSchemeIfComponent(typeNode: ts.TypeNode): ts.TypeNode {
621
- if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {
622
- const typeName = typeNode.typeName.text;
623
- if (schemeTypeNames.has(typeName)) {
624
- return factory.createTypeReferenceNode(
625
- factory.createQualifiedName(
626
- factory.createIdentifier('Scheme'),
627
- typeNode.typeName
628
- ),
629
- typeNode.typeArguments?.map(wrapWithSchemeIfComponent)
630
- );
631
- }
632
- if (typeNode.typeArguments) {
633
- return factory.createTypeReferenceNode(
634
- typeNode.typeName,
635
- typeNode.typeArguments.map(wrapWithSchemeIfComponent)
636
- );
637
- }
638
- }
639
- if (ts.isArrayTypeNode(typeNode)) {
640
- return factory.createArrayTypeNode(wrapWithSchemeIfComponent(typeNode.elementType));
641
- }
642
- if (ts.isUnionTypeNode(typeNode)) {
643
- return factory.createUnionTypeNode(typeNode.types.map(wrapWithSchemeIfComponent));
644
- }
645
- if (ts.isTypeLiteralNode(typeNode)) {
646
- return factory.createTypeLiteralNode(
647
- typeNode.members.map(member => {
648
- if (ts.isPropertySignature(member) && member.type) {
649
- return factory.updatePropertySignature(
650
- member,
651
- member.modifiers,
652
- member.name,
653
- member.questionToken,
654
- wrapWithSchemeIfComponent(member.type)
655
- );
656
- }
657
- return member;
658
- })
659
- );
660
- }
661
- return typeNode;
627
+ return {}; /* TODO needs implementation - skip for now */
662
628
  }
663
629
  }
664
630
 
@@ -20,7 +20,7 @@ type CreateBindingParams = {
20
20
  };
21
21
 
22
22
  const createBinding = ({
23
- operationDefinition: { verb, path },
23
+ operationDefinition: { verb, path, operation },
24
24
  overrides,
25
25
  isLazy = false,
26
26
  }: CreateBindingParams) =>
@@ -28,7 +28,7 @@ const createBinding = ({
28
28
  undefined,
29
29
  undefined,
30
30
  factory.createIdentifier(
31
- `use${isLazy ? 'Lazy' : ''}${capitalize(getOperationName(verb, path, undefined))}${
31
+ `use${isLazy ? 'Lazy' : ''}${capitalize(getOperationName(verb, path, operation.operationId))}${
32
32
  isQuery(verb, overrides) ? 'Query' : 'Mutation'
33
33
  }`
34
34
  ),
package/src/index.ts CHANGED
@@ -4,84 +4,10 @@ import path from 'node:path';
4
4
  import { generateApi } from './generate';
5
5
  import type { CommonOptions, ConfigFile, GenerationOptions, OutputFileOptions } from './types';
6
6
  import { isValidUrl, prettify } from './utils';
7
- import camelCase from 'lodash.camelcase';
8
- export type { OutputFilesConfig, ConfigFile } from './types';
7
+ export type { ConfigFile } from './types';
9
8
 
10
9
  const require = createRequire(__filename);
11
10
 
12
-
13
-
14
- // 確保目錄存在的函數
15
- async function ensureDirectoryExists(filePath: string) {
16
- const dirname = path.dirname(filePath);
17
- if (!fs.existsSync(dirname)) {
18
- await fs.promises.mkdir(dirname, { recursive: true });
19
- }
20
- }
21
-
22
-
23
- // 檢查檔案是否存在的函數
24
- function fileExists(filePath: string): boolean {
25
- try {
26
- return fs.statSync(filePath).isFile();
27
- } catch {
28
- return false;
29
- }
30
- }
31
-
32
- // 獲取資料夾名稱並轉換為 API 名稱
33
- function getApiNameFromDir(dirPath: string): string {
34
- const dirName = path.basename(dirPath);
35
- return `${dirName}Api`;
36
- }
37
-
38
- // 確保基礎文件存在的函數
39
- async function ensureBaseFilesExist(outputDir: string) {
40
- const enhanceEndpointsPath = path.join(outputDir, 'enhanceEndpoints.ts');
41
- const indexPath = path.join(outputDir, 'index.ts');
42
- const apiName = getApiNameFromDir(outputDir);
43
-
44
- // 如果 enhanceEndpoints.ts 不存在,創建它
45
- if (!fileExists(enhanceEndpointsPath)) {
46
- const enhanceEndpointsContent = `import api from './query.generated';
47
-
48
- const enhancedApi = api.enhanceEndpoints({
49
- endpoints: {
50
- },
51
- });
52
-
53
- export default enhancedApi;
54
- `;
55
- await fs.promises.writeFile(enhanceEndpointsPath, enhanceEndpointsContent, 'utf-8');
56
- }
57
-
58
- // 如果 index.ts 不存在,創建它
59
- if (!fileExists(indexPath)) {
60
- const indexContent = `export * from './query.generated';
61
- export {default as ${apiName}} from './enhanceEndpoints';
62
- `;
63
- await fs.promises.writeFile(indexPath, indexContent, 'utf-8');
64
- }
65
- }
66
-
67
-
68
- // 從路徑中提取分類名稱
69
- function getGroupNameFromPath(path: string, pattern: RegExp): string {
70
- // console.log('pattern', pattern);
71
-
72
- const match = path.match(pattern);
73
- // console.log('match', path, match);
74
-
75
- if (match && match[1]) {
76
- return camelCase(match[1]);
77
- }
78
- return 'common';
79
- }
80
-
81
-
82
-
83
-
84
-
85
11
  export async function generateEndpoints(options: GenerationOptions): Promise<string | void> {
86
12
  const schemaLocation = options.schemaFile;
87
13
 
@@ -94,15 +20,8 @@ export async function generateEndpoints(options: GenerationOptions): Promise<str
94
20
  });
95
21
  const { outputFile, prettierConfigFile } = options;
96
22
  if (outputFile) {
97
- const outputPath = path.resolve(process.cwd(), outputFile);
98
- await ensureDirectoryExists(outputPath);
99
-
100
- // 確保基礎文件存在
101
- const outputDir = path.dirname(outputPath);
102
- await ensureBaseFilesExist(outputDir);
103
-
104
23
  fs.writeFileSync(
105
- outputPath,
24
+ path.resolve(process.cwd(), outputFile),
106
25
  await prettify(outputFile, sourceCode, prettierConfigFile)
107
26
  );
108
27
  } else {
@@ -110,80 +29,18 @@ export async function generateEndpoints(options: GenerationOptions): Promise<str
110
29
  }
111
30
  }
112
31
 
113
-
114
32
  export function parseConfig(fullConfig: ConfigFile) {
115
33
  const outFiles: (CommonOptions & OutputFileOptions)[] = [];
116
34
 
117
35
  if ('outputFiles' in fullConfig) {
118
36
  const { outputFiles, ...commonConfig } = fullConfig;
119
-
120
- // 讀取 OpenAPI 文檔
121
- const openApiDoc = JSON.parse(fs.readFileSync(fullConfig.schemaFile, 'utf-8'));
122
- const paths = Object.keys(openApiDoc.paths);
123
-
124
- // 從配置中獲取分類規則
125
- const [outputPath, config] = Object.entries(outputFiles)[0];
126
- const patterns = config.groupMatch;
127
- const filterEndpoint = config.filterEndpoint;
128
-
129
- const pattern = patterns;
130
- // 根據路徑自動分類
131
- const groupedPaths = paths.reduce((acc, path) => {
132
- const groupName = getGroupNameFromPath(path, pattern);
133
- if (!acc[groupName]) {
134
- acc[groupName] = [];
135
- }
136
- acc[groupName].push(path);
137
- return acc;
138
- }, {} as Record<string, string[]>);
139
-
140
- // 為每個分類生成配置
141
- Object.entries(groupedPaths).forEach(([groupName, paths]) => {
142
- const finalOutputPath = outputPath.replace('$1', groupName);
143
-
144
- if (filterEndpoint) {
145
- // 如果有 filterEndpoint,使用基於路徑的篩選函數
146
- const pathBasedFilter = (operationName: string, operationDefinition: any) => {
147
- const path = operationDefinition.path;
148
-
149
- // 檢查路徑是否匹配當前分組
150
- const pathGroupName = getGroupNameFromPath(path, pattern);
151
- if (pathGroupName !== groupName) {
152
- return false;
153
- }
154
-
155
- // 使用 filterEndpoint 進行額外篩選
156
- const endpointFilter = filterEndpoint(groupName);
157
- if (endpointFilter instanceof RegExp) {
158
- return endpointFilter.test(operationName);
159
- }
160
-
161
- return true;
162
- };
163
-
164
- outFiles.push({
165
- ...commonConfig,
166
- outputFile: finalOutputPath,
167
- filterEndpoints: pathBasedFilter,
168
- });
169
- } else {
170
- // 如果沒有 filterEndpoint,只使用路徑分組
171
- const pathBasedFilter = (operationName: string, operationDefinition: any) => {
172
- const path = operationDefinition.path;
173
-
174
- // 檢查路徑是否匹配當前分組
175
- const pathGroupName = getGroupNameFromPath(path, pattern);
176
- return pathGroupName === groupName;
177
- };
178
-
179
- outFiles.push({
180
- ...commonConfig,
181
- outputFile: finalOutputPath,
182
- filterEndpoints: pathBasedFilter,
183
- });
184
- }
185
- });
186
-
37
+ for (const [outputFile, specificConfig] of Object.entries(outputFiles)) {
38
+ outFiles.push({
39
+ ...commonConfig,
40
+ ...specificConfig,
41
+ outputFile,
42
+ });
43
+ }
187
44
  } else {
188
45
  outFiles.push(fullConfig);
189
46
  }
package/src/types.ts CHANGED
@@ -142,18 +142,10 @@ export type EndpointOverrides = {
142
142
  parameterFilter: ParameterMatcher;
143
143
  }>;
144
144
 
145
- export type OutputFilesConfig = {
146
- [outputFile: string]: {
147
- groupMatch: RegExp,
148
- filterEndpoint?: (groupName: string) => RegExp
149
- }
150
- };
151
-
152
145
  export type ConfigFile =
153
146
  | Id<Require<CommonOptions & OutputFileOptions, 'outputFile'>>
154
147
  | Id<
155
148
  Omit<CommonOptions, 'outputFile'> & {
156
- // outputFiles: { [outputFile: string]: Omit<OutputFileOptions, 'outputFile'> };
157
- outputFiles: OutputFilesConfig
149
+ outputFiles: { [outputFile: string]: Omit<OutputFileOptions, 'outputFile'> };
158
150
  }
159
151
  >;