react-query-lightbase-codegen 2.5.10 → 3.0.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.
@@ -1,28 +1,13 @@
1
1
  import type { OpenAPIV3 } from "openapi-types";
2
- import { camelCase, pascalCase, sanitizeTypeName, specTitle } from "../utils";
3
-
4
- export interface OperationInfo {
5
- method: string;
6
- path: string;
7
- operationId: string;
8
- summary?: string;
9
- description?: string;
10
- parameters?: OpenAPIV3.ParameterObject[];
11
- requestBody?: OpenAPIV3.RequestBodyObject;
12
- responses: OpenAPIV3.ResponsesObject;
13
- }
14
-
15
- function resolveSchema(
16
- schema: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | undefined,
17
- spec: OpenAPIV3.Document
18
- ): OpenAPIV3.SchemaObject | undefined {
19
- if (!schema) return undefined;
20
- if ("$ref" in schema) {
21
- const index = schema.$ref.split("/").pop();
22
- return spec.components?.schemas?.[index as string] as OpenAPIV3.SchemaObject;
23
- }
24
- return schema;
25
- }
2
+ import {
3
+ type OperationInfo,
4
+ camelCase,
5
+ collectOperations,
6
+ getContentSchema,
7
+ pascalCase,
8
+ resolveSchema,
9
+ specTitle,
10
+ } from "../utils";
26
11
 
