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

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
@@ -117,6 +117,7 @@ export async function generateApi(
117
117
  useEnumType = false,
118
118
  mergeReadWriteOnly = false,
119
119
  httpResolverOptions,
120
+ sharedTypesFile,
120
121
  }: GenerationOptions
121
122
  ) {
122
123
  const v3Doc = (v3DocCache[spec] ??= await getV3Doc(spec, httpResolverOptions));
@@ -127,6 +128,48 @@ export async function generateApi(
127
128
  mergeReadWriteOnly,
128
129
  });
129
130
 
131
+ // 如果提供了 sharedTypesFile,則將 components 輸出到該文件
132
+ if (sharedTypesFile) {
133
+ const components = v3Doc.components;
134
+ if (components) {
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);
148
+ return factory.createTypeAliasDeclaration(
149
+ [factory.createModifier(ts.SyntaxKind.ExportKeyword)],
150
+ factory.createIdentifier(name),
151
+ undefined,
152
+ typeNode
153
+ );
154
+ });
155
+ });
156
+
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
+ );
166
+
167
+ // 寫入文件
168
+ const fs = await import('node:fs/promises');
169
+ await fs.writeFile(sharedTypesFile, output, 'utf-8');
170
+ }
171
+ }
172
+
130
173
  // temporary workaround for https://github.com/oazapfts/oazapfts/issues/491
131
174
  if (apiGen.spec.components?.schemas) {
132
175
  apiGen.preprocessComponents(apiGen.spec.components.schemas);
@@ -160,8 +203,17 @@ export async function generateApi(
160
203
  apiFile = apiFile.replace(/\\/g, '/');
161
204
  if (!apiFile.startsWith('.')) apiFile = `./${apiFile}`;
162
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
+ }
163
212
  }
164
213
  apiFile = apiFile.replace(/\.[jt]sx?$/, '');
214
+ if (sharedTypesFile) {
215
+ sharedTypesFile = sharedTypesFile.replace(/\.[jt]sx?$/, '');
216
+ }
165
217
 
166
218
  return printer.printNode(
167
219
  ts.EmitHint.Unspecified,
@@ -169,6 +221,18 @@ export async function generateApi(
169
221
  [
170
222
  generateImportNode(apiFile, { [apiImport]: 'api' }),
171
223
  generateImportNode('@acrool/react-fetcher', { IRestFulEndpointsQueryReturn: 'IRestFulEndpointsQueryReturn' }),
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
+ ] : []),
172
236
  ...(tag ? [generateTagTypes({ addTagTypes: extractAllTagTypes({ operationDefinitions }) })] : []),
173
237
  generateCreateApiCall({
174
238
  tag,
@@ -188,8 +252,7 @@ export async function generateApi(
188
252
  factory.createIdentifier(generatedApiName)
189
253
  ),
190
254
  ...Object.values(interfaces),
191
- ...apiGen.aliases,
192
- ...apiGen.enumAliases,
255
+ ...(sharedTypesFile ? [] : [...apiGen.aliases, ...apiGen.enumAliases]),
193
256
  ...(hooks
194
257
  ? [
195
258
  generateReactHooks({
@@ -239,16 +302,54 @@ export async function generateApi(
239
302
 
240
303
  const returnsJson = apiGen.getResponseType(responses) === 'json';
241
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
+
242
339
  if (returnsJson) {
243
340
  const returnTypes = Object.entries(responses || {})
244
341
  .map(
245
- ([code, response]) =>
246
- [
247
- code,
248
- apiGen.resolve(response),
249
- apiGen.getTypeFromResponse(response, 'readOnly') ||
250
- factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
251
- ] 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
+ }
252
353
  )
253
354
  .filter(([status, response]) =>
254
355
  isDataResponse(status, includeDefault, apiGen.resolve(response), responses || {})
@@ -308,22 +409,11 @@ export async function generateApi(
308
409
  return name;
309
410
  }
310
411
 
311
- for (const param of parameters) {
312
- const name = generateName(param.name, param.in);
313
- queryArg[name] = {
314
- origin: 'param',
315
- name,
316
- originalName: param.name,
317
- type: apiGen.getTypeFromSchema(isReference(param) ? param : param.schema, undefined, 'writeOnly'),
318
- required: param.required,
319
- param,
320
- };
321
- }
322
-
323
412
  if (requestBody) {
324
413
  const body = apiGen.resolve(requestBody);
325
414
  const schema = apiGen.getSchemaFromContent(body.content);
326
- const type = apiGen.getTypeFromSchema(schema);
415
+ const type = replaceReferences(schema);
416
+
327
417
  const schemaName = camelCase(
328
418
  (type as any).name ||
329
419
  getReferenceName(schema) ||
@@ -336,12 +426,27 @@ export async function generateApi(
336
426
  origin: 'body',
337
427
  name,
338
428
  originalName: schemaName,
339
- type: apiGen.getTypeFromSchema(schema, undefined, 'writeOnly'),
429
+ type,
340
430
  required: true,
341
431
  body,
342
432
  };
343
433
  }
344
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
+
345
450
  const propertyName = (name: string | ts.PropertyName): ts.PropertyName => {
346
451
  if (typeof name === 'string') {
347
452
  return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
package/src/types.ts CHANGED
@@ -132,6 +132,7 @@ export interface OutputFileOptions extends Partial<CommonOptions> {
132
132
  * If passed as true it will generate TS enums instead of union of strings
133
133
  */
134
134
  useEnumType?: boolean;
135
+ sharedTypesFile?: string;
135
136
  }
136
137
 
137
138
  export type EndpointOverrides = {