@7nohe/openapi-react-query-codegen 2.2.0 → 3.0.0-beta.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.
@@ -0,0 +1,51 @@
1
+ import { StructureKind, VariableDeclarationKind, } from "ts-morph";
2
+ /**
3
+ * Get the error type string based on client type.
4
+ */
5
+ function getErrorType(op, ctx) {
6
+ const errorTypeName = `${op.capitalizedMethodName}Error`;
7
+ // Operations without error responses have no generated Error type
8
+ const errorType = ctx.modelNames.includes(errorTypeName)
9
+ ? errorTypeName
10
+ : "unknown";
11
+ if (ctx.client === "@hey-api/client-axios") {
12
+ return `AxiosError<${errorType}>`;
13
+ }
14
+ return errorType;
15
+ }
16
+ /**
17
+ * Build useMutation hook.
18
+ * Example:
19
+ * export const useAddPet = <TData = Common.AddPetMutationResult, TError = AddPetError, TQueryKey extends Array<unknown> = unknown[], TContext = unknown>(
20
+ * mutationKey?: TQueryKey,
21
+ * options?: Omit<UseMutationOptions<TData, TError, Options<AddPetData, true>, TContext>, "mutationKey" | "mutationFn">
22
+ * ) => useMutation<TData, TError, Options<AddPetData, true>, TContext>({
23
+ * mutationKey: Common.UseAddPetKeyFn(mutationKey),
24
+ * mutationFn: clientOptions => addPet(clientOptions) as unknown as Promise<TData>,
25
+ * ...options
26
+ * });
27
+ */
28
+ export function buildUseMutationHook(op, ctx) {
29
+ const hookName = `use${op.capitalizedMethodName}`;
30
+ const errorType = getErrorType(op, ctx);
31
+ const dataTypeDefault = `Common.${op.capitalizedMethodName}MutationResult`;
32
+ const dataTypeName = ctx.modelNames.includes(`${op.capitalizedMethodName}Data`)
33
+ ? `${op.capitalizedMethodName}Data`
34
+ : "unknown";
35
+ const optionsType = `Options<${dataTypeName}, true>`;
36
+ const mutationFn = `clientOptions => ${op.methodName}(clientOptions) as unknown as Promise<TData>`;
37
+ const body = `useMutation<TData, TError, ${optionsType}, TContext>({ mutationKey: Common.Use${op.capitalizedMethodName}KeyFn(mutationKey), mutationFn: ${mutationFn}, ...options })`;
38
+ return {
39
+ kind: StructureKind.VariableStatement,
40
+ // Copy the operation's JSDoc (description and @deprecated) from the SDK function
41
+ leadingTrivia: op.jsDoc ? `${op.jsDoc}\n` : undefined,
42
+ isExported: true,
43
+ declarationKind: VariableDeclarationKind.Const,
44
+ declarations: [
45
+ {
46
+ name: hookName,
47
+ initializer: `<TData = ${dataTypeDefault}, TError = ${errorType}, TQueryKey extends Array<unknown> = unknown[], TContext = unknown>(mutationKey?: TQueryKey, options?: Omit<UseMutationOptions<TData, TError, ${optionsType}, TContext>, "mutationKey" | "mutationFn">) => ${body}`,
48
+ },
49
+ ],
50
+ };
51
+ }
@@ -0,0 +1,246 @@
1
+ import { StructureKind, VariableDeclarationKind, } from "ts-morph";
2
+ /**
3
+ * Get the error type string based on client type.
4
+ */
5
+ function getErrorType(op, ctx) {
6
+ const errorTypeName = `${op.capitalizedMethodName}Error`;
7
+ // Operations without error responses have no generated Error type
8
+ const errorType = ctx.modelNames.includes(errorTypeName)
9
+ ? errorTypeName
10
+ : "unknown";
11
+ if (ctx.client === "@hey-api/client-axios") {
12
+ return `AxiosError<${errorType}>`;
13
+ }
14
+ return errorType;
15
+ }
16
+ /**
17
+ * Get the data type based on hook type.
18
+ */
19
+ function getDataTypeDefault(op, hookType) {
20
+ const baseType = `Common.${op.capitalizedMethodName}DefaultResponse`;
21
+ if (hookType === "useSuspenseQuery") {
22
+ return `NonNullable<${baseType}>`;
23
+ }
24
+ if (hookType === "useInfiniteQuery") {
25
+ return `InfiniteData<${baseType}>`;
26
+ }
27
+ return baseType;
28
+ }
29
+ /**
30
+ * Get the options type name.
31
+ */
32
+ function getOptionsTypeName(hookType) {
33
+ switch (hookType) {
34
+ case "useSuspenseQuery":
35
+ return "UseSuspenseQueryOptions";
36
+ case "useInfiniteQuery":
37
+ return "UseInfiniteQueryOptions";
38
+ default:
39
+ return "UseQueryOptions";
40
+ }
41
+ }
42
+ /**
43
+ * Resolve the generated Data type name for an operation, falling back to
44
+ * unknown when the operation has no generated Data type.
45
+ */
46
+ export function getDataTypeName(op, ctx) {
47
+ return ctx.modelNames.includes(`${op.capitalizedMethodName}Data`)
48
+ ? `${op.capitalizedMethodName}Data`
49
+ : "unknown";
50
+ }
51
+ /**
52
+ * Build the client options parameter string.
53
+ */
54
+ export function buildClientOptionsParam(op, ctx) {
55
+ const dataTypeName = ctx.modelNames.includes(`${op.capitalizedMethodName}Data`)
56
+ ? `${op.capitalizedMethodName}Data`
57
+ : "unknown";
58
+ const hasParams = op.parameters.length > 0;
59
+ if (!hasParams) {
60
+ return `clientOptions: Options<${dataTypeName}, true> = {}`;
61
+ }
62
+ const defaultValue = op.allParamsOptional ? " = {}" : "";
63
+ return `clientOptions: Options<${dataTypeName}, true>${defaultValue}`;
64
+ }
65
+ /**
66
+ * Build useQuery hook.
67
+ * Example:
68
+ * export const useFindPets = <TData = Common.FindPetsDefaultResponse, TError = FindPetsError, TQueryKey extends Array<unknown> = unknown[]>(
69
+ * clientOptions: Options<FindPetsData, true> = {},
70
+ * queryKey?: TQueryKey,
71
+ * options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">
72
+ * ) => useQuery<TData, TError>({
73
+ * queryKey: Common.UseFindPetsKeyFn(clientOptions, queryKey),
74
+ * queryFn: () => findPets({ ...clientOptions }).then(response => response.data as TData) as TData,
75
+ * ...options
76
+ * });
77
+ */
78
+ export function buildUseQueryHook(op, ctx) {
79
+ const hookName = `use${op.capitalizedMethodName}`;
80
+ const errorType = getErrorType(op, ctx);
81
+ const dataTypeDefault = getDataTypeDefault(op, "useQuery");
82
+ const clientOptionsParam = buildClientOptionsParam(op, ctx);
83
+ const hasParams = op.parameters.length > 0;
84
+ // Build the queryFn body
85
+ const callArgs = hasParams ? "{ ...clientOptions }" : "{ ...clientOptions }";
86
+ const queryFn = `() => ${op.methodName}(${callArgs}).then(response => response.data as TData) as TData`;
87
+ const body = `useQuery<TData, TError>({ queryKey: Common.Use${op.capitalizedMethodName}KeyFn(clientOptions, queryKey), queryFn: ${queryFn}, ...options })`;
88
+ return {
89
+ kind: StructureKind.VariableStatement,
90
+ // Copy the operation's JSDoc (description and @deprecated) from the SDK function
91
+ leadingTrivia: op.jsDoc ? `${op.jsDoc}\n` : undefined,
92
+ isExported: true,
93
+ declarationKind: VariableDeclarationKind.Const,
94
+ declarations: [
95
+ {
96
+ name: hookName,
97
+ initializer: `<TData = ${dataTypeDefault}, TError = ${errorType}, TQueryKey extends Array<unknown> = unknown[]>(${clientOptionsParam}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">) => ${body}`,
98
+ },
99
+ ],
100
+ };
101
+ }
102
+ /**
103
+ * Build useSuspenseQuery hook.
104
+ */
105
+ export function buildUseSuspenseQueryHook(op, ctx) {
106
+ const hookName = `use${op.capitalizedMethodName}Suspense`;
107
+ const errorType = getErrorType(op, ctx);
108
+ const dataTypeDefault = getDataTypeDefault(op, "useSuspenseQuery");
109
+ const clientOptionsParam = buildClientOptionsParam(op, ctx);
110
+ const hasParams = op.parameters.length > 0;
111
+ const callArgs = hasParams ? "{ ...clientOptions }" : "{ ...clientOptions }";
112
+ const queryFn = `() => ${op.methodName}(${callArgs}).then(response => response.data as TData) as TData`;
113
+ const body = `useSuspenseQuery<TData, TError>({ queryKey: Common.Use${op.capitalizedMethodName}KeyFn(clientOptions, queryKey), queryFn: ${queryFn}, ...options })`;
114
+ return {
115
+ kind: StructureKind.VariableStatement,
116
+ // Copy the operation's JSDoc (description and @deprecated) from the SDK function
117
+ leadingTrivia: op.jsDoc ? `${op.jsDoc}\n` : undefined,
118
+ isExported: true,
119
+ declarationKind: VariableDeclarationKind.Const,
120
+ declarations: [
121
+ {
122
+ name: hookName,
123
+ initializer: `<TData = ${dataTypeDefault}, TError = ${errorType}, TQueryKey extends Array<unknown> = unknown[]>(${clientOptionsParam}, queryKey?: TQueryKey, options?: Omit<UseSuspenseQueryOptions<TData, TError>, "queryKey" | "queryFn">) => ${body}`,
124
+ },
125
+ ],
126
+ };
127
+ }
128
+ /**
129
+ * Build the nested type for getNextPageParam.
130
+ * E.g., "meta.next" becomes "{ meta: { next: number } }"
131
+ */
132
+ export function buildNestedNextPageType(nextPageParam) {
133
+ const segments = nextPageParam.split(".");
134
+ return segments.reduceRight((acc, segment) => {
135
+ return `{ ${segment}: ${acc} }`;
136
+ }, "number");
137
+ }
138
+ /**
139
+ * Build useInfiniteQuery hook.
140
+ */
141
+ export function buildUseInfiniteQueryHook(op, ctx) {
142
+ if (!op.isPaginatable) {
143
+ return null;
144
+ }
145
+ const hookName = `use${op.capitalizedMethodName}Infinite`;
146
+ const errorType = getErrorType(op, ctx);
147
+ const baseDataType = `Common.${op.capitalizedMethodName}DefaultResponse`;
148
+ const dataTypeName = getDataTypeName(op, ctx);
149
+ // Infinite queries take a dedicated options type that excludes the page
150
+ // parameter — it is supplied by TanStack Query's pageParam mechanism
151
+ const defaultValue = op.allParamsOptional ? " = {}" : "";
152
+ const clientOptionsParam = `clientOptions: Common.${op.capitalizedMethodName}InfiniteClientOptions${defaultValue}`;
153
+ // Build the queryFn with pageParam handling
154
+ const queryFn = `({ pageParam }) => ${op.methodName}({ ...clientOptions, query: { ...clientOptions.query, ${ctx.pageParam}: pageParam as number } } as Options<${dataTypeName}, true>).then(response => response.data as TData) as TData`;
155
+ // Build getNextPageParam with nested type
156
+ const nestedType = buildNestedNextPageType(ctx.nextPageParam);
157
+ const getNextPageParam = `getNextPageParam: (response) => (response as ${nestedType}).${ctx.nextPageParam}`;
158
+ // initialPageParam is a string literal
159
+ const infiniteOptions = `initialPageParam: "${ctx.initialPageParam}", ${getNextPageParam}`;
160
+ const body = `useInfiniteQuery({ queryKey: Common.Use${op.capitalizedMethodName}InfiniteKeyFn(clientOptions, queryKey), queryFn: ${queryFn}, ${infiniteOptions}, ...options })`;
161
+ return {
162
+ kind: StructureKind.VariableStatement,
163
+ // Copy the operation's JSDoc (description and @deprecated) from the SDK function
164
+ leadingTrivia: op.jsDoc ? `${op.jsDoc}\n` : undefined,
165
+ isExported: true,
166
+ declarationKind: VariableDeclarationKind.Const,
167
+ declarations: [
168
+ {
169
+ name: hookName,
170
+ initializer: `<TData = InfiniteData<${baseDataType}>, TError = ${errorType}, TQueryKey extends Array<unknown> = unknown[]>(${clientOptionsParam}, queryKey?: TQueryKey, options?: Omit<UseInfiniteQueryOptions<TData, TError>, "queryKey" | "queryFn">) => ${body}`,
171
+ },
172
+ ],
173
+ };
174
+ }
175
+ /**
176
+ * Build prefetch function.
177
+ * Example:
178
+ * export const prefetchUseFindPets = (queryClient: QueryClient, clientOptions: Options<FindPetsData, true> = {}) =>
179
+ * queryClient.prefetchQuery({
180
+ * queryKey: Common.UseFindPetsKeyFn(clientOptions),
181
+ * queryFn: () => findPets({ ...clientOptions }).then(response => response.data)
182
+ * });
183
+ */
184
+ export function buildPrefetchFn(op, ctx) {
185
+ const fnName = `prefetchUse${op.capitalizedMethodName}`;
186
+ const dataTypeName = ctx.modelNames.includes(`${op.capitalizedMethodName}Data`)
187
+ ? `${op.capitalizedMethodName}Data`
188
+ : "unknown";
189
+ const hasParams = op.parameters.length > 0;
190
+ const defaultValue = op.allParamsOptional ? " = {}" : "";
191
+ const clientOptionsParam = hasParams
192
+ ? `clientOptions: Options<${dataTypeName}, true>${defaultValue}`
193
+ : `clientOptions: Options<${dataTypeName}, true> = {}`;
194
+ const callArgs = "{ ...clientOptions }";
195
+ const queryFn = `() => ${op.methodName}(${callArgs}).then(response => response.data)`;
196
+ const body = `queryClient.prefetchQuery({ queryKey: Common.Use${op.capitalizedMethodName}KeyFn(clientOptions), queryFn: ${queryFn} })`;
197
+ return {
198
+ kind: StructureKind.VariableStatement,
199
+ // Copy the operation's JSDoc (description and @deprecated) from the SDK function
200
+ leadingTrivia: op.jsDoc ? `${op.jsDoc}\n` : undefined,
201
+ isExported: true,
202
+ declarationKind: VariableDeclarationKind.Const,
203
+ declarations: [
204
+ {
205
+ name: fnName,
206
+ initializer: `(queryClient: QueryClient, ${clientOptionsParam}) => ${body}`,
207
+ },
208
+ ],
209
+ };
210
+ }
211
+ /**
212
+ * Build ensureQueryData function.
213
+ * Example:
214
+ * export const ensureUseFindPetsData = (queryClient: QueryClient, clientOptions: Options<FindPetsData, true> = {}) =>
215
+ * queryClient.ensureQueryData({
216
+ * queryKey: Common.UseFindPetsKeyFn(clientOptions),
217
+ * queryFn: () => findPets({ ...clientOptions }).then(response => response.data)
218
+ * });
219
+ */
220
+ export function buildEnsureQueryDataFn(op, ctx) {
221
+ const fnName = `ensureUse${op.capitalizedMethodName}Data`;
222
+ const dataTypeName = ctx.modelNames.includes(`${op.capitalizedMethodName}Data`)
223
+ ? `${op.capitalizedMethodName}Data`
224
+ : "unknown";
225
+ const hasParams = op.parameters.length > 0;
226
+ const defaultValue = op.allParamsOptional ? " = {}" : "";
227
+ const clientOptionsParam = hasParams
228
+ ? `clientOptions: Options<${dataTypeName}, true>${defaultValue}`
229
+ : `clientOptions: Options<${dataTypeName}, true> = {}`;
230
+ const callArgs = "{ ...clientOptions }";
231
+ const queryFn = `() => ${op.methodName}(${callArgs}).then(response => response.data)`;
232
+ const body = `queryClient.ensureQueryData({ queryKey: Common.Use${op.capitalizedMethodName}KeyFn(clientOptions), queryFn: ${queryFn} })`;
233
+ return {
234
+ kind: StructureKind.VariableStatement,
235
+ // Copy the operation's JSDoc (description and @deprecated) from the SDK function
236
+ leadingTrivia: op.jsDoc ? `${op.jsDoc}\n` : undefined,
237
+ isExported: true,
238
+ declarationKind: VariableDeclarationKind.Const,
239
+ declarations: [
240
+ {
241
+ name: fnName,
242
+ initializer: `(queryClient: QueryClient, ${clientOptionsParam}) => ${body}`,
243
+ },
244
+ ],
245
+ };
246
+ }
@@ -0,0 +1,76 @@
1
+ import { StructureKind, VariableDeclarationKind, } from "ts-morph";
2
+ import { buildClientOptionsParam, buildNestedNextPageType, getDataTypeName, } from "./buildQueryHooks.mjs";
3
+ /**
4
+ * Build a queryOptions factory for a GET operation.
5
+ * The factory centralizes queryKey and queryFn so they can be reused with
6
+ * every TanStack Query utility (useQuery, useQueries, prefetchQuery,
7
+ * ensureQueryData, setQueryData, ...) with full type safety.
8
+ * Example:
9
+ * export const findPetsOptions = (clientOptions: Options<FindPetsData, true> = {}, queryKey?: Array<unknown>) =>
10
+ * queryOptions({
11
+ * queryKey: Common.UseFindPetsKeyFn(clientOptions, queryKey),
12
+ * queryFn: () => findPets({ ...clientOptions }).then(response => response.data),
13
+ * });
14
+ */
15
+ export function buildQueryOptionsFn(op, ctx) {
16
+ const fnName = `${op.methodName}Options`;
17
+ const clientOptionsParam = buildClientOptionsParam(op, ctx);
18
+ const queryFn = `() => ${op.methodName}({ ...clientOptions }).then(response => response.data)`;
19
+ const body = `queryOptions({ queryKey: Common.Use${op.capitalizedMethodName}KeyFn(clientOptions, queryKey), queryFn: ${queryFn} })`;
20
+ return {
21
+ kind: StructureKind.VariableStatement,
22
+ // Copy the operation's JSDoc (description and @deprecated) from the SDK function
23
+ leadingTrivia: op.jsDoc ? `${op.jsDoc}\n` : undefined,
24
+ isExported: true,
25
+ declarationKind: VariableDeclarationKind.Const,
26
+ declarations: [
27
+ {
28
+ name: fnName,
29
+ initializer: `(${clientOptionsParam}, queryKey?: Array<unknown>) => ${body}`,
30
+ },
31
+ ],
32
+ };
33
+ }
34
+ /**
35
+ * Build an infiniteQueryOptions factory for a paginatable GET operation.
36
+ * Uses the dedicated infinite query key and page-less options type.
37
+ * Example:
38
+ * export const findPaginatedPetsInfiniteOptions = (clientOptions: Common.FindPaginatedPetsInfiniteClientOptions = {}, queryKey?: Array<unknown>) =>
39
+ * infiniteQueryOptions({
40
+ * queryKey: Common.UseFindPaginatedPetsInfiniteKeyFn(clientOptions, queryKey),
41
+ * queryFn: ({ pageParam }) => findPaginatedPets({ ...clientOptions, query: { ...clientOptions.query, page: pageParam } } as Options<FindPaginatedPetsData, true>).then(response => response.data),
42
+ * initialPageParam: 1,
43
+ * getNextPageParam: (response) => (response as { nextPage: number }).nextPage,
44
+ * });
45
+ */
46
+ export function buildInfiniteQueryOptionsFn(op, ctx) {
47
+ if (!op.isPaginatable) {
48
+ return null;
49
+ }
50
+ const fnName = `${op.methodName}InfiniteOptions`;
51
+ const dataTypeName = getDataTypeName(op, ctx);
52
+ const defaultValue = op.allParamsOptional ? " = {}" : "";
53
+ const clientOptionsParam = `clientOptions: Common.${op.capitalizedMethodName}InfiniteClientOptions${defaultValue}`;
54
+ const queryFn = `({ pageParam }) => ${op.methodName}({ ...clientOptions, query: { ...clientOptions.query, ${ctx.pageParam}: pageParam } } as Options<${dataTypeName}, true>).then(response => response.data)`;
55
+ // Emit a numeric literal when possible so the inferred pageParam type
56
+ // matches what getNextPageParam returns
57
+ const initialPageParam = /^-?\d+$/.test(ctx.initialPageParam)
58
+ ? ctx.initialPageParam
59
+ : JSON.stringify(ctx.initialPageParam);
60
+ const nestedType = buildNestedNextPageType(ctx.nextPageParam);
61
+ const getNextPageParam = `(response) => (response as ${nestedType}).${ctx.nextPageParam}`;
62
+ const body = `infiniteQueryOptions({ queryKey: Common.Use${op.capitalizedMethodName}InfiniteKeyFn(clientOptions, queryKey), queryFn: ${queryFn}, initialPageParam: ${initialPageParam}, getNextPageParam: ${getNextPageParam} })`;
63
+ return {
64
+ kind: StructureKind.VariableStatement,
65
+ // Copy the operation's JSDoc (description and @deprecated) from the SDK function
66
+ leadingTrivia: op.jsDoc ? `${op.jsDoc}\n` : undefined,
67
+ isExported: true,
68
+ declarationKind: VariableDeclarationKind.Const,
69
+ declarations: [
70
+ {
71
+ name: fnName,
72
+ initializer: `(${clientOptionsParam}, queryKey?: Array<unknown>) => ${body}`,
73
+ },
74
+ ],
75
+ };
76
+ }
@@ -0,0 +1,251 @@
1
+ import { StructureKind, } from "ts-morph";
2
+ import { OpenApiRqFiles } from "../constants.mjs";
3
+ import { buildDefaultResponseType, buildInfiniteClientOptionsType, buildInfiniteQueryKeyConst, buildInfiniteQueryKeyFn, buildMutationKeyConst, buildMutationKeyFn, buildMutationResultType, buildQueryKeyConst, buildQueryKeyFn, buildQueryResultType, } from "./buildCommon.mjs";
4
+ import { buildUseMutationHook } from "./buildMutationHooks.mjs";
5
+ import { buildEnsureQueryDataFn, buildPrefetchFn, buildUseInfiniteQueryHook, buildUseQueryHook, buildUseSuspenseQueryHook, } from "./buildQueryHooks.mjs";
6
+ import { buildInfiniteQueryOptionsFn, buildQueryOptionsFn, } from "./buildQueryOptions.mjs";
7
+ import { buildAxiosErrorImport, buildClientImport, buildCommonImport, buildModelImport, buildQueryImport, buildQueryOptionsImport, buildServiceImport, createGenerationProject, } from "./projectFactory.mjs";
8
+ /**
9
+ * Build imports for common.ts file.
10
+ */
11
+ function buildCommonFileImports(ctx) {
12
+ const imports = [
13
+ buildClientImport(ctx),
14
+ buildQueryImport(),
15
+ buildServiceImport(ctx),
16
+ ];
17
+ const modelImport = buildModelImport(ctx);
18
+ if (modelImport) {
19
+ imports.push(modelImport);
20
+ }
21
+ if (ctx.client === "@hey-api/client-axios") {
22
+ imports.push(buildAxiosErrorImport());
23
+ }
24
+ return imports;
25
+ }
26
+ /**
27
+ * Build imports for hook files (queries, suspense, infinite, prefetch, ensure).
28
+ */
29
+ function buildHookFileImports(ctx) {
30
+ return [buildCommonImport(), ...buildCommonFileImports(ctx)];
31
+ }
32
+ /**
33
+ * Generate the index.ts file content.
34
+ */
35
+ function generateIndexFile(ctx) {
36
+ const project = createGenerationProject();
37
+ const sourceFile = project.createSourceFile(`${OpenApiRqFiles.index}.ts`, undefined, { overwrite: true });
38
+ const exports = [
39
+ {
40
+ kind: StructureKind.ExportDeclaration,
41
+ moduleSpecifier: "./common",
42
+ },
43
+ {
44
+ kind: StructureKind.ExportDeclaration,
45
+ moduleSpecifier: "./queries",
46
+ },
47
+ {
48
+ kind: StructureKind.ExportDeclaration,
49
+ moduleSpecifier: "./queryOptions",
50
+ },
51
+ ];
52
+ sourceFile.addExportDeclarations(exports);
53
+ return sourceFile.getFullText();
54
+ }
55
+ /**
56
+ * Generate the common.ts file content.
57
+ */
58
+ function generateCommonFile(operations, ctx) {
59
+ const project = createGenerationProject();
60
+ const sourceFile = project.createSourceFile(`${OpenApiRqFiles.common}.ts`, undefined, { overwrite: true });
61
+ // Add imports
62
+ sourceFile.addImportDeclarations(buildCommonFileImports(ctx));
63
+ // Group operations by HTTP method
64
+ const getOperations = operations.filter((op) => op.httpMethod === "GET");
65
+ const mutationOperations = operations.filter((op) => ["POST", "PUT", "PATCH", "DELETE"].includes(op.httpMethod));
66
+ // Add query types and keys
67
+ for (const op of getOperations) {
68
+ sourceFile.addTypeAlias(buildDefaultResponseType(op));
69
+ sourceFile.addTypeAlias(buildQueryResultType(op));
70
+ sourceFile.addVariableStatement(buildQueryKeyConst(op));
71
+ sourceFile.addVariableStatement(buildQueryKeyFn(op, ctx));
72
+ }
73
+ // Add dedicated infinite query types and keys for paginatable operations
74
+ for (const op of getOperations.filter((o) => o.isPaginatable)) {
75
+ sourceFile.addTypeAlias(buildInfiniteClientOptionsType(op, ctx));
76
+ sourceFile.addVariableStatement(buildInfiniteQueryKeyConst(op));
77
+ sourceFile.addVariableStatement(buildInfiniteQueryKeyFn(op));
78
+ }
79
+ // Add mutation types and keys
80
+ for (const op of mutationOperations) {
81
+ sourceFile.addTypeAlias(buildMutationResultType(op));
82
+ sourceFile.addVariableStatement(buildMutationKeyConst(op));
83
+ sourceFile.addVariableStatement(buildMutationKeyFn(op));
84
+ }
85
+ return sourceFile.getFullText();
86
+ }
87
+ /**
88
+ * Generate the queries.ts file content.
89
+ */
90
+ function generateQueriesFile(operations, ctx) {
91
+ const project = createGenerationProject();
92
+ const sourceFile = project.createSourceFile(`${OpenApiRqFiles.queries}.ts`, undefined, { overwrite: true });
93
+ // Add imports
94
+ sourceFile.addImportDeclarations(buildHookFileImports(ctx));
95
+ // Group operations
96
+ const getOperations = operations.filter((op) => op.httpMethod === "GET");
97
+ const mutationOperations = operations.filter((op) => ["POST", "PUT", "PATCH", "DELETE"].includes(op.httpMethod));
98
+ // Add useQuery hooks
99
+ for (const op of getOperations) {
100
+ sourceFile.addVariableStatement(buildUseQueryHook(op, ctx));
101
+ }
102
+ // Add useMutation hooks
103
+ for (const op of mutationOperations) {
104
+ sourceFile.addVariableStatement(buildUseMutationHook(op, ctx));
105
+ }
106
+ return sourceFile.getFullText();
107
+ }
108
+ /**
109
+ * Generate the queryOptions.ts file content.
110
+ */
111
+ function generateQueryOptionsFile(operations, ctx) {
112
+ const project = createGenerationProject();
113
+ const sourceFile = project.createSourceFile(`${OpenApiRqFiles.queryOptions}.ts`, undefined, { overwrite: true });
114
+ // Add imports
115
+ const imports = [
116
+ buildCommonImport(),
117
+ buildQueryOptionsImport(),
118
+ buildClientImport(ctx),
119
+ buildServiceImport(ctx),
120
+ ];
121
+ const modelImport = buildModelImport(ctx);
122
+ if (modelImport) {
123
+ imports.push(modelImport);
124
+ }
125
+ sourceFile.addImportDeclarations(imports);
126
+ // Only GET operations have query options
127
+ const getOperations = operations.filter((op) => op.httpMethod === "GET");
128
+ for (const op of getOperations) {
129
+ sourceFile.addVariableStatement(buildQueryOptionsFn(op, ctx));
130
+ }
131
+ for (const op of getOperations) {
132
+ const infiniteOptions = buildInfiniteQueryOptionsFn(op, ctx);
133
+ if (infiniteOptions) {
134
+ sourceFile.addVariableStatement(infiniteOptions);
135
+ }
136
+ }
137
+ return sourceFile.getFullText();
138
+ }
139
+ /**
140
+ * Generate the suspense.ts file content.
141
+ */
142
+ function generateSuspenseFile(operations, ctx) {
143
+ const project = createGenerationProject();
144
+ const sourceFile = project.createSourceFile(`${OpenApiRqFiles.suspense}.ts`, undefined, { overwrite: true });
145
+ // Add imports
146
+ sourceFile.addImportDeclarations(buildHookFileImports(ctx));
147
+ // Only GET operations for suspense
148
+ const getOperations = operations.filter((op) => op.httpMethod === "GET");
149
+ // Add useSuspenseQuery hooks
150
+ for (const op of getOperations) {
151
+ sourceFile.addVariableStatement(buildUseSuspenseQueryHook(op, ctx));
152
+ }
153
+ return sourceFile.getFullText();
154
+ }
155
+ /**
156
+ * Generate the infiniteQueries.ts file content.
157
+ */
158
+ function generateInfiniteQueriesFile(operations, ctx) {
159
+ const project = createGenerationProject();
160
+ const sourceFile = project.createSourceFile(`${OpenApiRqFiles.infiniteQueries}.ts`, undefined, { overwrite: true });
161
+ // Add imports
162
+ sourceFile.addImportDeclarations(buildHookFileImports(ctx));
163
+ // Only paginatable GET operations
164
+ const paginatableOperations = operations.filter((op) => op.httpMethod === "GET" && op.isPaginatable);
165
+ // Add useInfiniteQuery hooks
166
+ for (const op of paginatableOperations) {
167
+ const hook = buildUseInfiniteQueryHook(op, ctx);
168
+ if (hook) {
169
+ sourceFile.addVariableStatement(hook);
170
+ }
171
+ }
172
+ return sourceFile.getFullText();
173
+ }
174
+ /**
175
+ * Generate the prefetch.ts file content.
176
+ */
177
+ function generatePrefetchFile(operations, ctx) {
178
+ const project = createGenerationProject();
179
+ const sourceFile = project.createSourceFile(`${OpenApiRqFiles.prefetch}.ts`, undefined, { overwrite: true });
180
+ // Add imports
181
+ sourceFile.addImportDeclarations(buildHookFileImports(ctx));
182
+ // Only GET operations for prefetch
183
+ const getOperations = operations.filter((op) => op.httpMethod === "GET");
184
+ // Add prefetch functions
185
+ for (const op of getOperations) {
186
+ sourceFile.addVariableStatement(buildPrefetchFn(op, ctx));
187
+ }
188
+ return sourceFile.getFullText();
189
+ }
190
+ /**
191
+ * Generate the ensureQueryData.ts file content.
192
+ */
193
+ function generateEnsureQueryDataFile(operations, ctx) {
194
+ const project = createGenerationProject();
195
+ const sourceFile = project.createSourceFile(`${OpenApiRqFiles.ensureQueryData}.ts`, undefined, { overwrite: true });
196
+ // Add imports
197
+ sourceFile.addImportDeclarations(buildHookFileImports(ctx));
198
+ // Only GET operations for ensure
199
+ const getOperations = operations.filter((op) => op.httpMethod === "GET");
200
+ // Add ensureQueryData functions
201
+ for (const op of getOperations) {
202
+ sourceFile.addVariableStatement(buildEnsureQueryDataFn(op, ctx));
203
+ }
204
+ return sourceFile.getFullText();
205
+ }
206
+ /**
207
+ * Add the generated header comment to file content.
208
+ */
209
+ function addHeaderComment(content, version) {
210
+ const comment = `// generated with @7nohe/openapi-react-query-codegen@${version} \n\n`;
211
+ return comment + content;
212
+ }
213
+ /**
214
+ * Generate all files using ts-morph.
215
+ */
216
+ export function generateAllFiles(operations, ctx) {
217
+ return [
218
+ {
219
+ name: `${OpenApiRqFiles.index}.ts`,
220
+ content: addHeaderComment(generateIndexFile(ctx), ctx.version),
221
+ },
222
+ {
223
+ name: `${OpenApiRqFiles.common}.ts`,
224
+ content: addHeaderComment(generateCommonFile(operations, ctx), ctx.version),
225
+ },
226
+ {
227
+ name: `${OpenApiRqFiles.queries}.ts`,
228
+ content: addHeaderComment(generateQueriesFile(operations, ctx), ctx.version),
229
+ },
230
+ {
231
+ name: `${OpenApiRqFiles.queryOptions}.ts`,
232
+ content: addHeaderComment(generateQueryOptionsFile(operations, ctx), ctx.version),
233
+ },
234
+ {
235
+ name: `${OpenApiRqFiles.suspense}.ts`,
236
+ content: addHeaderComment(generateSuspenseFile(operations, ctx), ctx.version),
237
+ },
238
+ {
239
+ name: `${OpenApiRqFiles.infiniteQueries}.ts`,
240
+ content: addHeaderComment(generateInfiniteQueriesFile(operations, ctx), ctx.version),
241
+ },
242
+ {
243
+ name: `${OpenApiRqFiles.prefetch}.ts`,
244
+ content: addHeaderComment(generatePrefetchFile(operations, ctx), ctx.version),
245
+ },
246
+ {
247
+ name: `${OpenApiRqFiles.ensureQueryData}.ts`,
248
+ content: addHeaderComment(generateEnsureQueryDataFile(operations, ctx), ctx.version),
249
+ },
250
+ ];
251
+ }
@@ -0,0 +1,5 @@
1
+ export { generateAllFiles } from "./generateFiles.mjs";
2
+ export { createGenerationProject } from "./projectFactory.mjs";
3
+ export * from "./buildCommon.mjs";
4
+ export * from "./buildQueryHooks.mjs";
5
+ export * from "./buildMutationHooks.mjs";