@acrool/rtk-query-codegen-openapi 0.0.2-test.4 → 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,
@@ -182,20 +246,13 @@ export async function generateApi(
182
246
  true
183
247
  ),
184
248
  }),
185
- factory.createExportDeclaration(
249
+ factory.createExportAssignment(
186
250
  undefined,
187
- false,
188
- factory.createNamedExports([
189
- factory.createExportSpecifier(
190
- factory.createIdentifier(generatedApiName),
191
- factory.createIdentifier(exportName)
192
- ),
193
- ]),
194
- undefined
251
+ undefined,
252
+ factory.createIdentifier(generatedApiName)
195
253
  ),
196
254
  ...Object.values(interfaces),
197
- ...apiGen.aliases,
198
- ...apiGen.enumAliases,
255
+ ...(sharedTypesFile ? [] : [...apiGen.aliases, ...apiGen.enumAliases]),
199
256
  ...(hooks
200
257
  ? [
201
258
  generateReactHooks({
@@ -245,16 +302,54 @@ export async function generateApi(
245
302
 
246
303
  const returnsJson = apiGen.getResponseType(responses) === 'json';
247
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
+
248
339
  if (returnsJson) {
249
340
  const returnTypes = Object.entries(responses || {})
250
341
  .map(
251
- ([code, response]) =>
252
- [
253
- code,
254
- apiGen.resolve(response),
255
- apiGen.getTypeFromResponse(response, 'readOnly') ||
256
- factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
257
- ] 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
+ }
258
353
  )
259
354
  .filter(([status, response]) =>
260
355
  isDataResponse(status, includeDefault, apiGen.resolve(response), responses || {})
@@ -314,22 +409,11 @@ export async function generateApi(
314
409
  return name;
315
410
  }
316
411
 
317
- for (const param of parameters) {
318
- const name = generateName(param.name, param.in);
319
- queryArg[name] = {
320
- origin: 'param',
321
- name,
322
- originalName: param.name,
323
- type: apiGen.getTypeFromSchema(isReference(param) ? param : param.schema, undefined, 'writeOnly'),
324
- required: param.required,
325
- param,
326
- };
327
- }
328
-
329
412
  if (requestBody) {
330
413
  const body = apiGen.resolve(requestBody);
331
414
  const schema = apiGen.getSchemaFromContent(body.content);
332
- const type = apiGen.getTypeFromSchema(schema);
415
+ const type = replaceReferences(schema);
416
+
333
417
  const schemaName = camelCase(
334
418
  (type as any).name ||
335
419
  getReferenceName(schema) ||
@@ -342,12 +426,27 @@ export async function generateApi(
342
426
  origin: 'body',
343
427
  name,
344
428
  originalName: schemaName,
345
- type: apiGen.getTypeFromSchema(schema, undefined, 'writeOnly'),
429
+ type,
346
430
  required: true,
347
431
  body,
348
432
  };
349
433
  }
350
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
+
351
450
  const propertyName = (name: string | ts.PropertyName): ts.PropertyName => {
352
451
  if (typeof name === 'string') {
353
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 = {