react-query-lightbase-codegen 1.6.3 → 2.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.
Files changed (52) hide show
  1. package/dist/config/loadConfig.d.ts +2 -0
  2. package/dist/config/loadConfig.js +24 -0
  3. package/dist/generator/clientGenerator.d.ts +13 -0
  4. package/dist/generator/clientGenerator.js +199 -0
  5. package/dist/generator/instanceGenerator.d.ts +1 -0
  6. package/dist/generator/instanceGenerator.js +21 -0
  7. package/dist/generator/reactQueryGenerator.d.ts +2 -0
  8. package/dist/generator/reactQueryGenerator.js +82 -0
  9. package/dist/generator/schemaGenerator.d.ts +5 -0
  10. package/dist/generator/schemaGenerator.js +116 -0
  11. package/dist/index.d.ts +5 -3
  12. package/dist/index.js +106 -4
  13. package/dist/types/config.d.ts +11 -0
  14. package/dist/types/config.js +2 -0
  15. package/dist/types.d.ts +5 -0
  16. package/dist/types.js +2 -0
  17. package/dist/utils.d.ts +31 -20
  18. package/dist/utils.js +57 -179
  19. package/package.json +54 -82
  20. package/readme.md +94 -0
  21. package/src/config/loadConfig.ts +25 -0
  22. package/src/generator/clientGenerator.ts +234 -0
  23. package/src/generator/instanceGenerator.ts +20 -0
  24. package/src/generator/reactQueryGenerator.ts +92 -0
  25. package/src/generator/schemaGenerator.ts +139 -0
  26. package/src/index.ts +78 -3
  27. package/src/types/config.ts +12 -0
  28. package/src/types.ts +5 -0
  29. package/src/utils.ts +56 -213
  30. package/README.md +0 -77
  31. package/dist/convertSwaggerFile.d.ts +0 -5
  32. package/dist/convertSwaggerFile.js +0 -26
  33. package/dist/convertSwaggerFile.js.map +0 -1
  34. package/dist/generateHooks.d.ts +0 -18
  35. package/dist/generateHooks.js +0 -444
  36. package/dist/generateHooks.js.map +0 -1
  37. package/dist/generateImports.d.ts +0 -6
  38. package/dist/generateImports.js +0 -21
  39. package/dist/generateImports.js.map +0 -1
  40. package/dist/generateSchemas.d.ts +0 -7
  41. package/dist/generateSchemas.js +0 -100
  42. package/dist/generateSchemas.js.map +0 -1
  43. package/dist/importSpecs.d.ts +0 -10
  44. package/dist/importSpecs.js +0 -127
  45. package/dist/importSpecs.js.map +0 -1
  46. package/dist/index.js.map +0 -1
  47. package/dist/utils.js.map +0 -1
  48. package/src/convertSwaggerFile.ts +0 -25
  49. package/src/generateHooks.ts +0 -538
  50. package/src/generateImports.ts +0 -32
  51. package/src/generateSchemas.ts +0 -117
  52. package/src/importSpecs.ts +0 -168
