@orval/query 8.18.0 → 8.20.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.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { GetterPropType, OutputClient, OutputHttpClient, Verbs, camel, compareVersions, generateFormDataAndUrlEncodedFunction, generateMutator, generateMutatorConfig, generateMutatorRequestOptions, generateOptions, generateVerbImports, getAngularFilteredParamsCallExpression, getAngularFilteredParamsHelperBody, getFullRoute, getRouteAsArray, getSuccessResponseType, isObject, isString, isSyntheticDefaultImportsAllow, jsDoc, kebab, logWarning, makeRouteSafe, mergeDeep, pascal, stringify, toObjectString } from "@orval/core";
1
+ import { GetterPropType, OutputClient, OutputHttpClient, Verbs, camel, compareVersions, generateFormDataAndUrlEncodedFunction, generateMutator, generateMutatorConfig, generateMutatorRequestOptions, generateOptions, generateVerbImports, getAngularFilteredParamsCallExpression, getAngularFilteredParamsHelperBody, getFullRoute, getRouteAsArray, getSuccessResponseType, isObject, isOperationInTagBucket, isString, isSyntheticDefaultImportsAllow, jsDoc, logWarning, makeRouteSafe, mergeDeep, pascal, stringify, toObjectString } from "@orval/core";
2
2
  import { generateFetchHeader, generateRequestFunction } from "@orval/fetch";
3
3
  import nodePath from "node:path";
4
4
  import { styleText } from "node:util";
@@ -48,24 +48,6 @@ const normalizeMutator = (workspace, mutator) => {
48
48
  default: true
49
49
  };
50
50
  };