27
12
  function generateAxiosMethod(operation: OperationInfo, spec: OpenAPIV3.Document): string {
28
13
  const { method, path, operationId, summary, description, parameters, requestBody, responses } = operation;
@@ -34,9 +19,15 @@ function generateAxiosMethod(operation: OperationInfo, spec: OpenAPIV3.Document)
34
19
  // Add parameter descriptions
35
20
  parameters?.forEach((param) => {
36
21
  const desc = param.description ? ` - ${param.description}` : "";
37
- jsDocLines.push(
38
- ` * @param ${param.in === "path" ? "params." : param.in === "query" ? "query." : ""}${param.name}${desc}`
39
- );
22
+ const prefix =
23
+ param.in === "path"
24
+ ? "params."
25
+ : param.in === "query"
26
+ ? "query."
27
+ : param.in === "header"
28
+ ? "headers."
29
+ : "";
30
+ jsDocLines.push(` * @param ${prefix}${param.name}${desc}`);
40
31
  });
41
32
 
42
33
  if (requestBody && "description" in requestBody) {
@@ -49,15 +40,10 @@ function generateAxiosMethod(operation: OperationInfo, spec: OpenAPIV3.Document)
49
40
  const [code, response] = responseDetails;
50
41
  const responseObj = response as OpenAPIV3.ResponseObject;
51
42
  const desc = "description" in responseObj ? responseObj.description : "";
52
- const contentType =
53
- responseObj.content?.["application/ld+json"]?.schema ??
54
- responseObj.content?.["application/json"]?.schema ??
55
- responseObj.content?.["application/octet-stream"]?.schema ??
56
- responseObj.content?.["application/json;charset=UTF-8"]?.schema;
57
-
43
+ const contentSchema = getContentSchema(responseObj.content);
58
44
  const typeName = pascalCase(`${operationId}Response${code}`);
59
45
 
60
- if (contentType) {
46
+ if (contentSchema) {
61
47
  if (desc) {
62
48
  jsDocLines.push(` * @returns ${desc}`);
63
49
  }
@@ -79,15 +65,9 @@ function generateAxiosMethod(operation: OperationInfo, spec: OpenAPIV3.Document)
79
65
  ? resolveSchema(requestBody.content["multipart/form-data"].schema, spec)
80
66
  : undefined;
81
67
 
82
- const content =
83
- requestBody && "content" in requestBody
84
- ? (requestBody.content?.["application/ld+json"]?.schema ??
85
- requestBody.content?.["application/json"]?.schema ??
86
- requestBody.content?.["application/octet-stream"]?.schema ??
87
- requestBody.content?.["application/json;charset=UTF-8"]?.schema)
88
- : undefined;
89
-
90
- const requestBodySchema = content ? resolveSchema(content, spec) : undefined;
68
+ const requestBodyContent =
69
+ requestBody && "content" in requestBody ? getContentSchema(requestBody.content) : undefined;
70
+ const requestBodySchema = requestBodyContent ? resolveSchema(requestBodyContent, spec) : undefined;
91
71
 
92
72
  // Check if request body is a primitive type (string, number, boolean)
93
73
  const isPrimitiveRequestBody =
@@ -151,15 +131,12 @@ function generateAxiosMethod(operation: OperationInfo, spec: OpenAPIV3.Document)
151
131
  .join("\n ")}`
152
132
  : "",
153
133
  queryParams.length > 0 ? "axiosConfig.params = { ...axiosConfig.params, ...queryData };" : "",
134
+ headerParams.length > 0
135
+ ? `axiosConfig.headers = { ...axiosConfig.headers, ${headerParams.map((p) => `["${p.name}"]: data["${p.name}"]`).join(", ")} };`
136
+ : "",
154
137
  isFormData
155
138
  ? "axiosConfig.headers = { ...axiosConfig.headers, 'Content-Type': 'multipart/form-data' };"
156
139
  : "",
157
- headerParams.length > 0
158
- ? `const headerData = {
159
- ${headerParams.map((p) => `["${p.name}"]: data["${p.name}"]`).join(",\n ")}
160
- };`
161
- : "",
162
- headerParams.length > 0 ? "axiosConfig.headers = { ...axiosConfig.headers, ...headerData };" : "",
163
140
  requestBody
164
141
  ? `const res = await apiClient.${method}<${responseType}>(url, ${formDataSchema?.properties || requestBodySchema?.properties ? "bodyData" : "data"}, axiosConfig);`
165
142
  : `const res = await apiClient.${method}<${responseType}>(url, axiosConfig);`,
@@ -168,10 +145,6 @@ function generateAxiosMethod(operation: OperationInfo, spec: OpenAPIV3.Document)
168
145
  .filter(Boolean)
169
146
  .join("\n ");
170
147
 
171
- // ${queryParams.length > 0 ? "params: queryData," : ""}
172
- // ${requestBody ? `data: ${isFormData ? "formData" : "bodyData"},` : ""}
173
- // ${isFormData ? `config: { headers: { 'Content-Type': 'multipart/form-data', ...axiosConfig?.headers }, ...axiosConfig },` : "...axiosConfig"}
174
-
175
148
  const requestParms = hasData
176
149
  ? isPrimitiveRequestBody
177
150
  ? `props: { data: T.${pascalCase(operationId)}Params; axiosConfig?: AxiosRequestConfig; }`
@@ -186,53 +159,10 @@ function generateAxiosMethod(operation: OperationInfo, spec: OpenAPIV3.Document)
186
159
  }
187
160
 
188
161
  export function generateApiClient(spec: OpenAPIV3.Document): string {
189
- const operations: OperationInfo[] = [];
190
-
191
- const resolveParameters = (
192
- parameters: (OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject)[]
193
- ): OpenAPIV3.ParameterObject[] => {
194
- return parameters.map((p) => {
195
- if ("$ref" in p) {
196
- const index = p.$ref.split("/").pop();
197
- return spec.components?.schemas?.[index as string] as OpenAPIV3.ParameterObject;
198
- }
199
- return p;
200
- });
201
- };
202
-
203
- const resolveRequestBody = (
204
- requestBody: OpenAPIV3.RequestBodyObject | OpenAPIV3.ReferenceObject | undefined
205
- ): OpenAPIV3.RequestBodyObject | undefined => {
206
- if (!requestBody) return undefined;
207
- if ("$ref" in requestBody) {
208
- const index = requestBody.$ref.split("/").pop();
209
- return spec.components?.schemas?.[index as string] as OpenAPIV3.RequestBodyObject;
210
- }
211
- return requestBody;
212
- };
213
-
214
- // Collect all operations
215
- Object.entries(spec.paths || {}).forEach(([path, pathItem]) => {
216
- if (!pathItem) return;
217
- ["get", "post", "put", "delete", "patch"].forEach((method) => {
218
- const operation = pathItem[method as keyof OpenAPIV3.PathItemObject] as OpenAPIV3.OperationObject;
219
- if (!operation) return;
220
- operations.push({
221
- method: method,
222
- path,
223
- operationId: `${sanitizeTypeName(operation.operationId || `${path.replace(/\W+/g, "_")}`)}`,
224
- summary: operation.summary,
225
- description: operation.description,
226
- parameters: resolveParameters([...(pathItem.parameters || []), ...(operation.parameters || [])]),
227
- requestBody: resolveRequestBody(operation.requestBody),
228
- responses: operation.responses,
229
- });
230
- });
231
- });
232
-
162
+ const operations = collectOperations(spec);
233
163
  const title = specTitle(spec);
234
164
 
235
- return `import type { AxiosResponse, AxiosRequestConfig } from 'axios';
165
+ return `import type { AxiosRequestConfig } from 'axios';
236
166
  import { getApiClient } from './apiClient';
237
167
  import type * as T from './${title}.schema';
238
168
 
@@ -1,21 +1,15 @@
1
1
  import type { OpenAPIV3 } from "openapi-types";
2
- import { camelCase, sanitizeTypeName, specTitle } from "../utils";
3
- import type { OperationInfo } from "./clientGenerator";
4
-
5
- function resolveSchema(
6
- schema: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | undefined,
7
- spec: OpenAPIV3.Document
8
- ): OpenAPIV3.SchemaObject | undefined {
9
- if (!schema) return undefined;
10
- if ("$ref" in schema) {
11
- const index = schema.$ref.split("/").pop();
12
- return spec.components?.schemas?.[index as string] as OpenAPIV3.SchemaObject;
13
- }
14
- return schema;
15
- }
2
+ import {
3
+ type OperationInfo,
4
+ camelCase,
5
+ collectOperations,
6
+ getContentSchema,
7
+ resolveSchema,
8
+ specTitle,
9
+ } from "../utils";
16
10
 
17
11
  function generateQueryOptions(operation: OperationInfo, spec: OpenAPIV3.Document): string {
18
- const { operationId, parameters, requestBody, method } = operation;
12
+ const { operationId, parameters, requestBody } = operation;
19
13
 
20
14
  const hasData = (parameters && parameters.length > 0) || operation.requestBody;
21
15
 
@@ -32,13 +26,7 @@ function generateQueryOptions(operation: OperationInfo, spec: OpenAPIV3.Document
32
26
  return schema.required?.map((p) => `'${p}'`) || [];
33
27
  };
34
28
 
35
- const content =
36
- requestBody && "content" in requestBody
37
- ? (requestBody.content?.["application/ld+json"]?.schema ??
38
- requestBody.content?.["application/json"]?.schema ??
39
- requestBody.content?.["application/octet-stream"]?.schema)
40
- : undefined;
41
-
29
+ const content = requestBody && "content" in requestBody ? getContentSchema(requestBody.content) : undefined;
42
30
  const requestBodySchema = content ? resolveSchema(content, spec) : undefined;
43
31
 
44
32
  // Check if request body is a primitive type (string, number, boolean)
@@ -104,30 +92,7 @@ export const ${namedQueryOptions} = (
104
92
  }
105
93
 
106
94
  export function generateReactQuery(spec: OpenAPIV3.Document): string {
107
- const operations: OperationInfo[] = [];
108
-
109
- // Collect operations (same as in clientGenerator)
110
- Object.entries(spec.paths || {}).forEach(([path, pathItem]) => {
111
- if (!pathItem) return;
112
-
113
- ["get", "post", "put", "delete", "patch"].forEach((method) => {
114
- const operation = pathItem[method as keyof OpenAPIV3.PathItemObject] as OpenAPIV3.OperationObject;
115
- if (!operation) return;
116
- operations.push({
117
- method: method,
118
- path,
119
- operationId: sanitizeTypeName(`${operation.operationId || `${path.replace(/\W+/g, "_")}`}`),
120
- summary: operation.summary,
121
- description: operation.description,
122
- parameters: [
123
- ...(pathItem.parameters || []),
124
- ...(operation.parameters || []),
125
- ] as OpenAPIV3.ParameterObject[],
126
- requestBody: operation.requestBody as OpenAPIV3.RequestBodyObject,
127
- responses: operation.responses,
128
- });
129
- });
130
- });
95
+ const operations = collectOperations(spec);
131
96
 
132
97
  return `import { queryOptions, skipToken } from '@tanstack/react-query';
133
98
  import * as apiClient from './${specTitle(spec)}.client';
@@ -1,9 +1,27 @@
1
1
  import type { OpenAPIV3 } from "openapi-types";
2
- import { getTypeFromSchema, pascalCase, sanitizePropertyName, sanitizeTypeName } from "../utils";
2
+ import {
3
+ getContentSchema,
4
+ getTypeFromSchema,
5
+ pascalCase,
6
+ sanitizePropertyName,
7
+ sanitizeTypeName,
8
+ } from "../utils";
3
9
 
4
- interface SchemaContext {
5
- schemas: { [key: string]: OpenAPIV3.SchemaObject };
6
- generatedTypes: Set<string>;
10
+ /**
11
+ * Formats a parameter as a TypeScript property string with optional JSDoc.
12
+ */
13
+ function formatParamProperty(param: OpenAPIV3.ParameterObject, forceRequired = false): string {
14
+ const safeName = sanitizePropertyName(param.name);
15
+ const isDeprecated = param.deprecated;
16
+ const hasDescription = param.description;
17
+ const isOptional = forceRequired ? false : !param.required;
18
+
19
+ const desc =
20
+ hasDescription || isDeprecated
21
+ ? `/**${hasDescription ? `\n * ${param.description}` : ""}${isDeprecated ? "\n * @deprecated" : ""}\n */\n`
22
+ : "";
23
+
24
+ return `${desc}${safeName}${isOptional ? "?" : ""}: ${getTypeFromSchema(param.schema)}`;
7
25
  }
8
26
 
9
27
  function generateTypeDefinition(
@@ -26,18 +44,16 @@ function generateTypeDefinition(
26
44
  * Generates TypeScript interface definitions from OpenAPI schemas
27
45
  */
28
46
  export function generateTypeDefinitions(spec: OpenAPIV3.Document): string {
29
- const context: SchemaContext = {
30
- schemas: (spec.components?.schemas as { [key: string]: OpenAPIV3.SchemaObject }) || {},
31
- generatedTypes: new Set(),
32
- };
47
+ const schemas = (spec.components?.schemas as { [key: string]: OpenAPIV3.SchemaObject }) || {};
48
+ const generatedTypes = new Set<string>();
33
49
 
34
50
  let output = "/* Generated TypeScript Definitions */\n\n";
35
51
 
36
52
  // Generate types for all schema definitions
37
- for (const [name, schema] of Object.entries(context.schemas)) {
38
- if (context.generatedTypes.has(name)) continue;
53
+ for (const [name, schema] of Object.entries(schemas)) {
54
+ if (generatedTypes.has(name)) continue;
39
55
  output += generateTypeDefinition(name, schema);
40
- context.generatedTypes.add(name);
56
+ generatedTypes.add(name);
41
57
  }
42
58
 
43
59
  // Generate request/response types
@@ -54,34 +70,36 @@ export function generateTypeDefinitions(spec: OpenAPIV3.Document): string {
54
70
  // Generate request body type
55
71
  if (requestBody) {
56
72
  const content = (requestBody as OpenAPIV3.RequestBodyObject).content;
57
- const jsonContent =
58
- content["application/ld+json"] ??
59
- content["application/json"] ??
60
- content["multipart/form-data"] ??
61
- content["application/octet-stream"] ??
62
- content["application/json;charset=UTF-8"];
63
- if (jsonContent?.schema) {
73
+ const requestSchema = getContentSchema(content);
74
+ if (requestSchema) {
64
75
  const typeName = `${operationId}Request`;
65
- output += generateTypeDefinition(typeName, jsonContent.schema as OpenAPIV3.SchemaObject);
76
+ output += generateTypeDefinition(typeName, requestSchema as OpenAPIV3.SchemaObject);
66
77
  }
67
78
  }
68
79
 
69
80
  // Generate response types
81
+ const errorTypes: string[] = [];
70
82
  if (responses) {
71
83
  for (const [code, response] of Object.entries(responses)) {
72
84
  const responseObj = response as OpenAPIV3.ResponseObject;
73
- const content =
74
- responseObj.content?.["application/ld+json"] ??
75
- responseObj.content?.["application/json"] ??
76
- responseObj.content?.["application/octet-stream"] ??
77
- responseObj.content?.["application/json;charset=UTF-8"];
78
- if (content?.schema) {
85
+ const responseSchema = getContentSchema(responseObj.content);
86
+ if (responseSchema) {
79
87
  const typeName = `${operationId}Response${code}`;
80
- output += generateTypeDefinition(typeName, content.schema as OpenAPIV3.SchemaObject);
88
+ output += generateTypeDefinition(typeName, responseSchema as OpenAPIV3.SchemaObject);
89
+
90
+ // Track non-2xx responses for error union type
91
+ if (!code.startsWith("2")) {
92
+ errorTypes.push(typeName);
93
+ }
81
94
  }
82
95
  }
83
96
  }
84
97
 
98
+ // Generate error union type if there are error responses
99
+ if (errorTypes.length > 0) {
100
+ output += `export type ${pascalCase(operationId)}Error = ${errorTypes.join(" | ")};\n\n`;
101
+ }
102
+
85
103
  // Build data type parts
86
104
  const dataProps: string[] = [];
87
105
 
@@ -92,42 +110,10 @@ export function generateTypeDefinitions(spec: OpenAPIV3.Document): string {
92
110
  const headerParams = (parameters?.filter((p) => "in" in p && p.in === "header") ||
93
111
  []) as OpenAPIV3.ParameterObject[];
94
112
 
95
- // Add path and query parameters
96
- urlParams.forEach((p) => {
97
- const safeName = sanitizePropertyName(p.name);
98
- const isDeprecated = "deprecated" in p && p.deprecated;
99
- const hasDescription = "description" in p && p.description;
100
- const desc =
101
- hasDescription || isDeprecated
102
- ? `/**${hasDescription ? `\n* ${p.description}` : ""}${isDeprecated ? "\n* @deprecated" : ""}
103
- */\n`
104
- : "";
105
- dataProps.push(`${desc}${safeName}: ${getTypeFromSchema(p.schema)}`);
106
- });
107
-
108
- queryParams.forEach((p) => {
109
- const safeName = sanitizePropertyName(p.name);
110
- const isDeprecated = "deprecated" in p && p.deprecated;
111
- const hasDescription = "description" in p && p.description;
112
- const desc =
113
- hasDescription || isDeprecated
114
- ? `\n/**${hasDescription ? `\n* ${p.description}` : ""}${isDeprecated ? "\n* @deprecated" : ""}
115
- */\n`
116
- : "";
117
- dataProps.push(`${desc}${safeName}${p.required ? "" : "?"}: ${getTypeFromSchema(p.schema)}`);
118
- });
119
-
120
- headerParams.forEach((p) => {
121
- const safeName = sanitizePropertyName(p.name);
122
- const isDeprecated = "deprecated" in p && p.deprecated;
123
- const hasDescription = "description" in p && p.description;
124
- const desc =
125
- hasDescription || isDeprecated
126
- ? `\n/**${hasDescription ? `\n* ${p.description}` : ""}${isDeprecated ? "\n* @deprecated" : ""}
127
- */\n`
128
- : "";
129
- dataProps.push(`${desc}${safeName}${p.required ? "" : "?"}: ${getTypeFromSchema(p.schema)}`);
130
- });
113
+ // Add path, query, and header parameters
114
+ urlParams.forEach((p) => dataProps.push(formatParamProperty(p, true))); // Path params always required
115
+ queryParams.forEach((p) => dataProps.push(formatParamProperty(p)));
116
+ headerParams.forEach((p) => dataProps.push(formatParamProperty(p)));
131
117
 
132
118
  // Add request body type if it exists
133
119
  const hasData = (parameters && parameters.length > 0) || requestBody;
package/src/utils.ts CHANGED
@@ -1,5 +1,115 @@
1
1
  import type { OpenAPIV3 } from "openapi-types";
2
2
 
3
+ /**
4
+ * Supported content types in order of preference
5
+ */
6
+ export const CONTENT_TYPES = [
7
+ "application/ld+json",
8
+ "application/json",
9
+ "multipart/form-data",
10
+ "application/octet-stream",
11
+ "application/json;charset=UTF-8",
12
+ ] as const;
13
+
14
+ /**
15
+ * Resolves a schema reference to its actual schema object.
16
+ * If the schema is already a concrete schema (not a $ref), returns it as-is.
17
+ */
18
+ export function resolveSchema(
19
+ schema: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | undefined,
20
+ spec: OpenAPIV3.Document
21
+ ): OpenAPIV3.SchemaObject | undefined {
22
+ if (!schema) return undefined;
23
+ if ("$ref" in schema) {
24
+ const index = schema.$ref.split("/").pop();
25
+ return spec.components?.schemas?.[index as string] as OpenAPIV3.SchemaObject;
26
+ }
27
+ return schema;
28
+ }
29
+
30
+ /**
31
+ * Extracts the schema from a content object, checking supported content types in order.
32
+ */
33
+ export function getContentSchema(
34
+ content: { [media: string]: OpenAPIV3.MediaTypeObject } | undefined
35
+ ): OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined {
36
+ if (!content) return undefined;
37
+ for (const type of CONTENT_TYPES) {
38
+ if (content[type]?.schema) {
39
+ return content[type].schema;
40
+ }
41
+ }
42
+ return undefined;
43
+ }
44
+
45
+ /**
46
+ * Operation info extracted from OpenAPI paths
47
+ */
48
+ export interface OperationInfo {
49
+ method: string;
50
+ path: string;
51
+ operationId: string;
52
+ summary?: string;
53
+ description?: string;
54
+ parameters: OpenAPIV3.ParameterObject[];
55
+ requestBody?: OpenAPIV3.RequestBodyObject;
56
+ responses: OpenAPIV3.ResponsesObject;
57
+ }
58
+
59
+ const HTTP_METHODS = ["get", "post", "put", "delete", "patch"] as const;
60
+
61
+ /**
62
+ * Collects all operations from an OpenAPI spec, resolving parameter and request body references.
63
+ */
64
+ export function collectOperations(spec: OpenAPIV3.Document): OperationInfo[] {
65
+ const operations: OperationInfo[] = [];
66
+
67
+ const resolveParameters = (
68
+ parameters: (OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject)[]
69
+ ): OpenAPIV3.ParameterObject[] => {
70
+ return parameters.map((p) => {
71
+ if ("$ref" in p) {
72
+ const index = p.$ref.split("/").pop();
73
+ return spec.components?.parameters?.[index as string] as OpenAPIV3.ParameterObject;
74
+ }
75
+ return p;
76
+ });
77
+ };
78
+
79
+ const resolveRequestBody = (
80
+ requestBody: OpenAPIV3.RequestBodyObject | OpenAPIV3.ReferenceObject | undefined
81
+ ): OpenAPIV3.RequestBodyObject | undefined => {
82
+ if (!requestBody) return undefined;
83
+ if ("$ref" in requestBody) {
84
+ const index = requestBody.$ref.split("/").pop();
85
+ return spec.components?.requestBodies?.[index as string] as OpenAPIV3.RequestBodyObject;
86
+ }
87
+ return requestBody;
88
+ };
89
+
90
+ Object.entries(spec.paths || {}).forEach(([path, pathItem]) => {
91
+ if (!pathItem) return;
92
+
93
+ HTTP_METHODS.forEach((method) => {
94
+ const operation = pathItem[method] as OpenAPIV3.OperationObject | undefined;
95
+ if (!operation) return;
96
+
97
+ operations.push({
98
+ method,
99
+ path,
100
+ operationId: sanitizeTypeName(operation.operationId || path.replace(/\W+/g, "_")),
101
+ summary: operation.summary,
102
+ description: operation.description,
103
+ parameters: resolveParameters([...(pathItem.parameters || []), ...(operation.parameters || [])]),
104
+ requestBody: resolveRequestBody(operation.requestBody),
105
+ responses: operation.responses,
106
+ });
107
+ });
108
+ });
109
+
110
+ return operations;
111
+ }
112
+
3
113
  export function camelCase(str: string): string {
4
114
  return str
5
115
  .replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase())
@@ -63,7 +173,9 @@ export function specTitle(spec: OpenAPIV3.Document): string {
63
173
  * Handles:
64
174
  * - References ($ref) by extracting the type name
65
175
  * - Nullable types by appending "| null"
176
+ * - Composition types (allOf → intersection, oneOf/anyOf → union)
66
177
  * - Enums by creating union types of the values
178
+ * - OneOf schemas as union types
67
179
  * - Basic types (string, number, boolean)
68
180
  * - Binary format strings as a union with file metadata object
69
181
  * - Arrays by recursively getting the item type
@@ -71,7 +183,7 @@ export function specTitle(spec: OpenAPIV3.Document): string {
71
183
  * - Objects with additionalProperties as Records
72
184
  * - Fallback to "any" for unknown types
73
185
  *
74
- * @param param - The OpenAPI schema/parameter object to convert
186
+ * @param schema - The OpenAPI schema/parameter object to convert
75
187
  * @returns The TypeScript type as a string
76
188
  */
77
189
  export function getTypeFromSchema(
@@ -87,6 +199,30 @@ export function getTypeFromSchema(
87
199
  // Add "| null" for nullable types
88
200
  const nullable = "nullable" in schema && schema.nullable ? " | null" : "";
89
201
 
202
+ // Handle allOf (intersection types)
203
+ if ("allOf" in schema && schema.allOf) {
204
+ const types = schema.allOf.map((s) => getTypeFromSchema(s)).filter(Boolean) as string[];
205
+ if (types.length === 0) return "any";
206
+ const result = types.length === 1 ? types[0] : `(${types.join(" & ")})`;
207
+ return `${result}${nullable}`;
208
+ }
209
+
210
+ // Handle oneOf (union types - exactly one)
211
+ if ("oneOf" in schema && schema.oneOf) {
212
+ const types = schema.oneOf.map((s) => getTypeFromSchema(s)).filter(Boolean) as string[];
213
+ if (types.length === 0) return "any";
214
+ const result = types.length === 1 ? types[0] : `(${types.join(" | ")})`;
215
+ return `${result}${nullable}`;
216
+ }
217
+
218
+ // Handle anyOf (union types - one or more)
219
+ if ("anyOf" in schema && schema.anyOf) {
220
+ const types = schema.anyOf.map((s) => getTypeFromSchema(s)).filter(Boolean) as string[];
221
+ if (types.length === 0) return "any";
222
+ const result = types.length === 1 ? types[0] : `(${types.join(" | ")})`;
223
+ return `${result}${nullable}`;
224
+ }
225
+
90
226
  // Handle enums as union types
91
227
  if ("enum" in schema && schema.enum) {
92
228
  if (Object.values(schema.enum)?.length > 0) {
@@ -134,8 +270,7 @@ export function getTypeFromSchema(
134
270
  const hasDescription = "description" in prop && prop.description;
135
271
  const desc =
136
272
  hasDescription || isDeprecated
137
- ? `/**${hasDescription ? `\n* ${prop.description}` : ""}${isDeprecated ? "\n* @deprecated" : ""}
138
- */\n`
273
+ ? `/**${hasDescription ? `\n * ${prop.description}` : ""}${isDeprecated ? "\n * @deprecated" : ""}\n */\n`
139
274
  : "";
140
275
  return `${desc}${safeName}${isRequired ? "" : "?"}: ${propertyType};`;
141
276
  })