@@ -0,0 +1,234 @@
1
+ import type { OpenAPIV3 } from "openapi-types";
2
+ import type { OpenAPIConfig } from "../types/config";
3
+ import { camelCase, pascalCase, sanitizePropertyName, sanitizeTypeName, specTitle } from "../utils";
4
+
5
+ export interface OperationInfo {
6
+ method: string;
7
+ path: string;
8
+ operationId: string;
9
+ summary?: string;
10
+ description?: string;
11
+ parameters?: OpenAPIV3.ParameterObject[];
12
+ requestBody?: OpenAPIV3.RequestBodyObject;
13
+ responses: OpenAPIV3.ResponsesObject;
14
+ }
15
+
16
+ function resolveSchema(
17
+ schema: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | undefined,
18
+ spec: OpenAPIV3.Document
19
+ ): OpenAPIV3.SchemaObject | undefined {
20
+ if (!schema) return undefined;
21
+ if ("$ref" in schema) {
22
+ const index = schema.$ref.split("/").pop();
23
+ return spec.components?.schemas?.[index as string] as OpenAPIV3.SchemaObject;
24
+ }
25
+ return schema;
26
+ }
27
+
28
+ function generateAxiosMethod(operation: OperationInfo, spec: OpenAPIV3.Document): string {
29
+ const { method, path, operationId, summary, description, parameters, requestBody, responses } = operation;
30
+ // Generate JSDoc
31
+ const jsDocLines = ["/**"];
32
+ if (summary) jsDocLines.push(` * ${summary}`);
33
+ if (description) jsDocLines.push(` * ${description}`);
34
+
35
+ // Add parameter descriptions
36
+ parameters?.forEach((param) => {
37
+ const desc = param.description ? ` - ${param.description}` : "";
38
+ jsDocLines.push(
39
+ ` * @param ${param.in === "path" ? "params." : param.in === "query" ? "query." : ""}${param.name}${desc}`
40
+ );
41
+ });
42
+
43
+ if (requestBody && "description" in requestBody) {
44
+ jsDocLines.push(` * @param data - ${requestBody.description}`);
45
+ }
46
+
47
+ // Add return type description
48
+ const responseDetails = Object.entries(responses).find(([code]) => code.startsWith("2"));
49
+ if (responseDetails) {
50
+ const [code, response] = responseDetails;
51
+ const responseObj = response as OpenAPIV3.ResponseObject;
52
+ const desc = "description" in responseObj ? responseObj.description : "";
53
+ const contentType = responseObj.content?.["application/json"]?.schema;
54
+ const typeName = `${operationId}Response${code}`;
55
+
56
+ if (contentType) {
57
+ if (desc) {
58
+ jsDocLines.push(` * @returns ${desc}`);
59
+ }
60
+ jsDocLines.push(` * @see ${typeName}`);
61
+ } else if (desc) {
62
+ jsDocLines.push(` * @returns ${desc}`);
63
+ }
64
+ }
65
+
66
+ jsDocLines.push(" */");
67
+
68
+ const urlParams = parameters?.filter((p) => p.in === "path") || [];
69
+ const queryParams = parameters?.filter((p) => p.in === "query") || [];
70
+
71
+ const isFormData = requestBody && "content" in requestBody && requestBody.content?.["multipart/form-data"];
72
+
73
+ const formDataSchema = isFormData
74
+ ? resolveSchema(requestBody.content["multipart/form-data"].schema, spec)
75
+ : undefined;
76
+
77
+ const requestBodySchema = requestBody?.content?.["application/json"]?.schema
78
+ ? resolveSchema(requestBody.content["application/json"].schema, spec)
79
+ : undefined;
80
+
81
+ // Build data type parts
82
+ const dataProps: string[] = [];
83
+
84
+ // Add path and query parameters
85
+ urlParams.forEach((p) => {
86
+ const safeName = sanitizePropertyName(p.name);
87
+ dataProps.push(`${safeName}: ${getTypeFromParam(p)}`);
88
+ });
89
+ queryParams.forEach((p) => {
90
+ const safeName = sanitizePropertyName(p.name);
91
+ dataProps.push(`${safeName}${p.required ? "" : "?"}: ${getTypeFromParam(p)}`);
92
+ });
93
+
94
+ // Add request body type if it exists
95
+ const hasData = (parameters && parameters.length > 0) || operation.requestBody;
96
+
97
+ let dataType = "undefined";
98
+ const namedType = pascalCase(operationId);
99
+ if (hasData) {
100
+ if (requestBody && dataProps.length > 0) {
101
+ dataType = `T.${namedType}Request & { ${dataProps.join("; ")} }`;
102
+ } else if (requestBody) {
103
+ dataType = `T.${namedType}Request`;
104
+ } else if (dataProps.length > 0) {
105
+ dataType = `{ ${dataProps.join("; ")} }`;
106
+ } else {
107
+ dataType = "Record<string, never>";
108
+ }
109
+ }
110
+
111
+ // Get response type from 2xx response
112
+ const successResponse = Object.entries(responses).find(([code]) => code.startsWith("2"));
113
+ const responseType = successResponse ? `T.${`${namedType}Response${successResponse[0]}`}` : "any";
114
+
115
+ const urlWithParams = urlParams.length > 0 ? path.replace(/{(\w+)}/g, "${data.$1}") : path;
116
+
117
+ const methodBody = [
118
+ "const apiClient = getApiClient();",
119
+ `const url = \`${urlWithParams}\`;`,
120
+ queryParams.length > 0
121
+ ? `const queryData = {
122
+ ${queryParams.map((p) => `["${p.name}"]: data["${p.name}"]`).join(",\n ")}
123
+ };`
124
+ : "",
125
+ requestBodySchema?.properties
126
+ ? `const bodyData = {
127
+ ${Object.entries(requestBodySchema.properties)
128
+ .map(([key]) => `${key}: data.${key}`)
129
+ .join(",\n ")}
130
+ };`
131
+ : "",
132
+ formDataSchema?.properties
133
+ ? `const formData = new FormData();
134
+ ${Object.entries(formDataSchema.properties)
135
+ .map(([key, prop]) => {
136
+ const schemaProperty = prop as OpenAPIV3.SchemaObject;
137
+ const isBinary = schemaProperty.format === "binary";
138
+ return formDataSchema?.required?.includes(key)
139
+ ? `formData.append("${key}", ${isBinary ? "" : "String("}${queryParams.length > 0 ? "bodyData" : "data"}.${key}${isBinary ? "" : ")"});`
140
+ : `if (${queryParams.length > 0 ? "bodyData" : "data"}.${key} != null) {
141
+ formData.append("${key}", ${isBinary ? "" : "String("}${queryParams.length > 0 ? "bodyData" : "data"}.${key}${isBinary ? "" : ")"});
142
+ }`;
143
+ })
144
+ .join("\n ")}`
145
+ : "",
146
+ `return apiClient.${method.toLowerCase()}<${responseType}>(url, {
147
+ ${queryParams.length > 0 ? "params: queryData," : ""}
148
+ ${requestBody ? `data: ${isFormData ? "formData" : "bodyData"},` : ""}
149
+ ${isFormData ? `config: { headers: { 'Content-Type': 'multipart/form-data', ...config.headers }, ...config },` : "...config"}
150
+ });`,
151
+ ]
152
+ .filter(Boolean)
153
+ .join("\n ");
154
+
155
+ return `
156
+ ${jsDocLines.join("\n ")}
157
+ export function ${camelCase(operationId)}(data${hasData ? `: ${dataType}` : "?: undefined"}, config?: AxiosRequestConfig): Promise<AxiosResponse<${responseType}>> {
158
+ ${methodBody}
159
+ }`;
160
+ }
161
+
162
+ function getTypeFromParam(param: OpenAPIV3.ParameterObject): string {
163
+ if ("schema" in param) {
164
+ const schema = param.schema as OpenAPIV3.SchemaObject;
165
+ switch (schema.type) {
166
+ case "string":
167
+ return "string";
168
+ case "integer":
169
+ case "number":
170
+ return "number";
171
+ case "boolean":
172
+ return "boolean";
173
+ case "array":
174
+ return "Array<any>"; // You might want to make this more specific
175
+ default:
176
+ return "any";
177
+ }
178
+ }
179
+ return "any";
180
+ }
181
+
182
+ export function generateApiClient(spec: OpenAPIV3.Document, config: OpenAPIConfig): string {
183
+ const operations: OperationInfo[] = [];
184
+
185
+ const resolveParameters = (
186
+ parameters: (OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject)[]
187
+ ): OpenAPIV3.ParameterObject[] => {
188
+ return parameters.map((p) => {
189
+ if ("$ref" in p) {
190
+ const index = p.$ref.split("/").pop();
191
+ return spec.components?.schemas?.[index as string] as OpenAPIV3.ParameterObject;
192
+ }
193
+ return p;
194
+ });
195
+ };
196
+
197
+ const resolveRequestBody = (
198
+ requestBody: OpenAPIV3.RequestBodyObject | OpenAPIV3.ReferenceObject | undefined
199
+ ): OpenAPIV3.RequestBodyObject | undefined => {
200
+ if (!requestBody) return undefined;
201
+ if ("$ref" in requestBody) {
202
+ const index = requestBody.$ref.split("/").pop();
203
+ return spec.components?.schemas?.[index as string] as OpenAPIV3.RequestBodyObject;
204
+ }
205
+ return requestBody;
206
+ };
207
+
208
+ // Collect all operations
209
+ Object.entries(spec.paths || {}).forEach(([path, pathItem]) => {
210
+ if (!pathItem) return;
211
+ ["get", "post", "put", "delete", "patch"].forEach((method) => {
212
+ const operation = pathItem[method as keyof OpenAPIV3.PathItemObject] as OpenAPIV3.OperationObject;
213
+ if (!operation) return;
214
+ operations.push({
215
+ method: method.toUpperCase(),
216
+ path,
217
+ operationId: `${method}${sanitizeTypeName(operation.operationId || `${path.replace(/\W+/g, "_")}`)}`,
218
+ summary: operation.summary,
219
+ description: operation.description,
220
+ parameters: resolveParameters([...(pathItem.parameters || []), ...(operation.parameters || [])]),
221
+ requestBody: resolveRequestBody(operation.requestBody),
222
+ responses: operation.responses,
223
+ });
224
+ });
225
+ });
226
+
227
+ const title = specTitle(spec);
228
+
229
+ return `import type { AxiosResponse, AxiosRequestConfig } from 'axios';
230
+ import { getApiClient } from './apiClient';
231
+ import type * as T from './${title}.schema';
232
+
233
+ ${operations.map((op) => generateAxiosMethod(op, spec)).join("\n\n")}`;
234
+ }
@@ -0,0 +1,20 @@
1
+ import type { OpenAPIV3 } from "openapi-types";
2
+
3
+ export function generateInstance(): string {
4
+ return `import type { AxiosInstance } from 'axios';
5
+
6
+ let apiClient: AxiosInstance;
7
+
8
+ export function setApiClient(instance: AxiosInstance): void {
9
+ apiClient = instance;
10
+ }
11
+
12
+ export function getApiClient(): AxiosInstance {
13
+ if (!apiClient) {
14
+ throw new Error('API client not configured. Call setApiClient with an axios instance first.');
15
+ }
16
+ return apiClient;
17
+ }
18
+
19
+ export { apiClient };`;
20
+ }
@@ -0,0 +1,92 @@
1
+ import type { OpenAPIV3 } from "openapi-types";
2
+ import { camelCase, sanitizeTypeName, specTitle } from "../utils";
3
+ import type { OperationInfo } from "./clientGenerator";
4
+
5
+ function generateQueryOptions(operation: OperationInfo, spec: OpenAPIV3.Document): string {
6
+ const { operationId, parameters, requestBody } = operation;
7
+
8
+ const hasData = (parameters && parameters.length > 0) || operation.requestBody;
9
+
10
+ // Helper to get required fields from a schema
11
+ const getRequiredFields = (
12
+ schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject,
13
+ context: { schemas: { [key: string]: OpenAPIV3.SchemaObject } }
14
+ ): string[] => {
15
+ if ("$ref" in schema) {
16
+ const refType = schema.$ref.split("/").pop();
17
+ const refSchema = context.schemas[refType as string];
18
+ return refSchema?.required?.map((p) => `'${p}'`) || [];
19
+ }
20
+ return schema.required?.map((p) => `'${p}'`) || [];
21
+ };
22
+
23
+ // Get required parameter names from both parameters and request body
24
+ const requiredParams = [
25
+ ...(parameters?.filter((p) => p.required).map((p) => `'${p.name}'`) || []),
26
+ ...(requestBody && "content" in requestBody && requestBody.content?.["application/json"]?.schema
27
+ ? getRequiredFields(requestBody.content["application/json"].schema, {
28
+ schemas: (spec.components?.schemas as { [key: string]: OpenAPIV3.SchemaObject }) || {},
29
+ })
30
+ : []),
31
+ ...(requestBody && "content" in requestBody && requestBody.content?.["multipart/form-data"]?.schema
32
+ ? getRequiredFields(requestBody.content["multipart/form-data"].schema, {
33
+ schemas: (spec.components?.schemas as { [key: string]: OpenAPIV3.SchemaObject }) || {},
34
+ })
35
+ : []),
36
+ ];
37
+
38
+ const namedQuery = camelCase(operationId);
39
+
40
+ return `
41
+ export const ${namedQuery}QueryOptions = (
42
+ ${hasData ? `params: Partial<Parameters<typeof apiClient.${namedQuery}>[0]>, config?: Partial<Parameters<typeof apiClient.${namedQuery}>[1]>` : ""}
43
+ ) => {
44
+ const enabled = ${hasData ? `hasDefinedProps(params, ${requiredParams.join(", ")})` : "true"};
45
+ return queryOptions({
46
+ queryKey: ['${camelCase(operationId)}', ${hasData ? "params" : "undefined"}],
47
+ queryFn: enabled ? async () => {
48
+ const response = await apiClient.${namedQuery}(${hasData ? "params" : "undefined"}, config);
49
+ return response.data;
50
+ } : skipToken,
51
+ });
52
+ };`;
53
+ }
54
+
55
+ export function generateReactQuery(spec: OpenAPIV3.Document): string {
56
+ const operations: OperationInfo[] = [];
57
+
58
+ // Collect operations (same as in clientGenerator)
59
+ Object.entries(spec.paths || {}).forEach(([path, pathItem]) => {
60
+ if (!pathItem) return;
61
+
62
+ ["get", "post", "put", "delete", "patch"].forEach((method) => {
63
+ const operation = pathItem[method as keyof OpenAPIV3.PathItemObject] as OpenAPIV3.OperationObject;
64
+ if (!operation) return;
65
+ operations.push({
66
+ method: method.toUpperCase(),
67
+ path,
68
+ operationId: `${method}${sanitizeTypeName(operation.operationId || `${path.replace(/\W+/g, "_")}`)}`,
69
+ summary: operation.summary,
70
+ description: operation.description,
71
+ parameters: [
72
+ ...(pathItem.parameters || []),
73
+ ...(operation.parameters || []),
74
+ ] as OpenAPIV3.ParameterObject[],
75
+ requestBody: operation.requestBody as OpenAPIV3.RequestBodyObject,
76
+ responses: operation.responses,
77
+ });
78
+ });
79
+ });
80
+
81
+ return `import { queryOptions, skipToken } from '@tanstack/react-query';
82
+ import * as apiClient from './${specTitle(spec)}.client';
83
+ const hasDefinedProps = <T extends { [P in K]?: any }, K extends PropertyKey>(
84
+ obj: T,
85
+ ...keys: K[]
86
+ ): obj is T & { [P in K]-?: Exclude<T[P], undefined> } => {
87
+ return keys.every((k) => obj[k] !== undefined);
88
+ };
89
+
90
+ ${operations.map((op) => generateQueryOptions(op, spec)).join("\n\n")}
91
+ `;
92
+ }
@@ -0,0 +1,139 @@
1
+ import type { OpenAPIV3 } from "openapi-types";
2
+ import { camelCase, pascalCase, sanitizePropertyName, sanitizeTypeName } from "../utils";
3
+
4
+ interface SchemaContext {
5
+ schemas: { [key: string]: OpenAPIV3.SchemaObject };
6
+ generatedTypes: Set<string>;
7
+ }
8
+
9
+ /**
10
+ * Converts OpenAPI schema type to TypeScript type
11
+ */
12
+ function getTypeFromSchema(
13
+ schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject,
14
+ context: SchemaContext
15
+ ): string {
16
+ if (!schema) return "any";
17
+
18
+ if ("$ref" in schema) {
19
+ const refType = schema.$ref.split("/").pop();
20
+ return sanitizeTypeName(refType as string);
21
+ }
22
+
23
+ // Handle enum types properly
24
+ if (schema.enum) {
25
+ return schema.enum.map((e) => (typeof e === "string" ? `'${e}'` : e)).join(" | ");
26
+ }
27
+
28
+ switch (schema.type) {
29
+ case "string":
30
+ return "string";
31
+ case "number":
32
+ case "integer":
33
+ return "number";
34
+ case "boolean":
35
+ return "boolean";
36
+ case "array": {
37
+ const itemType = getTypeFromSchema(schema.items, context);
38
+ return `Array<${itemType}>`;
39
+ }
40
+ case "object":
41
+ if (schema.properties) {
42
+ const properties = Object.entries(schema.properties)
43
+ .map(([key, prop]) => {
44
+ const isRequired = schema.required?.includes(key);
45
+ const propertyType = getTypeFromSchema(prop, context);
46
+ const safeName = sanitizePropertyName(key);
47
+ return ` ${safeName}${isRequired ? "" : "?"}: ${propertyType};`;
48
+ })
49
+ .join("\n");
50
+ return `{\n${properties}\n}`;
51
+ }
52
+ if (schema.additionalProperties) {
53
+ const valueType =
54
+ typeof schema.additionalProperties === "boolean"
55
+ ? "any"
56
+ : getTypeFromSchema(schema.additionalProperties, context);
57
+ return `Record<string, ${valueType}>`;
58
+ }
59
+ return "Record<string, any>";
60
+ default:
61
+ return "any";
62
+ }
63
+ }
64
+
65
+ function generateTypeDefinition(
66
+ badName: string,
67
+ schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject,
68
+ context: SchemaContext
69
+ ): string {
70
+ const description = !("$ref" in schema) && schema.description ? `/**\n * ${schema.description}\n */\n` : "";
71
+
72
+ const name = sanitizeTypeName(badName);
73
+
74
+ const typeValue = getTypeFromSchema(schema, context);
75
+
76
+ // Use 'type' for primitives, unions, and simple types
77
+ // Use 'interface' only for complex objects with properties
78
+ const isInterface = !("$ref" in schema) && schema.type === "object" && schema.properties;
79
+ const namedInterface = pascalCase(name);
80
+ return isInterface
81
+ ? `${description}export interface ${name} ${typeValue}\n\n`
82
+ : `${description}export type ${namedInterface} = ${typeValue}\n\n`;
83
+ }
84
+
85
+ /**
86
+ * Generates TypeScript interface definitions from OpenAPI schemas
87
+ */
88
+ export function generateTypeDefinitions(spec: OpenAPIV3.Document): string {
89
+ const context: SchemaContext = {
90
+ schemas: (spec.components?.schemas as { [key: string]: OpenAPIV3.SchemaObject }) || {},
91
+ generatedTypes: new Set(),
92
+ };
93
+
94
+ let output = "/* Generated TypeScript Definitions */\n\n";
95
+
96
+ // Generate types for all schema definitions
97
+ for (const [name, schema] of Object.entries(context.schemas)) {
98
+ if (context.generatedTypes.has(name)) continue;
99
+ output += generateTypeDefinition(name, schema, context);
100
+ context.generatedTypes.add(name);
101
+ }
102
+
103
+ // Generate request/response types
104
+ if (spec.paths) {
105
+ for (const [path, pathItem] of Object.entries(spec.paths)) {
106
+ for (const [method, operation] of Object.entries(pathItem as OpenAPIV3.PathItemObject)) {
107
+ if (method === "$ref") continue;
108
+
109
+ const operationObject = operation as OpenAPIV3.OperationObject;
110
+ if (!operationObject) continue;
111
+
112
+ // Generate request body type
113
+ if (operationObject.requestBody) {
114
+ const content = (operationObject.requestBody as OpenAPIV3.RequestBodyObject).content;
115
+ const jsonContent = content["application/json"] || content["multipart/form-data"];
116
+ if (jsonContent?.schema) {
117
+ const typeName = sanitizeTypeName(`${operationObject.operationId}Request`);
118
+ output += generateTypeDefinition(typeName, jsonContent.schema as OpenAPIV3.SchemaObject, context);
119
+ }
120
+ }
121
+
122
+ // Generate response types
123
+ if (operationObject.responses) {
124
+ for (const [code, response] of Object.entries(operationObject.responses)) {
125
+ const responseObj = response as OpenAPIV3.ResponseObject;
126
+ const content = responseObj.content?.["application/json"];
127
+ if (content?.schema) {
128
+ const opName = `${method}${sanitizeTypeName(operationObject.operationId || `${path.replace(/\W+/g, "_")}`)}`;
129
+ const typeName = sanitizeTypeName(`${opName}_Response${code}`);
130
+ output += generateTypeDefinition(typeName, content.schema as OpenAPIV3.SchemaObject, context);
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+
138
+ return output;
139
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,78 @@
1
- import { convertSwaggerFile } from './convertSwaggerFile.js';
2
- import { importSpecs } from './importSpecs.js';
3
- export { importSpecs, convertSwaggerFile };
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import axios from "axios";
4
+ import type { OpenAPIV3 } from "openapi-types";
5
+ import * as yaml from "yaml";
6
+ import { generateApiClient } from "./generator/clientGenerator";
7
+ import { generateInstance } from "./generator/instanceGenerator";
8
+ import { generateReactQuery } from "./generator/reactQueryGenerator";
9
+ import { generateTypeDefinitions } from "./generator/schemaGenerator";
10
+ import type { OpenAPIConfig } from "./types/config";
11
+ import { specTitle } from "./utils";
12
+
13
+ /**
14
+ * Loads the OpenAPI specification from either a URL or local file
15
+ */
16
+ async function loadOpenAPISpec(specSource: string): Promise<OpenAPIV3.Document> {
17
+ try {
18
+ if (specSource.startsWith("http")) {
19
+ const response = await axios.get(specSource);
20
+ // Check if response is YAML by looking for common YAML indicators
21
+ const isYaml =
22
+ typeof response.data === "string" &&
23
+ (response.data.trim().startsWith("openapi:") || response.data.trim().startsWith("swagger:"));
24
+
25
+ return isYaml ? yaml.parse(response.data) : response.data;
26
+ }
27
+
28
+ const content = await readFile(specSource, "utf-8");
29
+ // Handle both JSON and YAML formats
30
+ return specSource.endsWith(".json") ? JSON.parse(content) : yaml.parse(content);
31
+ } catch (error) {
32
+ if (error instanceof Error) {
33
+ throw new Error(`Failed to load OpenAPI spec: ${error.message}`);
34
+ }
35
+ throw new Error("Failed to load OpenAPI spec: Unknown error");
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Main function to generate the API client
41
+ */
42
+ export async function codegenerate(config: OpenAPIConfig): Promise<void> {
43
+ try {
44
+ // Load specs
45
+ const specs = Array.isArray(config.specSource)
46
+ ? await Promise.all(config.specSource.map(loadOpenAPISpec))
47
+ : [await loadOpenAPISpec(config.specSource)];
48
+
49
+ // Create export directory if it doesn't exist
50
+ await mkdir(config.exportDir, { recursive: true });
51
+
52
+ // Generate and write type definitions
53
+ const instance = generateInstance();
54
+ await writeFile(resolve(config.exportDir, "apiClient.ts"), instance, "utf-8");
55
+
56
+ // Generate for each spec...
57
+ for (const spec of specs) {
58
+ const title = specTitle(spec);
59
+
60
+ // Generate and write type definitions
61
+ const typeDefinitions = generateTypeDefinitions(spec);
62
+ await writeFile(resolve(config.exportDir, `${title}.schema.ts`), typeDefinitions, "utf-8");
63
+
64
+ // Generate and write API client
65
+ const clientCode = generateApiClient(spec, config);
66
+ await writeFile(resolve(config.exportDir, `${title}.client.ts`), clientCode, "utf-8");
67
+
68
+ // Generate and write React Query options
69
+ const queryCode = generateReactQuery(spec);
70
+ await writeFile(resolve(config.exportDir, `${title}.queryOptions.ts`), queryCode, "utf-8");
71
+ }
72
+ } catch (error) {
73
+ if (error instanceof Error) {
74
+ throw new Error(`Failed to generate API client: ${error.message}`);
75
+ }
76
+ throw new Error("Failed to generate API client: Unknown error");
77
+ }
78
+ }
@@ -0,0 +1,12 @@
1
+ export interface OpenAPIConfig {
2
+ /**
3
+ * OpenAPI specification source - can be a URL or local file path
4
+ * Supports JSON, YAML, or YML formats
5
+ */
6
+ specSource: string | string[];
7
+
8
+ /**
9
+ * Directory where generated files will be exported
10
+ */
11
+ exportDir: string;
12
+ }
package/src/types.ts ADDED
@@ -0,0 +1,5 @@
1
+ export interface Config {
2
+ input: string;
3
+ output: string;
4
+ axiosInstancePath: string; // Path to the file exporting the axios instance
5
+ }