51
- function vueWrapTypeWithMaybeRef(props) {
52
- return props.map((prop) => {
53
- const [paramName, paramType] = prop.implementation.split(":");
54
- if (!paramType) return prop;
55
- const name = prop.type === GetterPropType.NAMED_PATH_PARAMS ? prop.name : paramName;
56
- const [type, defaultValue] = paramType.split("=");
57
- return {
58
- ...prop,
59
- implementation: `${name}: MaybeRef<${type.trim()}>${defaultValue ? ` = ${defaultValue}` : ""}`
60
- };
61
- });
62
- }
63
- const vueUnRefParams = (props) => {
64
- return props.map((prop) => {
65
- if (prop.type === GetterPropType.NAMED_PATH_PARAMS) return `const ${prop.destructured} = unref(${prop.name});`;
66
- return `${prop.name} = unref(${prop.name});`;
67
- }).join("\n");
68
- };
69
51
  const getQueryTypeForFramework = (type) => {
70
52
  switch (type) {
71
53
  case "suspenseQuery": return "query";
@@ -159,7 +141,6 @@ const generateAngularHttpRequestFunction = ({ headers, queryParams, operationNam
159
141
  hasSignal,
160
142
  hasSignalParam,
161
143
  isExactOptionalPropertyTypes,
162
- isVue: false,
163
144
  isAngular: context.output.httpClient === OutputHttpClient.ANGULAR
164
145
  });
165
146
  const requestOptions = isRequestOptions ? generateMutatorRequestOptions(override.requestOptions, mutator.hasSecondArg) : "";
@@ -228,11 +209,11 @@ const generateAngularHttpRequestFunction = ({ headers, queryParams, operationNam
228
209
  }
229
210
  `;
230
211
  };
231
- const generateAxiosRequestFunction = ({ headers, queryParams, operationName, response, mutator, body, props: _props, verb, formData, formUrlEncoded, override, paramsSerializer }, { route: _route, context }, isVue) => {
232
- let props = _props;
212
+ const generateAxiosRequestFunction = ({ headers, queryParams, operationName, response, mutator, body, props: _props, verb, formData, formUrlEncoded, override, paramsSerializer }, { route: _route, context }, adapter) => {
213
+ const props = adapter.transformProps(_props);
233
214
  let route = _route;
234
- if (isVue) props = vueWrapTypeWithMaybeRef(_props);
235
215
  if (context.output.urlEncodeParameters) route = makeRouteSafe(route);
216
+ const unrefStatements = adapter.getRequestUnrefStatements(props);
236
217
  const isRequestOptions = override.requestOptions !== false;
237
218
  const isFormData = !override.formData.disabled;
238
219
  const isFormUrlEncoded = override.formUrlEncoded !== false;
@@ -258,46 +239,34 @@ const generateAxiosRequestFunction = ({ headers, queryParams, operationName, res
258
239
  isFormUrlEncoded,
259
240
  hasSignal,
260
241
  hasSignalParam,
261
- isExactOptionalPropertyTypes,
262
- isVue
242
+ isExactOptionalPropertyTypes
263
243
  });
264
244
  const bodyDefinition = body.definition.replace("[]", String.raw`\[\]`);
265
245
  const propsImplementation = mutator.bodyTypeName && body.definition ? toObjectString(props, "implementation").replace(new RegExp(String.raw`(\w*):\s?${bodyDefinition}`), `$1: ${mutator.bodyTypeName}<${body.definition}>`) : toObjectString(props, "implementation");
266
246
  const requestOptions = isRequestOptions ? generateMutatorRequestOptions(override.requestOptions, mutator.hasSecondArg) : "";
267
247
  if (mutator.isHook) {
268
- const ret = `${override.query.shouldExportMutatorHooks ? "export " : ""}const use${pascal(operationName)}Hook = () => {
269
- const ${operationName} = ${mutator.name}<${response.definition.success || "unknown"}>();
270
-
271
- return useCallback((\n ${propsImplementation}\n ${isRequestOptions && mutator.hasSecondArg ? `options${context.output.optionsParamRequired ? "" : "?"}: SecondParameter<ReturnType<typeof ${mutator.name}>>,` : ""}${getSignalDefinition({
248
+ const callback = `(\n ${propsImplementation}\n ${isRequestOptions && mutator.hasSecondArg ? `options${context.output.optionsParamRequired ? "" : "?"}: SecondParameter<ReturnType<typeof ${mutator.name}>>,` : ""}${getSignalDefinition({
272
249
  hasSignal,
273
250
  hasSignalParam
274
- })}) => {${bodyForm}
251
+ })}) => {
252
+ ${unrefStatements}
253
+ ${bodyForm}
275
254
  return ${operationName}(
276
255
  ${mutatorConfig},
277
256
  ${requestOptions});
278
- }, [${operationName}])
279
- }
280
- `;
281
- const vueRet = `${override.query.shouldExportMutatorHooks ? "export " : ""}const use${pascal(operationName)}Hook = () => {
257
+ }`;
258
+ return `${override.query.shouldExportMutatorHooks ? "export " : ""}const use${pascal(operationName)}Hook = () => {
282
259
  const ${operationName} = ${mutator.name}<${response.definition.success || "unknown"}>();
283
260
 
284
- return (\n ${propsImplementation}\n ${isRequestOptions && mutator.hasSecondArg ? `options${context.output.optionsParamRequired ? "" : "?"}: SecondParameter<ReturnType<typeof ${mutator.name}>>,` : ""}${getSignalDefinition({
285
- hasSignal,
286
- hasSignalParam
287
- })}) => {${bodyForm}
288
- return ${operationName}(
289
- ${mutatorConfig},
290
- ${requestOptions});
291
- }
261
+ return ${adapter.wrapHookMutatorCallback(callback, operationName)}
292
262
  }
293
263
  `;
294
- return isVue ? vueRet : ret;
295
264
  }
296
265
  return `${override.query.shouldExportHttpClient ? "export " : ""}const ${operationName} = (\n ${propsImplementation}\n ${isRequestOptions && mutator.hasSecondArg ? `options${context.output.optionsParamRequired ? "" : "?"}: SecondParameter<typeof ${mutator.name}>,` : ""}${getSignalDefinition({
297
266
  hasSignal,
298
267
  hasSignalParam
299
268
  })}) => {
300
- ${isVue ? vueUnRefParams(props) : ""}
269
+ ${unrefStatements}
301
270
  ${bodyForm}
302
271
  return ${mutator.name}<${response.definition.success || "unknown"}>(
303
272
  ${mutatorConfig},
@@ -320,8 +289,7 @@ const generateAxiosRequestFunction = ({ headers, queryParams, operationName, res
320
289
  paramsSerializerOptions: override.paramsSerializerOptions,
321
290
  isExactOptionalPropertyTypes,
322
291
  hasSignal,
323
- hasSignalParam,
324
- isVue
292
+ hasSignalParam
325
293
  });
326
294
  const optionsArgs = generateRequestOptionsArguments({
327
295
  isRequestOptions,
@@ -330,7 +298,7 @@ const generateAxiosRequestFunction = ({ headers, queryParams, operationName, res
330
298
  });
331
299
  const queryProps = toObjectString(props, "implementation");
332
300
  return `${override.query.shouldExportHttpClient ? "export " : ""}const ${operationName} = (\n ${queryProps} ${optionsArgs} ): Promise<AxiosResponse<${response.definition.success || "unknown"}>> => {
333
- ${isVue ? vueUnRefParams(props) : ""}
301
+ ${unrefStatements}
334
302
  ${bodyForm}
335
303
  return axios${isSyntheticDefaultImportsAllowed ? "" : ".default"}.${verb}(${options});
336
304
  }
@@ -420,7 +388,7 @@ const getMutationRequestArgs = (isRequestOptions, httpClient, mutator, useRuntim
420
388
  };
421
389
  const getQueryHeader = (params) => {
422
390
  if (params.output.httpClient === OutputHttpClient.FETCH) return generateFetchHeader(params);
423
- if (params.output.httpClient === OutputHttpClient.ANGULAR) return (params.tag ? Object.values(params.verbOptions).filter((verbOption) => kebab(verbOption.tags[0] ?? "default") === params.tag) : Object.values(params.verbOptions)).some((v) => v.queryParams) ? getAngularFilteredParamsHelperBody() : "";
391
+ if (params.output.httpClient === OutputHttpClient.ANGULAR) return Object.values(params.verbOptions).filter((verbOption) => isOperationInTagBucket(verbOption, params.tag)).some((v) => v.queryParams) ? getAngularFilteredParamsHelperBody() : "";
424
392
  return "";
425
393
  };
426
394
  //#endregion
@@ -702,15 +670,20 @@ const VUE_QUERY_DEPENDENCIES = [{
702
670
  dependency: "@tanstack/vue-query"
703
671
  }, {
704
672
  exports: [
673
+ {
674
+ name: "computed",
675
+ values: true
676
+ },
705
677
  {
706
678
  name: "unref",
707
679
  values: true
708
680
  },
709
- { name: "MaybeRef" },
710
681
  {
711
- name: "computed",
682
+ name: "toValue",
712
683
  values: true
713
- }
684
+ },
685
+ { name: "MaybeRef" },
686
+ { name: "MaybeRefOrGetter" }
714
687
  ],
715
688
  dependency: "vue"
716
689
  }];
@@ -1140,9 +1113,6 @@ const createReactAdapter = ({ hasQueryV5, hasQueryV5WithDataTagError, hasQueryV5
1140
1113
  },
1141
1114
  generateMutationHookBody({ operationPrefix, mutationImplementation, hasInvalidation, optionalQueryClientArgument }) {
1142
1115
  return ` ${hasInvalidation ? `const backupQueryClient = useQueryClient();\n ` : ""}return ${operationPrefix}Mutation(${mutationImplementation}${optionalQueryClientArgument ? `, queryClient` : ""});`;
1143
- },
1144
- generateRequestFunction(verbOptions, options) {
1145
- return options.context.output.httpClient === OutputHttpClient.AXIOS ? generateAxiosRequestFunction(verbOptions, options, false) : generateRequestFunction(verbOptions, options);
1146
1116
  }
1147
1117
  });
1148
1118
  //#endregion
@@ -1210,9 +1180,6 @@ const createSolidAdapter = ({ hasQueryV5, hasQueryV5WithDataTagError, hasQueryV5
1210
1180
  },
1211
1181
  getOptionalQueryClientArgument() {
1212
1182
  return ", queryClient?: () => QueryClient";
1213
- },
1214
- generateRequestFunction(verbOptions, options) {
1215
- return options.context.output.httpClient === OutputHttpClient.AXIOS ? generateAxiosRequestFunction(verbOptions, options, false) : generateRequestFunction(verbOptions, options);
1216
1183
  }
1217
1184
  });
1218
1185
  //#endregion
@@ -1309,14 +1276,38 @@ const createSvelteAdapter = ({ hasSvelteQueryV4, hasSvelteQueryV6, hasQueryV5, h
1309
1276
  getQueryType(type) {
1310
1277
  if (hasSvelteQueryV4) return getQueryTypeForFramework(type);
1311
1278
  return type;
1312
- },
1313
- generateRequestFunction(verbOptions, options) {
1314
- return options.context.output.httpClient === OutputHttpClient.AXIOS ? generateAxiosRequestFunction(verbOptions, options, false) : generateRequestFunction(verbOptions, options);
1315
1279
  }
1316
1280
  };
1317
1281
  };
1318
1282
  //#endregion
1319
1283
  //#region src/frameworks/vue.ts
1284
+ const getVueReactivity = (hasQueryV5) => hasQueryV5 ? {
1285
+ wrapper: "MaybeRefOrGetter",
1286
+ resolve: "toValue"
1287
+ } : {
1288
+ wrapper: "MaybeRef",
1289
+ resolve: "unref"
1290
+ };
1291
+ function vueWrapTypeWithMaybeRef(props, hasQueryV5) {
1292
+ const { wrapper } = getVueReactivity(hasQueryV5);
1293
+ return props.map((prop) => {
1294
+ const [paramName, paramType] = prop.implementation.split(":");
1295
+ if (!paramType) return prop;
1296
+ const name = prop.type === GetterPropType.NAMED_PATH_PARAMS ? prop.name : paramName;
1297
+ const [type, defaultValue] = paramType.split("=");
1298
+ return {
1299
+ ...prop,
1300
+ implementation: `${name}: ${wrapper}<${type.trim()}>${defaultValue ? ` = ${defaultValue}` : ""}`
1301
+ };
1302
+ });
1303
+ }
1304
+ const vueUnRefParams = (props, hasQueryV5) => {
1305
+ const { resolve } = getVueReactivity(hasQueryV5);
1306
+ return props.map((prop) => {
1307
+ if (prop.type === GetterPropType.NAMED_PATH_PARAMS) return `const ${prop.destructured} = ${resolve}(${prop.name});`;
1308
+ return `${prop.name} = ${resolve}(${prop.name});`;
1309
+ }).join("\n");
1310
+ };
1320
1311
  const createVueAdapter = ({ hasVueQueryV4, hasQueryV5, hasQueryV5WithDataTagError, hasQueryV5WithInfiniteQueryOptionsError, hasQueryV5WithMutationContextOnSuccess, hasQueryV5WithRequiredContextOnSuccess }) => ({
1321
1312
  outputClient: OutputClient.VUE_QUERY,
1322
1313
  hookPrefix: "use",
@@ -1326,19 +1317,23 @@ const createVueAdapter = ({ hasVueQueryV4, hasQueryV5, hasQueryV5WithDataTagErro
1326
1317
  hasQueryV5WithMutationContextOnSuccess,
1327
1318
  hasQueryV5WithRequiredContextOnSuccess,
1328
1319
  transformProps(props) {
1329
- return vueWrapTypeWithMaybeRef(props);
1320
+ return vueWrapTypeWithMaybeRef(props, hasQueryV5);
1330
1321
  },
1331
1322
  shouldDestructureNamedPathParams() {
1332
1323
  return false;
1333
1324
  },
1334
1325
  getHttpFunctionQueryProps(queryProperties, httpClient) {
1335
- if (httpClient === OutputHttpClient.FETCH && queryProperties) return queryProperties.split(",").map((prop) => `unref(${prop})`).join(",");
1326
+ if (httpClient === OutputHttpClient.FETCH && queryProperties) {
1327
+ const { resolve } = getVueReactivity(hasQueryV5);
1328
+ return queryProperties.split(",").map((prop) => `${resolve}(${prop})`).join(",");
1329
+ }
1336
1330
  return queryProperties;
1337
1331
  },
1338
1332
  getInfiniteQueryHttpProps(props, queryParam, httpClient) {
1333
+ const { resolve } = getVueReactivity(hasQueryV5);
1339
1334
  return props.map((param) => {
1340
- if (param.name === "params") return `{...unref(params), '${queryParam}': pageParam ?? unref(params)?.['${queryParam}']}`;
1341
- return httpClient === OutputHttpClient.FETCH ? `unref(${param.name})` : param.name;
1335
+ if (param.name === "params") return `{...${resolve}(params), '${queryParam}': pageParam ?? ${resolve}(params)?.['${queryParam}']}`;
1336
+ return httpClient === OutputHttpClient.FETCH ? `${resolve}(${param.name})` : param.name;
1342
1337
  }).join(",");
1343
1338
  },
1344
1339
  getQueryReturnType({ type }) {
@@ -1365,12 +1360,21 @@ const createVueAdapter = ({ hasVueQueryV4, hasQueryV5, hasQueryV5WithDataTagErro
1365
1360
  shouldAnnotateQueryKey() {
1366
1361
  return false;
1367
1362
  },
1368
- getUnrefStatements(props) {
1369
- return vueUnRefParams(props.filter((prop) => prop.type === GetterPropType.NAMED_PATH_PARAMS));
1363
+ getRequestUnrefStatements(props) {
1364
+ return vueUnRefParams(props, hasQueryV5);
1365
+ },
1366
+ getQueryOptionsUnrefStatements(props) {
1367
+ return vueUnRefParams(props.filter((prop) => prop.type === GetterPropType.NAMED_PATH_PARAMS), hasQueryV5);
1368
+ },
1369
+ wrapHookMutatorCallback(callback) {
1370
+ return callback;
1370
1371
  },
1371
1372
  generateEnabledOption(params, options) {
1372
1373
  if (params.length === 0) return "";
1373
- if (!isObject(options) || !Object.hasOwn(options, "enabled")) return `enabled: computed(() => ${params.map(({ name }) => `unref(${name}) !== null && unref(${name}) !== undefined`).join(" && ")}),`;
1374
+ if (!isObject(options) || !Object.hasOwn(options, "enabled")) {
1375
+ const { resolve } = getVueReactivity(hasQueryV5);
1376
+ return `enabled: computed(() => ${params.map(({ name }) => `${resolve}(${name}) !== null && ${resolve}(${name}) !== undefined`).join(" && ")}),`;
1377
+ }
1374
1378
  return "";
1375
1379
  },
1376
1380
  getQueryKeyPrefix() {
@@ -1410,9 +1414,6 @@ const createVueAdapter = ({ hasVueQueryV4, hasQueryV5, hasQueryV5WithDataTagErro
1410
1414
  generateMutationHookBody({ operationPrefix, mutationImplementation, hasInvalidation, optionalQueryClientArgument }) {
1411
1415
  return ` ${hasInvalidation ? `const backupQueryClient = useQueryClient();\n ` : ""}return ${operationPrefix}Mutation(${mutationImplementation}${optionalQueryClientArgument ? `, queryClient` : ""});`;
1412
1416
  },
1413
- generateRequestFunction(verbOptions, options) {
1414
- return options.context.output.httpClient === OutputHttpClient.AXIOS ? generateAxiosRequestFunction(verbOptions, options, true) : generateRequestFunction(verbOptions, options);
1415
- },
1416
1417
  getQueryPropertyForProp(prop, body) {
1417
1418
  return prop.type === GetterPropType.BODY ? body.implementation : prop.name;
1418
1419
  }
@@ -1420,100 +1421,108 @@ const createVueAdapter = ({ hasVueQueryV4, hasQueryV5, hasQueryV5WithDataTagErro
1420
1421
  //#endregion
1421
1422
  //#region src/frameworks/index.ts
1422
1423
  /** Fill in defaults for fields that most adapters leave empty or share a common implementation. */
1423
- const withDefaults = (adapter) => ({
1424
- isAngularHttp: false,
1425
- getHttpFirstParam: () => "",
1426
- getMutationHttpPrefix: () => "",
1427
- getUnrefStatements: () => "",
1428
- getQueryInvocationSuffix: () => "",
1429
- transformProps: (props) => props,
1430
- getHttpFunctionQueryProps: (qp) => qp,
1431
- getQueryType: (type) => type,
1432
- shouldDestructureNamedPathParams: () => true,
1433
- shouldAnnotateQueryKey: () => true,
1434
- shouldGenerateOverrideTypes: () => false,
1435
- shouldCastQueryResult: () => true,
1436
- shouldCastQueryOptions: () => true,
1437
- getQueryKeyPrefix: () => "queryOptions?.queryKey ?? ",
1438
- getQueryOptionsDefinitionPrefix: () => "Use",
1439
- getHookPropsDefinitions: (props) => toObjectString(props, "implementation"),
1440
- getQueryKeyRouteString(route, shouldSplitQueryKey) {
1441
- if (shouldSplitQueryKey) return getRouteAsArray(route);
1442
- return `\`${route}\``;
1443
- },
1444
- generateEnabledOption(params, options) {
1445
- if (params.length === 0) return "";
1446
- if (!isObject(options) || !Object.hasOwn(options, "enabled")) return `enabled: ${params.map(({ name }) => `${name} !== null && ${name} !== undefined`).join(" && ")},`;
1447
- return "";
1448
- },
1449
- getQueryPropertyForProp(prop, body) {
1450
- if (prop.type === GetterPropType.NAMED_PATH_PARAMS) return prop.destructured;
1451
- return prop.type === GetterPropType.BODY ? body.implementation : prop.name;
1452
- },
1453
- getInfiniteQueryHttpProps(props, queryParam) {
1454
- return props.map((param) => {
1455
- if (param.type === GetterPropType.NAMED_PATH_PARAMS) return param.destructured;
1456
- return param.name === "params" ? `{...params, '${queryParam}': pageParam ?? params?.['${queryParam}']}` : param.name;
1457
- }).join(",");
1458
- },
1459
- generateQueryInit({ queryOptionsFnName, queryProperties, isRequestOptions }) {
1460
- return `const ${isRequestOptions ? "queryOptions" : "options"} = ${queryOptionsFnName}(${queryProperties}${queryProperties ? "," : ""}${isRequestOptions ? "options" : "queryOptions"})`;
1461
- },
1462
- generateQueryInvocationArgs({ queryOptionsVarName, optionalQueryClientArgument }) {
1463
- return `${queryOptionsVarName}${optionalQueryClientArgument ? ", queryClient" : ""}`;
1464
- },
1465
- getOptionalQueryClientArgument() {
1466
- return adapter.hasQueryV5 ? ", queryClient?: QueryClient" : "";
1467
- },
1468
- generateQueryArguments({ operationName, definitions, mutator, isRequestOptions, type, queryParams, queryParam, initialData, httpClient, hasInvalidation, useRuntimeFetcher }) {
1469
- const definition = getQueryOptionsDefinition({
1470
- operationName,
1471
- mutator,
1472
- definitions,
1473
- type,
1474
- prefix: adapter.getQueryOptionsDefinitionPrefix?.() ?? "Use",
1475
- hasQueryV5: adapter.hasQueryV5,
1476
- hasQueryV5WithInfiniteQueryOptionsError: adapter.hasQueryV5WithInfiniteQueryOptionsError,
1477
- queryParams,
1478
- queryParam,
1479
- isReturnType: false,
1480
- initialData,
1481
- adapter
1482
- });
1483
- if (!isRequestOptions) return `${type ? "queryOptions" : "mutationOptions"}${initialData === "defined" ? "" : "?"}: ${definition}`;
1484
- const requestType = getQueryArgumentsRequestType(httpClient, mutator, useRuntimeFetcher);
1485
- const isQueryRequired = initialData === "defined";
1486
- const optionsType = `{ ${type ? "query" : "mutation"}${isQueryRequired ? "" : "?"}:${definition}, ${!type && hasInvalidation ? "skipInvalidation?: boolean, " : ""}${requestType}}`;
1487
- return `options${isQueryRequired ? "" : "?"}: ${optionsType}\n`;
1488
- },
1489
- generateMutationOnSuccess({ operationName, definitions, isRequestOptions, generateInvalidateCall, uniqueInvalidates }) {
1490
- const invalidateCalls = uniqueInvalidates.map((t) => generateInvalidateCall(t)).join("\n");
1491
- if (adapter.hasQueryV5WithMutationContextOnSuccess) {
1492
- if (isRequestOptions) return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, onMutateResult: TContext, context: MutationFunctionContext) => {
1424
+ const withDefaults = (adapter) => {
1425
+ const composed = {
1426
+ isAngularHttp: false,
1427
+ getHttpFirstParam: () => "",
1428
+ getMutationHttpPrefix: () => "",
1429
+ getRequestUnrefStatements: () => "",
1430
+ getQueryOptionsUnrefStatements: () => "",
1431
+ wrapHookMutatorCallback: (callback, operationName) => `useCallback(${callback}, [${operationName}])`,
1432
+ getQueryInvocationSuffix: () => "",
1433
+ transformProps: (props) => props,
1434
+ getHttpFunctionQueryProps: (qp) => qp,
1435
+ getQueryType: (type) => type,
1436
+ shouldDestructureNamedPathParams: () => true,
1437
+ shouldAnnotateQueryKey: () => true,
1438
+ shouldGenerateOverrideTypes: () => false,
1439
+ shouldCastQueryResult: () => true,
1440
+ shouldCastQueryOptions: () => true,
1441
+ getQueryKeyPrefix: () => "queryOptions?.queryKey ?? ",
1442
+ getQueryOptionsDefinitionPrefix: () => "Use",
1443
+ getHookPropsDefinitions: (props) => toObjectString(props, "implementation"),
1444
+ getQueryKeyRouteString(route, shouldSplitQueryKey) {
1445
+ if (shouldSplitQueryKey) return getRouteAsArray(route);
1446
+ return `\`${route}\``;
1447
+ },
1448
+ generateEnabledOption(params, options) {
1449
+ if (params.length === 0) return "";
1450
+ if (!isObject(options) || !Object.hasOwn(options, "enabled")) return `enabled: ${params.map(({ name }) => `${name} !== null && ${name} !== undefined`).join(" && ")},`;
1451
+ return "";
1452
+ },
1453
+ getQueryPropertyForProp(prop, body) {
1454
+ if (prop.type === GetterPropType.NAMED_PATH_PARAMS) return prop.destructured;
1455
+ return prop.type === GetterPropType.BODY ? body.implementation : prop.name;
1456
+ },
1457
+ generateRequestFunction(verbOptions, options) {
1458
+ return options.context.output.httpClient === OutputHttpClient.AXIOS ? generateAxiosRequestFunction(verbOptions, options, composed) : generateRequestFunction(verbOptions, options);
1459
+ },
1460
+ getInfiniteQueryHttpProps(props, queryParam) {
1461
+ return props.map((param) => {
1462
+ if (param.type === GetterPropType.NAMED_PATH_PARAMS) return param.destructured;
1463
+ return param.name === "params" ? `{...params, '${queryParam}': pageParam ?? params?.['${queryParam}']}` : param.name;
1464
+ }).join(",");
1465
+ },
1466
+ generateQueryInit({ queryOptionsFnName, queryProperties, isRequestOptions }) {
1467
+ return `const ${isRequestOptions ? "queryOptions" : "options"} = ${queryOptionsFnName}(${queryProperties}${queryProperties ? "," : ""}${isRequestOptions ? "options" : "queryOptions"})`;
1468
+ },
1469
+ generateQueryInvocationArgs({ queryOptionsVarName, optionalQueryClientArgument }) {
1470
+ return `${queryOptionsVarName}${optionalQueryClientArgument ? ", queryClient" : ""}`;
1471
+ },
1472
+ getOptionalQueryClientArgument() {
1473
+ return composed.hasQueryV5 ? ", queryClient?: QueryClient" : "";
1474
+ },
1475
+ generateQueryArguments({ operationName, definitions, mutator, isRequestOptions, type, queryParams, queryParam, initialData, httpClient, hasInvalidation, useRuntimeFetcher }) {
1476
+ const definition = getQueryOptionsDefinition({
1477
+ operationName,
1478
+ mutator,
1479
+ definitions,
1480
+ type,
1481
+ prefix: composed.getQueryOptionsDefinitionPrefix(),
1482
+ hasQueryV5: composed.hasQueryV5,
1483
+ hasQueryV5WithInfiniteQueryOptionsError: composed.hasQueryV5WithInfiniteQueryOptionsError,
1484
+ queryParams,
1485
+ queryParam,
1486
+ isReturnType: false,
1487
+ initialData,
1488
+ adapter: composed
1489
+ });
1490
+ if (!isRequestOptions) return `${type ? "queryOptions" : "mutationOptions"}${initialData === "defined" ? "" : "?"}: ${definition}`;
1491
+ const requestType = getQueryArgumentsRequestType(httpClient, mutator, useRuntimeFetcher);
1492
+ const isQueryRequired = initialData === "defined";
1493
+ const optionsType = `{ ${type ? "query" : "mutation"}${isQueryRequired ? "" : "?"}:${definition}, ${!type && hasInvalidation ? "skipInvalidation?: boolean, " : ""}${requestType}}`;
1494
+ return `options${isQueryRequired ? "" : "?"}: ${optionsType}\n`;
1495
+ },
1496
+ generateMutationOnSuccess({ operationName, definitions, isRequestOptions, generateInvalidateCall, uniqueInvalidates }) {
1497
+ const invalidateCalls = uniqueInvalidates.map((t) => generateInvalidateCall(t)).join("\n");
1498
+ if (composed.hasQueryV5WithMutationContextOnSuccess) {
1499
+ if (isRequestOptions) return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, onMutateResult: TContext, context: MutationFunctionContext) => {
1493
1500
  if (!options?.skipInvalidation) {
1494
1501
  ${invalidateCalls}
1495
1502
  }
1496
1503
  mutationOptions?.onSuccess?.(data, variables, onMutateResult, context);
1497
1504
  };`;
1498
- return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, onMutateResult: TContext, context: MutationFunctionContext) => {
1505
+ return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, onMutateResult: TContext, context: MutationFunctionContext) => {
1499
1506
  ${invalidateCalls}
1500
1507
  mutationOptions?.onSuccess?.(data, variables, onMutateResult, context);
1501
1508
  };`;
1502
- } else {
1503
- if (isRequestOptions) return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, context: TContext${adapter.hasQueryV5WithRequiredContextOnSuccess ? "" : " | undefined"}) => {
1509
+ } else {
1510
+ if (isRequestOptions) return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, context: TContext${composed.hasQueryV5WithRequiredContextOnSuccess ? "" : " | undefined"}) => {
1504
1511
  if (!options?.skipInvalidation) {
1505
1512
  ${invalidateCalls}
1506
1513
  }
1507
1514
  mutationOptions?.onSuccess?.(data, variables, context);
1508
1515
  };`;
1509
- return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, context: TContext${adapter.hasQueryV5WithRequiredContextOnSuccess ? "" : " | undefined"}) => {
1516
+ return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, context: TContext${composed.hasQueryV5WithRequiredContextOnSuccess ? "" : " | undefined"}) => {
1510
1517
  ${invalidateCalls}
1511
1518
  mutationOptions?.onSuccess?.(data, variables, context);
1512
1519
  };`;
1513
- }
1514
- },
1515
- ...adapter
1516
- });
1520
+ }
1521
+ },
1522
+ ...adapter
1523
+ };
1524
+ return composed;
1525
+ };
1517
1526
  /**
1518
1527
  * Create a FrameworkAdapter for the given output client, resolving version flags
1519
1528
  * from the packageJson and query config.
@@ -1594,6 +1603,33 @@ const HTTP_METHODS = [
1594
1603
  "head",
1595
1604
  "trace"
1596
1605
  ];
1606
+ const MUTATION_OPERATION_LOCAL_NAMES = new Set([
1607
+ "backupQueryClient",
1608
+ "context",
1609
+ "customOptions",
1610
+ "data",
1611
+ "fetchOptions",
1612
+ "http",
1613
+ "mutationFn",
1614
+ "mutationKey",
1615
+ "mutationOptions",
1616
+ "onMutateResult",
1617
+ "onSuccess",
1618
+ "options",
1619
+ "props",
1620
+ "queryClient",
1621
+ "variables"
1622
+ ]);
1623
+ const getMutationOperationReferenceName = (operationName, localNames) => {
1624
+ if (!localNames.has(operationName)) return operationName;
1625
+ let candidate = camel(`${operationName}-request-fn`);
1626
+ let index = 2;
1627
+ while (localNames.has(candidate)) {
1628
+ candidate = camel(`${operationName}-request-fn-${index}`);
1629
+ index += 1;
1630
+ }
1631
+ return candidate;
1632
+ };
1597
1633
  /**
1598
1634
  * Look up an operation's route and path-parameter metadata from the OpenAPI
1599
1635
  * spec. Matches against both the raw `operationId` and its camelCase form
@@ -1739,10 +1775,14 @@ const generateMutationHook = async ({ verbOptions, options, isRequestOptions, ht
1739
1775
  const bodyOptionalMark = body.isOptional ? "?" : "";
1740
1776
  const definitions = props.map(({ definition, type }) => type === GetterPropType.BODY ? mutator?.bodyTypeName ? `data${bodyOptionalMark}: ${mutator.bodyTypeName}<${body.definition}>` : `data${bodyOptionalMark}: ${body.definition}` : definition).join(";");
1741
1777
  const properties = props.map(({ name, type }) => type === GetterPropType.BODY ? "data" : name).join(",");
1778
+ const operationLocalNames = new Set(MUTATION_OPERATION_LOCAL_NAMES);
1779
+ for (const { name, type } of props) operationLocalNames.add(type === GetterPropType.BODY ? "data" : name);
1742
1780
  const errorType = getQueryErrorType(operationName, response, httpClient, mutator, override.fetch.forceSuccessResponse);
1743
- const dataType = mutator?.isHook ? `ReturnType<typeof use${pascal(operationName)}Hook>` : `typeof ${operationName}`;
1781
+ const operationReferenceName = getMutationOperationReferenceName(operationName, operationLocalNames);
1782
+ const dataType = mutator?.isHook ? `ReturnType<typeof use${pascal(operationName)}Hook>` : `typeof ${operationReferenceName}`;
1783
+ const operationTypeReferenceName = mutator?.isHook ? operationName : operationReferenceName;
1744
1784
  const mutationOptionFnReturnType = getQueryOptionsDefinition({
1745
- operationName,
1785
+ operationName: operationTypeReferenceName,
1746
1786
  mutator,
1747
1787
  definitions,
1748
1788
  prefix: adapter.getQueryOptionsDefinitionPrefix(),
@@ -1762,7 +1802,7 @@ const generateMutationHook = async ({ verbOptions, options, isRequestOptions, ht
1762
1802
  const hasInvalidation = uniqueInvalidates.length > 0 && adapter.supportsMutationInvalidation();
1763
1803
  const useRuntimeFetcher = override.fetch.useRuntimeFetcher;
1764
1804
  const mutationArguments = adapter.generateQueryArguments({
1765
- operationName,
1805
+ operationName: operationTypeReferenceName,
1766
1806
  definitions,
1767
1807
  mutator,
1768
1808
  isRequestOptions,
@@ -1771,7 +1811,7 @@ const generateMutationHook = async ({ verbOptions, options, isRequestOptions, ht
1771
1811
  useRuntimeFetcher
1772
1812
  });
1773
1813
  const mutationArgumentsForOptions = adapter.generateQueryArguments({
1774
- operationName,
1814
+ operationName: operationTypeReferenceName,
1775
1815
  definitions,
1776
1816
  mutator,
1777
1817
  isRequestOptions,
@@ -1787,13 +1827,13 @@ const generateMutationHook = async ({ verbOptions, options, isRequestOptions, ht
1787
1827
 
1788
1828
  ${hooksOptionImplementation}
1789
1829
 
1790
- ${mutator?.isHook ? `const ${operationName} = use${pascal(operationName)}Hook()` : ""}
1830
+ ${mutator?.isHook ? `const ${operationReferenceName} = use${pascal(operationName)}Hook()` : ""}
1791
1831
 
1792
1832
 
1793
1833
  const mutationFn: MutationFunction<Awaited<ReturnType<${dataType}>>, ${definitions ? `{${definitions}}` : "void"}> = (${properties ? "props" : ""}) => {
1794
1834
  ${properties ? `const {${properties}} = props ?? {};` : ""}
1795
1835
 
1796
- return ${operationName}(${adapter.getMutationHttpPrefix(mutator)}${properties}${properties ? "," : ""}${getMutationRequestArgs(isRequestOptions, httpClient, mutator, useRuntimeFetcher)})
1836
+ return ${operationReferenceName}(${adapter.getMutationHttpPrefix(mutator)}${properties}${properties ? "," : ""}${getMutationRequestArgs(isRequestOptions, httpClient, mutator, useRuntimeFetcher)})
1797
1837
  }
1798
1838
 
1799
1839
  ${hasInvalidation ? adapter.generateMutationOnSuccess({
@@ -1832,6 +1872,7 @@ ${hasInvalidation ? adapter.generateMutationOnSuccess({
1832
1872
  });
1833
1873
  return {
1834
1874
  implementation: `
1875
+ ${!mutator?.isHook && operationReferenceName !== operationName ? `const ${operationReferenceName} = ${operationName};` : ""}
1835
1876
  ${mutationOptionsFn}
1836
1877
 
1837
1878
  export type ${pascal(operationName)}MutationResult = NonNullable<Awaited<ReturnType<${dataType}>>>
@@ -2154,7 +2195,7 @@ ${hookOptions}
2154
2195
 
2155
2196
  const queryFn: QueryFunction<Awaited<ReturnType<${mutator?.isHook ? `ReturnType<typeof use${pascal(operationName)}Hook>` : `typeof ${operationName}`}>>${hasQueryV5 && hasInfiniteQueryParam ? `, QueryKey, ${infiniteQueryParamType}` : ""}> = (${queryFnArguments}) => ${operationName}(${httpFunctionProps}${httpFunctionProps ? ", " : ""}${queryOptions});
2156
2197
 
2157
- ${adapter.getUnrefStatements(props)}
2198
+ ${adapter.getQueryOptionsUnrefStatements(props)}
2158
2199
 
2159
2200
  ${queryOptionsMutator ? `const customOptions = ${queryOptionsMutator.name}({ queryKey, queryFn, ${queryOptionsImp}}${queryOptionsMutator.hasSecondArg ? `, { ${queryProperties} }` : ""}${queryOptionsMutator.hasThirdArg ? `, { url: \`${route}\`, operationId: '${operationId}', operationName: '${operationName}' }` : ""});` : ""}
2160
2201
 
@@ -2467,11 +2508,19 @@ const WITH_QUERY_KEY_HELPER = `const withQueryKey = <T extends object, K>(query:
2467
2508
  };`;
2468
2509
  const generateQueryHeader = (params) => {
2469
2510
  const needsWithQueryKey = params.clientImplementation.includes("withQueryKey(");
2470
- return `${params.hasAwaitedType ? "" : `type AwaitedInput<T> = PromiseLike<T> | T;\n
2511
+ const innerHeader = getQueryHeader(params);
2512
+ const innerImpl = typeof innerHeader === "string" ? innerHeader : innerHeader.implementation;
2513
+ const innerSharedTypes = typeof innerHeader === "string" ? void 0 : innerHeader.sharedTypes;
2514
+ const ownImplementation = `${params.hasAwaitedType ? "" : `type AwaitedInput<T> = PromiseLike<T> | T;\n
2471
2515
  type Awaited<O> = O extends AwaitedInput<infer T> ? T : never;\n\n`}
2472
2516
  ${params.isRequestOptions && params.isMutator ? `type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];\n\n` : ""}
2473
- ${getQueryHeader(params)}
2517
+ ${innerImpl}
2474
2518
  ${needsWithQueryKey ? `${WITH_QUERY_KEY_HELPER}\n\n` : ""}`;
2519
+ if (innerSharedTypes && innerSharedTypes.length > 0) return {
2520
+ implementation: ownImplementation,
2521
+ sharedTypes: innerSharedTypes
2522
+ };
2523
+ return ownImplementation;
2475
2524
  };
2476
2525
  const generateQuery = async (verbOptions, options, outputClient) => {
2477
2526
  const isZodOutput = typeof options.context.output.schemas === "object" && options.context.output.schemas.type === "zod";