@orval/query 8.23.0 → 8.25.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.d.mts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { ClientBuilder, ClientDependenciesBuilder, ClientHeaderBuilder, NormalizedOutputOptions, QueryOptions } from "@orval/core";
2
-
3
2
  //#region src/dependencies.d.ts
4
3
  declare const getSvelteQueryDependencies: ClientDependenciesBuilder;
5
4
  declare const getReactQueryDependencies: ClientDependenciesBuilder;
@@ -10,11 +9,7 @@ declare const getAngularQueryDependencies: ClientDependenciesBuilder;
10
9
  //#region src/index.d.ts
11
10
  declare const generateQueryHeader: ClientHeaderBuilder;
12
11
  declare const generateQuery: ClientBuilder;
13
- declare const builder: ({
14
- type,
15
- options: queryOptions,
16
- output
17
- }?: {
12
+ declare const builder: ({ type, options: queryOptions, output }?: {
18
13
  type?: "react-query" | "vue-query" | "svelte-query" | "angular-query" | "solid-query";
19
14
  options?: QueryOptions;
20
15
  output?: NormalizedOutputOptions;
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, getRoute, getRouteAsArray, getSuccessResponseType, isObject, isOperationInTagBucket, isString, isSyntheticDefaultImportsAllow, jsDoc, logWarning, makeRouteSafe, mergeDeep, pascal, stringify, toObjectString } from "@orval/core";
1
+ import { GetterPropType, OutputClient, OutputHttpClient, Verbs, camel, compareVersions, generateFormDataAndUrlEncodedFunction, generateMutator, generateMutatorConfig, generateMutatorRequestOptions, generateOptions, generateResponseDateDeserializer, generateVerbImports, getAngularFilteredParamsCallExpression, getAngularFilteredParamsHelperBody, getFullRoute, getRoute, 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";
@@ -180,9 +180,7 @@ const generateAngularHttpRequestFunction = ({ headers, queryParams, operationNam
180
180
  case "delete":
181
181
  httpCall = bodyArg ? `http.${verb}${httpGeneric}(url, { ${httpOptions.length > 0 ? httpOptions.join(", ") + ", " : ""}body: ${bodyArg} })` : `http.${verb}${httpGeneric}(url${optionsStr})`;
182
182
  break;
183
- default:
184
- httpCall = `http.${verb}${httpGeneric}(url, ${bodyArg || "undefined"}${optionsStr})`;
185
- break;
183
+ default: httpCall = `http.${verb}${httpGeneric}(url, ${bodyArg || "undefined"}${optionsStr})`;
186
184
  }
187
185
  const responseType = response.definition.success;
188
186
  const isPrimitiveType = [
@@ -227,6 +225,13 @@ const generateAxiosRequestFunction = ({ headers, queryParams, operationName, res
227
225
  isFormData,
228
226
  isFormUrlEncoded
229
227
  });
228
+ const dateDeserializer = override.useDatesTransform ? generateResponseDateDeserializer({
229
+ operationName,
230
+ response,
231
+ context
232
+ }) : void 0;
233
+ const dateDeserializerImplementation = dateDeserializer ? `\n${dateDeserializer.implementation}` : "";
234
+ const thenDateDeserializer = dateDeserializer ? `.then(${dateDeserializer.name})` : "";
230
235
  if (mutator) {
231
236
  const mutatorConfig = generateMutatorConfig({
232
237
  route,
@@ -253,14 +258,14 @@ const generateAxiosRequestFunction = ({ headers, queryParams, operationName, res
253
258
  ${bodyForm}
254
259
  return ${operationName}(
255
260
  ${mutatorConfig},
256
- ${requestOptions});
261
+ ${requestOptions})${thenDateDeserializer};
257
262
  }`;
258
263
  return `${override.query.shouldExportMutatorHooks ? "export " : ""}const use${pascal(operationName)}Hook = () => {
259
264
  const ${operationName} = ${mutator.name}<${response.definition.success || "unknown"}>();
260
265
 
261
266
  return ${adapter.wrapHookMutatorCallback(callback, operationName)}
262
267
  }
263
- `;
268
+ ${dateDeserializerImplementation}`;
264
269
  }
265
270
  return `${override.query.shouldExportHttpClient ? "export " : ""}const ${operationName} = (\n ${propsImplementation}\n ${isRequestOptions && mutator.hasSecondArg ? `options${context.output.optionsParamRequired ? "" : "?"}: SecondParameter<typeof ${mutator.name}>,` : ""}${getSignalDefinition({
266
271
  hasSignal,
@@ -270,9 +275,9 @@ const generateAxiosRequestFunction = ({ headers, queryParams, operationName, res
270
275
  ${bodyForm}
271
276
  return ${mutator.name}<${response.definition.success || "unknown"}>(
272
277
  ${mutatorConfig},
273
- ${requestOptions});
278
+ ${requestOptions})${thenDateDeserializer};
274
279
  }
275
- `;
280
+ ${dateDeserializerImplementation}`;
276
281
  }
277
282
  const isSyntheticDefaultImportsAllowed = isSyntheticDefaultImportsAllow(context.output.tsconfig);
278
283
  const options = generateOptions({
@@ -300,9 +305,9 @@ const generateAxiosRequestFunction = ({ headers, queryParams, operationName, res
300
305
  return `${override.query.shouldExportHttpClient ? "export " : ""}const ${operationName} = (\n ${queryProps} ${optionsArgs} ): Promise<AxiosResponse<${response.definition.success || "unknown"}>> => {
301
306
  ${unrefStatements}
302
307
  ${bodyForm}
303
- return axios${isSyntheticDefaultImportsAllowed ? "" : ".default"}.${verb}(${options});
308
+ return axios${isSyntheticDefaultImportsAllowed ? "" : ".default"}.${verb}(${options})${dateDeserializer ? `.then((res) => { res.data = ${dateDeserializer.name}(res.data); return res; })` : ""};
304
309
  }
305
- `;
310
+ ${dateDeserializerImplementation}`;
306
311
  };
307
312
  const generateRequestOptionsArguments = ({ isRequestOptions, hasSignal, hasSignalParam = false }) => {
308
313
  if (isRequestOptions) return "options?: AxiosRequestConfig\n";
@@ -352,9 +357,11 @@ const getQueryOptions = ({ isRequestOptions, mutator, isExactOptionalPropertyTyp
352
357
  const getHookOptions = ({ isRequestOptions, httpClient, mutator, useRuntimeFetcher = false }) => {
353
358
  if (!isRequestOptions) return "";
354
359
  let value = "const {query: queryOptions";
355
- if (!mutator) if (httpClient === OutputHttpClient.AXIOS) value += ", axios: axiosOptions";
356
- else if (httpClient === OutputHttpClient.FETCH && useRuntimeFetcher) value += ", fetch: fetchOptions, fetcher: fetcherFn";
357
- else value += ", fetch: fetchOptions";
360
+ if (!mutator) {
361
+ if (httpClient === OutputHttpClient.AXIOS) value += ", axios: axiosOptions";
362
+ else if (httpClient === OutputHttpClient.FETCH && useRuntimeFetcher) value += ", fetch: fetchOptions, fetcher: fetcherFn";
363
+ else value += ", fetch: fetchOptions";
364
+ }
358
365
  if (mutator?.hasSecondArg) value += ", request: requestOptions";
359
366
  value += "} = options ?? {};";
360
367
  return value;
@@ -715,6 +722,12 @@ const getSolidQueryImports = (prefix, hasRenamedOptionsTypes) => {
715
722
  { name: "MutationFunction" },
716
723
  { name: `${capitalized}QueryResult` },
717
724
  { name: `${capitalized}InfiniteQueryResult` },
725
+ { name: `Defined${capitalized}QueryResult` },
726
+ { name: `Defined${capitalized}InfiniteQueryResult` },
727
+ { name: "DefinedInitialDataOptions" },
728
+ { name: "UndefinedInitialDataOptions" },
729
+ { name: "DefinedInitialDataInfiniteOptions" },
730
+ { name: "UndefinedInitialDataInfiniteOptions" },
718
731
  { name: "QueryKey" },
719
732
  { name: "InfiniteData" },
720
733
  { name: `${capitalized}MutationResult` },
@@ -906,10 +919,16 @@ const QueryType = {
906
919
  SUSPENSE_QUERY: "suspenseQuery",
907
920
  SUSPENSE_INFINITE: "suspenseInfiniteQuery"
908
921
  };
909
- const INFINITE_QUERY_PROPERTIES = new Set(["getNextPageParam", "getPreviousPageParam"]);
922
+ const INFINITE_QUERY_PROPERTIES = /* @__PURE__ */ new Set(["getNextPageParam", "getPreviousPageParam"]);
923
+ /**
924
+ * Whether a key from `override.query.options` reaches the emitted options
925
+ * literal for this query type. Page-param callbacks are meaningless on a plain
926
+ * query, so they are dropped there.
927
+ */
928
+ const isConfiguredOptionEmitted = (key, type) => isInfiniteQuery(type) || !INFINITE_QUERY_PROPERTIES.has(key);
910
929
  const generateQueryOptions = ({ params, options, type, adapter }) => {
911
930
  if (options === false) return "";
912
- const queryConfig = isObject(options) ? ` ${stringify(omitBy(options, (_, key) => type !== QueryType.INFINITE && type !== QueryType.SUSPENSE_INFINITE && INFINITE_QUERY_PROPERTIES.has(key)))?.slice(1, -1)}` : "";
931
+ const queryConfig = isObject(options) ? ` ${stringify(omitBy(options, (_, key) => !isConfiguredOptionEmitted(key, type)))?.slice(1, -1)}` : "";
913
932
  if (params.length === 0 || isSuspenseQuery(type)) {
914
933
  if (options) return `${queryConfig} ...queryOptions`;
915
934
  return "...queryOptions";
@@ -919,20 +938,66 @@ const generateQueryOptions = ({ params, options, type, adapter }) => {
919
938
  const isSuspenseQuery = (type) => {
920
939
  return [QueryType.SUSPENSE_INFINITE, QueryType.SUSPENSE_QUERY].includes(type);
921
940
  };
922
- const getQueryOptionsDefinition = ({ operationName, mutator, definitions, type, prefix, hasQueryV5, hasQueryV5WithInfiniteQueryOptionsError, queryParams, queryParam, isReturnType, initialData, adapter }) => {
941
+ const isInfiniteQuery = (type) => {
942
+ return [QueryType.INFINITE, QueryType.SUSPENSE_INFINITE].includes(type);
943
+ };
944
+ const getOptionsKind = (type) => isInfiniteQuery(type) ? "infiniteQuery" : "query";
945
+ /**
946
+ * Resolves the adapter's constraint together with the plain options type it has
947
+ * to be rendered against. Both are optional on `FrameworkAdapter` and neither is
948
+ * useful alone: without a type name there is nothing to `Pick` from, and without
949
+ * required keys the caller has nothing to supply. Returning them as one value is
950
+ * what stops the signature and the type disagreeing about whether `options` is
951
+ * mandatory.
952
+ */
953
+ const resolveUserQueryOptionsConstraint = (adapter, type, options) => {
954
+ const constraint = adapter?.getUserQueryOptionsConstraint?.(type);
955
+ if (!constraint) return;
956
+ const optionsTypeName = adapter?.getOptionsReturnTypeName?.(getOptionsKind(type));
957
+ if (!optionsTypeName) return;
958
+ const require = isObject(options) ? constraint.require?.filter((key) => !(isConfiguredOptionEmitted(key, type) && Object.hasOwn(options, key))) : constraint.require;
959
+ return {
960
+ ...constraint,
961
+ require,
962
+ optionsTypeName
963
+ };
964
+ };
965
+ /**
966
+ * Whether the caller must supply options the generator cannot infer, which is
967
+ * what makes the whole `options` parameter mandatory. An `exclude`-only
968
+ * constraint reshapes the type without requiring anything, so it does not count.
969
+ */
970
+ const requiresUserSuppliedQueryOptions = (adapter, type, options) => !!type && !!resolveUserQueryOptionsConstraint(adapter, type, options)?.require?.length;
971
+ const getQueryOptionsDefinition = ({ operationName, mutator, definitions, type, prefix, hasQueryV5, hasQueryV5WithInfiniteQueryOptionsError, queryParams, queryParam, isReturnType, initialData, adapter, options }) => {
923
972
  const isMutatorHook = mutator?.isHook;
924
973
  const partialOptions = !isReturnType && hasQueryV5;
925
974
  if (type) {
926
975
  const funcReturnType = `Awaited<ReturnType<${isMutatorHook ? `ReturnType<typeof use${pascal(operationName)}Hook>` : `typeof ${operationName}`}>>`;
927
- const optionTypeInitialDataPostfix = initialData && !isSuspenseQuery(type) ? ` & Pick<
928
- ${pascal(initialData)}InitialDataOptions<
976
+ const isInfiniteType = isInfiniteQuery(type);
977
+ const infiniteTypeArgs = hasQueryV5 && isInfiniteType && queryParam && queryParams ? `, QueryKey, ${queryParams.schema.name}['${queryParam}']` : "";
978
+ const initialDataOptionsType = initialData && adapter?.getInitialDataOptionsType ? adapter.getInitialDataOptionsType({
979
+ initialData,
980
+ isInfinite: isInfiniteType,
981
+ funcReturnType,
982
+ infiniteTypeArgs
983
+ }) : `${pascal(initialData ?? "")}InitialDataOptions<
929
984
  ${funcReturnType},
930
985
  TError,
931
- ${funcReturnType}${hasQueryV5 && (type === QueryType.INFINITE || type === QueryType.SUSPENSE_INFINITE) && queryParam && queryParams ? `, QueryKey` : ""}
932
- > , 'initialData'
986
+ ${funcReturnType}${hasQueryV5 && isInfiniteType && queryParam && queryParams ? `, QueryKey` : ""}
987
+ >`;
988
+ const optionTypeInitialDataPostfix = initialData && !isSuspenseQuery(type) ? ` & Pick<
989
+ ${initialDataOptionsType} , 'initialData'
933
990
  >` : "";
934
- const optionsTypeName = isReturnType && adapter?.getOptionsReturnTypeName ? adapter.getOptionsReturnTypeName(type === QueryType.INFINITE || type === QueryType.SUSPENSE_INFINITE ? "infiniteQuery" : "query") : void 0;
935
- const optionType = optionsTypeName ? `${optionsTypeName}<${funcReturnType}, TError, TData${hasQueryV5 && (type === QueryType.INFINITE || type === QueryType.SUSPENSE_INFINITE) && queryParam && queryParams ? `, QueryKey, ${queryParams.schema.name}['${queryParam}']` : ""}>` : `${prefix}${pascal(type)}Options<${funcReturnType}, TError, TData${hasQueryV5 && (type === QueryType.INFINITE || type === QueryType.SUSPENSE_INFINITE) && queryParam && queryParams ? hasQueryV5WithInfiniteQueryOptionsError ? `, QueryKey, ${queryParams.schema.name}['${queryParam}']` : `, ${funcReturnType}, QueryKey, ${queryParams.schema.name}['${queryParam}']` : ""}>`;
991
+ const userOptionsConstraint = isReturnType ? void 0 : resolveUserQueryOptionsConstraint(adapter, type, options);
992
+ if (userOptionsConstraint) {
993
+ const { optionsTypeName, require = [], exclude = [] } = userOptionsConstraint;
994
+ const plainOptionsType = `${optionsTypeName}<${funcReturnType}, TError, TData${infiniteTypeArgs}>`;
995
+ const quoteKeys = (keys) => keys.map((key) => `'${key}'`).join(" | ");
996
+ const omitted = [...require, ...exclude];
997
+ return `${omitted.length ? `Omit<Partial<${plainOptionsType}>, ${quoteKeys(omitted)}>` : `Partial<${plainOptionsType}>`}${require.length ? ` & Pick<${plainOptionsType}, ${quoteKeys(require)}>` : ""}${optionTypeInitialDataPostfix}`;
998
+ }
999
+ const optionsTypeName = isReturnType ? adapter?.getOptionsReturnTypeName?.(getOptionsKind(type)) : void 0;
1000
+ const optionType = optionsTypeName ? `${optionsTypeName}<${funcReturnType}, TError, TData${infiniteTypeArgs}>` : `${prefix}${pascal(type)}Options<${funcReturnType}, TError, TData${hasQueryV5 && isInfiniteType && queryParam && queryParams ? hasQueryV5WithInfiniteQueryOptionsError ? `, QueryKey, ${queryParams.schema.name}['${queryParam}']` : `, ${funcReturnType}, QueryKey, ${queryParams.schema.name}['${queryParam}']` : ""}>`;
936
1001
  return `${partialOptions ? "Partial<" : ""}${optionType}${partialOptions ? ">" : ""}${optionTypeInitialDataPostfix}`;
937
1002
  }
938
1003
  const mutationOptionsTypeName = adapter?.getOptionsReturnTypeName ? adapter.getOptionsReturnTypeName("mutation") : void 0;
@@ -1117,6 +1182,11 @@ const createReactAdapter = ({ hasQueryV5, hasQueryV5WithDataTagError, hasQueryV5
1117
1182
  });
1118
1183
  //#endregion
1119
1184
  //#region src/frameworks/solid.ts
1185
+ const QUERY_OPTIONS_CONSTRAINT = { exclude: ["initialData"] };
1186
+ const INFINITE_QUERY_OPTIONS_CONSTRAINT = {
1187
+ require: ["initialPageParam", "getNextPageParam"],
1188
+ exclude: ["initialData"]
1189
+ };
1120
1190
  const createSolidAdapter = ({ hasQueryV5, hasQueryV5WithDataTagError, hasQueryV5WithInfiniteQueryOptionsError, hasQueryV5WithMutationContextOnSuccess, hasQueryV5WithRequiredContextOnSuccess, hasSolidQueryUsePrefix, hasSolidQueryRenamedOptionsTypes }) => ({
1121
1191
  outputClient: OutputClient.SOLID_QUERY,
1122
1192
  hookPrefix: hasSolidQueryUsePrefix ? "use" : "create",
@@ -1145,11 +1215,25 @@ const createSolidAdapter = ({ hasQueryV5, hasQueryV5WithDataTagError, hasQueryV5
1145
1215
  shouldCastQueryOptions() {
1146
1216
  return false;
1147
1217
  },
1148
- getQueryReturnType({ type }) {
1218
+ getUserQueryOptionsConstraint(type) {
1219
+ if (!hasQueryV5) return;
1220
+ if (isInfiniteQuery(type)) return INFINITE_QUERY_OPTIONS_CONSTRAINT;
1221
+ return hasSolidQueryUsePrefix ? QUERY_OPTIONS_CONSTRAINT : void 0;
1222
+ },
1223
+ getQueryType(type) {
1224
+ return getQueryTypeForFramework(type);
1225
+ },
1226
+ shouldGenerateOverrideTypes() {
1227
+ return hasQueryV5 && hasSolidQueryUsePrefix;
1228
+ },
1229
+ getInitialDataOptionsType({ initialData, isInfinite, funcReturnType, infiniteTypeArgs }) {
1230
+ return `ReturnType<${`${pascal(initialData)}InitialData${isInfinite ? "Infinite" : ""}Options`}<${funcReturnType}, TError, TData${infiniteTypeArgs}>>`;
1231
+ },
1232
+ getQueryReturnType({ type, isInitialDataDefined }) {
1149
1233
  const prefix = hasSolidQueryUsePrefix ? "Use" : "Create";
1150
1234
  const queryKeyType = hasQueryV5 ? `DataTag<QueryKey, TData${hasQueryV5WithDataTagError ? ", TError" : ""}>` : "QueryKey";
1151
- if (type !== QueryType.INFINITE && type !== QueryType.SUSPENSE_INFINITE) return `${prefix}QueryResult<TData, TError> & { queryKey: ${queryKeyType} }`;
1152
- return `${prefix}InfiniteQueryResult<TData, TError> & { queryKey: ${queryKeyType} }`;
1235
+ const resultName = isInfiniteQuery(type) ? "InfiniteQueryResult" : "QueryResult";
1236
+ return `${isInitialDataDefined ? "Defined" : ""}${prefix}${resultName}<TData, TError> & { queryKey: ${queryKeyType} }`;
1153
1237
  },
1154
1238
  getMutationReturnType({ dataType, variableType }) {
1155
1239
  return `: ${hasSolidQueryUsePrefix ? "Use" : "Create"}MutationResult<
@@ -1472,24 +1556,27 @@ const withDefaults = (adapter) => {
1472
1556
  getOptionalQueryClientArgument() {
1473
1557
  return composed.hasQueryV5 ? ", queryClient?: QueryClient" : "";
1474
1558
  },
1475
- generateQueryArguments({ operationName, definitions, mutator, isRequestOptions, type, queryParams, queryParam, initialData, httpClient, hasInvalidation, useRuntimeFetcher }) {
1559
+ generateQueryArguments({ operationName, definitions, mutator, isRequestOptions, type, queryParams, queryParam, initialData, httpClient, hasInvalidation, useRuntimeFetcher, options }) {
1560
+ const prefix = composed.getQueryOptionsDefinitionPrefix();
1476
1561
  const definition = getQueryOptionsDefinition({
1477
1562
  operationName,
1478
1563
  mutator,
1479
1564
  definitions,
1480
1565
  type,
1481
- prefix: composed.getQueryOptionsDefinitionPrefix(),
1566
+ prefix,
1482
1567
  hasQueryV5: composed.hasQueryV5,
1483
1568
  hasQueryV5WithInfiniteQueryOptionsError: composed.hasQueryV5WithInfiniteQueryOptionsError,
1484
1569
  queryParams,
1485
1570
  queryParam,
1486
1571
  isReturnType: false,
1487
1572
  initialData,
1488
- adapter: composed
1573
+ adapter: composed,
1574
+ options
1489
1575
  });
1490
- if (!isRequestOptions) return `${type ? "queryOptions" : "mutationOptions"}${initialData === "defined" ? "" : "?"}: ${definition}`;
1576
+ const requiresUserQueryOptions = requiresUserSuppliedQueryOptions(composed, type, options);
1577
+ if (!isRequestOptions) return `${type ? "queryOptions" : "mutationOptions"}${initialData === "defined" || requiresUserQueryOptions ? "" : "?"}: ${definition}`;
1491
1578
  const requestType = getQueryArgumentsRequestType(httpClient, mutator, useRuntimeFetcher);
1492
- const isQueryRequired = initialData === "defined";
1579
+ const isQueryRequired = initialData === "defined" || requiresUserQueryOptions;
1493
1580
  const optionsType = `{ ${type ? "query" : "mutation"}${isQueryRequired ? "" : "?"}:${definition}, ${!type && hasInvalidation ? "skipInvalidation?: boolean, " : ""}${requestType}}`;
1494
1581
  return `options${isQueryRequired ? "" : "?"}: ${optionsType}\n`;
1495
1582
  },
@@ -1535,23 +1622,30 @@ const createFrameworkAdapter = ({ outputClient, packageJson, queryVersion }) =>
1535
1622
  const _hasQueryV5WithMutationContextOnSuccess = isQueryV5WithMutationContextOnSuccess(packageJson, clientType);
1536
1623
  const _hasQueryV5WithRequiredContextOnSuccess = isQueryV5WithRequiredContextOnSuccess(packageJson, clientType);
1537
1624
  switch (outputClient) {
1538
- case OutputClient.VUE_QUERY: return withDefaults(createVueAdapter({
1539
- hasVueQueryV4: !isVueQueryV3(packageJson) || queryVersion === 4,
1540
- hasQueryV5: _hasQueryV5,
1541
- hasQueryV5WithDataTagError: _hasQueryV5WithDataTagError,
1542
- hasQueryV5WithInfiniteQueryOptionsError: _hasQueryV5WithInfiniteQueryOptionsError,
1543
- hasQueryV5WithMutationContextOnSuccess: _hasQueryV5WithMutationContextOnSuccess,
1544
- hasQueryV5WithRequiredContextOnSuccess: _hasQueryV5WithRequiredContextOnSuccess
1545
- }));
1546
- case OutputClient.SVELTE_QUERY: return withDefaults(createSvelteAdapter({
1547
- hasSvelteQueryV4: !isSvelteQueryV3(packageJson) || queryVersion === 4,
1548
- hasSvelteQueryV6: isSvelteQueryV6(packageJson),
1549
- hasQueryV5: _hasQueryV5,
1550
- hasQueryV5WithDataTagError: _hasQueryV5WithDataTagError,
1551
- hasQueryV5WithInfiniteQueryOptionsError: _hasQueryV5WithInfiniteQueryOptionsError,
1552
- hasQueryV5WithMutationContextOnSuccess: _hasQueryV5WithMutationContextOnSuccess,
1553
- hasQueryV5WithRequiredContextOnSuccess: _hasQueryV5WithRequiredContextOnSuccess
1554
- }));
1625
+ case OutputClient.VUE_QUERY: {
1626
+ const hasVueQueryV4 = !isVueQueryV3(packageJson) || queryVersion === 4;
1627
+ return withDefaults(createVueAdapter({
1628
+ hasVueQueryV4,
1629
+ hasQueryV5: _hasQueryV5,
1630
+ hasQueryV5WithDataTagError: _hasQueryV5WithDataTagError,
1631
+ hasQueryV5WithInfiniteQueryOptionsError: _hasQueryV5WithInfiniteQueryOptionsError,
1632
+ hasQueryV5WithMutationContextOnSuccess: _hasQueryV5WithMutationContextOnSuccess,
1633
+ hasQueryV5WithRequiredContextOnSuccess: _hasQueryV5WithRequiredContextOnSuccess
1634
+ }));
1635
+ }
1636
+ case OutputClient.SVELTE_QUERY: {
1637
+ const hasSvelteQueryV4 = !isSvelteQueryV3(packageJson) || queryVersion === 4;
1638
+ const _hasSvelteQueryV6 = isSvelteQueryV6(packageJson);
1639
+ return withDefaults(createSvelteAdapter({
1640
+ hasSvelteQueryV4,
1641
+ hasSvelteQueryV6: _hasSvelteQueryV6,
1642
+ hasQueryV5: _hasQueryV5,
1643
+ hasQueryV5WithDataTagError: _hasQueryV5WithDataTagError,
1644
+ hasQueryV5WithInfiniteQueryOptionsError: _hasQueryV5WithInfiniteQueryOptionsError,
1645
+ hasQueryV5WithMutationContextOnSuccess: _hasQueryV5WithMutationContextOnSuccess,
1646
+ hasQueryV5WithRequiredContextOnSuccess: _hasQueryV5WithRequiredContextOnSuccess
1647
+ }));
1648
+ }
1555
1649
  case OutputClient.ANGULAR_QUERY: return withDefaults(createAngularAdapter({
1556
1650
  hasQueryV5: _hasQueryV5,
1557
1651
  hasQueryV5WithDataTagError: _hasQueryV5WithDataTagError,
@@ -1559,15 +1653,19 @@ const createFrameworkAdapter = ({ outputClient, packageJson, queryVersion }) =>
1559
1653
  hasQueryV5WithMutationContextOnSuccess: _hasQueryV5WithMutationContextOnSuccess,
1560
1654
  hasQueryV5WithRequiredContextOnSuccess: _hasQueryV5WithRequiredContextOnSuccess
1561
1655
  }));
1562
- case OutputClient.SOLID_QUERY: return withDefaults(createSolidAdapter({
1563
- hasQueryV5: _hasQueryV5,
1564
- hasQueryV5WithDataTagError: _hasQueryV5WithDataTagError,
1565
- hasQueryV5WithInfiniteQueryOptionsError: _hasQueryV5WithInfiniteQueryOptionsError,
1566
- hasQueryV5WithMutationContextOnSuccess: _hasQueryV5WithMutationContextOnSuccess,
1567
- hasQueryV5WithRequiredContextOnSuccess: _hasQueryV5WithRequiredContextOnSuccess,
1568
- hasSolidQueryUsePrefix: isSolidQueryWithUsePrefix(packageJson),
1569
- hasSolidQueryRenamedOptionsTypes: isSolidQueryWithRenamedOptionsTypes(packageJson)
1570
- }));
1656
+ case OutputClient.SOLID_QUERY: {
1657
+ const hasSolidQueryWithUsePrefix = isSolidQueryWithUsePrefix(packageJson);
1658
+ const hasSolidQueryWithRenamedOptionsTypes = isSolidQueryWithRenamedOptionsTypes(packageJson);
1659
+ return withDefaults(createSolidAdapter({
1660
+ hasQueryV5: _hasQueryV5,
1661
+ hasQueryV5WithDataTagError: _hasQueryV5WithDataTagError,
1662
+ hasQueryV5WithInfiniteQueryOptionsError: _hasQueryV5WithInfiniteQueryOptionsError,
1663
+ hasQueryV5WithMutationContextOnSuccess: _hasQueryV5WithMutationContextOnSuccess,
1664
+ hasQueryV5WithRequiredContextOnSuccess: _hasQueryV5WithRequiredContextOnSuccess,
1665
+ hasSolidQueryUsePrefix: hasSolidQueryWithUsePrefix,
1666
+ hasSolidQueryRenamedOptionsTypes: hasSolidQueryWithRenamedOptionsTypes
1667
+ }));
1668
+ }
1571
1669
  default: return withDefaults(createReactAdapter({
1572
1670
  hasQueryV5: _hasQueryV5,
1573
1671
  hasQueryV5WithDataTagError: _hasQueryV5WithDataTagError,
@@ -1603,7 +1701,7 @@ const HTTP_METHODS = [
1603
1701
  "head",
1604
1702
  "trace"
1605
1703
  ];
1606
- const MUTATION_OPERATION_LOCAL_NAMES = new Set([
1704
+ const MUTATION_OPERATION_LOCAL_NAMES = /* @__PURE__ */ new Set([
1607
1705
  "backupQueryClient",
1608
1706
  "context",
1609
1707
  "customOptions",
@@ -1914,6 +2012,24 @@ const hasQueryParam = (queryParams, queryParam) => {
1914
2012
  if (!queryParam || !queryParams) return false;
1915
2013
  return queryParams.paramNames?.includes(queryParam) ?? true;
1916
2014
  };
2015
+ /**
2016
+ * When nothing is configured, infinite hooks stay allowed, just without a
2017
+ * page param. When candidates are configured but the operation declares none
2018
+ * of them, the infinite hook is suppressed so orval does not emit a useless
2019
+ * one for a non-paginated `GET`.
2020
+ */
2021
+ const resolveInfiniteQueryParam = (queryParams, useInfiniteQueryParam) => {
2022
+ const candidates = (Array.isArray(useInfiniteQueryParam) ? useInfiniteQueryParam : [useInfiniteQueryParam]).filter((name) => !!name);
2023
+ if (candidates.length === 0) return {
2024
+ queryParam: void 0,
2025
+ infiniteHookAllowed: true
2026
+ };
2027
+ const queryParam = candidates.find((name) => hasQueryParam(queryParams, name));
2028
+ return {
2029
+ queryParam,
2030
+ infiniteHookAllowed: queryParam !== void 0
2031
+ };
2032
+ };
1917
2033
  const escapeRegExpMetaChars = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
1918
2034
  /**
1919
2035
  * Wraps the body parameter's type in a property string with the mutator's
@@ -1982,8 +2098,29 @@ const renderSetQueryDataHelper = ({ doc, isReactQuery, fnName, propsSig, body })
1982
2098
  }\n`;
1983
2099
  };
1984
2100
  /**
2101
+ * Rewrites `name?: T` to `name: undefined | T` so a required parameter can follow
2102
+ * it (TS1016).
2103
+ *
2104
+ * Keep `undefined` first. `wrapPropsBodyWithMutatorBodyType` matches an optional
2105
+ * `undefined\s*\|\s*` prefix when it swaps in a mutator body type, and misses the
2106
+ * `T | undefined` form that `allowUndefinedParam` emits.
2107
+ */
2108
+ const widenOptionalPropsToUndefined = (props, field) => props.map((prop) => {
2109
+ const regex = new RegExp(String.raw`^${escapeRegExpMetaChars(prop.name)}\s*\?:`);
2110
+ if (!regex.test(prop[field])) return prop;
2111
+ const widened = prop[field].replace(regex, `${prop.name}: undefined | `);
2112
+ return field === "definition" ? {
2113
+ ...prop,
2114
+ definition: widened
2115
+ } : {
2116
+ ...prop,
2117
+ implementation: widened
2118
+ };
2119
+ });
2120
+ /**
1985
2121
  * Renders the prop list shared by `getXxxQueryKey`, `setXxxQueryData` and
1986
- * `getXxxQueryData` helpers: headers are dropped, path params stay required,
2122
+ * `getXxxQueryData` helpers: headers are dropped (unless `includeHeaders`
2123
+ * is set — key-mutator factories need them), path params stay required,
1987
2124
  * non-path params (query params, body) are passed through `widenNonPath`
1988
2125
  * (defaults to identity — pass `makeOptionalParam` or `allowUndefinedParam`
1989
2126
  * to relax the signature).
@@ -1991,8 +2128,8 @@ const renderSetQueryDataHelper = ({ doc, isReactQuery, fnName, propsSig, body })
1991
2128
  * Centralising this prevents the three call sites from drifting apart on
1992
2129
  * how they treat the same props.
1993
2130
  */
1994
- const buildKeyShapedProps = ({ props, body, mutator, widenNonPath = (impl) => impl }) => wrapPropsBodyWithMutatorBodyType({
1995
- propsString: toObjectString(props.filter((prop) => prop.type !== GetterPropType.HEADER).map((prop) => ({
2131
+ const buildKeyShapedProps = ({ props, body, mutator, widenNonPath = (impl) => impl, includeHeaders = false }) => wrapPropsBodyWithMutatorBodyType({
2132
+ propsString: toObjectString(props.filter((prop) => includeHeaders || prop.type !== GetterPropType.HEADER).map((prop) => ({
1996
2133
  ...prop,
1997
2134
  implementation: prop.type === GetterPropType.PARAM || prop.type === GetterPropType.NAMED_PATH_PARAMS ? prop.implementation : widenNonPath(prop.implementation)
1998
2135
  })), "implementation"),
@@ -2051,21 +2188,15 @@ const generatePrefetch = ({ usePrefetch, type, useQuery, useInfinite, operationN
2051
2188
  const generateQueryImplementation = ({ queryOption: { name, typeName: optionTypeName, queryParam, options, type, queryKeyFnName }, operationId, operationName, typeName, queryProperties, queryKeyProperties, queryParams, params, props, body, mutator, queryOptionsMutator, queryKeyMutator, isRequestOptions, response, httpClient, isExactOptionalPropertyTypes, hasSignal, useRuntimeFetcher, forceSuccessResponse, route, doc, usePrefetch, useQuery, useInfinite, useInvalidate, useSetQueryData, useGetQueryData, adapter }) => {
2052
2189
  const { hasQueryV5, hasQueryV5WithDataTagError, hasQueryV5WithInfiniteQueryOptionsError } = adapter;
2053
2190
  const hasSignalParam = props.some((prop) => prop.name === "signal");
2191
+ const requiresUserQueryOptions = requiresUserSuppliedQueryOptions(adapter, type, options);
2192
+ const signatureProps = requiresUserQueryOptions ? widenOptionalPropsToUndefined(props, "implementation") : props;
2054
2193
  const queryPropDefinitions = wrapPropsBodyWithMutatorBodyType({
2055
- propsString: toObjectString(props, "definition"),
2194
+ propsString: toObjectString(requiresUserQueryOptions ? widenOptionalPropsToUndefined(props, "definition") : props, "definition"),
2056
2195
  body,
2057
2196
  mutator
2058
2197
  });
2059
2198
  const definedInitialDataQueryPropsDefinitions = wrapPropsBodyWithMutatorBodyType({
2060
- propsString: toObjectString(props.map((prop) => {
2061
- const regex = new RegExp(String.raw`^${prop.name}\s*\?:`);
2062
- if (!regex.test(prop.definition)) return prop;
2063
- const definitionWithUndefined = prop.definition.replace(regex, `${prop.name}: undefined | `);
2064
- return {
2065
- ...prop,
2066
- definition: definitionWithUndefined
2067
- };
2068
- }), "definition"),
2199
+ propsString: toObjectString(widenOptionalPropsToUndefined(props, "definition"), "definition"),
2069
2200
  body,
2070
2201
  mutator
2071
2202
  });
@@ -2074,6 +2205,11 @@ const generateQueryImplementation = ({ queryOption: { name, typeName: optionType
2074
2205
  body,
2075
2206
  mutator
2076
2207
  });
2208
+ const queryPropsBeforeRequiredOptions = requiresUserQueryOptions ? wrapPropsBodyWithMutatorBodyType({
2209
+ propsString: toObjectString(signatureProps, "implementation"),
2210
+ body,
2211
+ mutator
2212
+ }) : queryProps;
2077
2213
  const infiniteQueryParamType = hasQueryParam(queryParams, queryParam) && queryParams && queryParam ? `${queryParams.schema.name}['${queryParam}']` : "";
2078
2214
  const hasInfiniteQueryParam = !!infiniteQueryParamType;
2079
2215
  const httpFunctionProps = queryParam ? adapter.getInfiniteQueryHttpProps(props, queryParam, httpClient, !!mutator) : adapter.getHttpFunctionQueryProps(queryProperties, httpClient, !!mutator);
@@ -2104,7 +2240,8 @@ const generateQueryImplementation = ({ queryOption: { name, typeName: optionType
2104
2240
  queryParam,
2105
2241
  initialData: "defined",
2106
2242
  httpClient,
2107
- useRuntimeFetcher
2243
+ useRuntimeFetcher,
2244
+ options
2108
2245
  });
2109
2246
  const undefinedInitialDataQueryArguments = adapter.generateQueryArguments({
2110
2247
  operationName,
@@ -2116,7 +2253,8 @@ const generateQueryImplementation = ({ queryOption: { name, typeName: optionType
2116
2253
  queryParam,
2117
2254
  initialData: "undefined",
2118
2255
  httpClient,
2119
- useRuntimeFetcher
2256
+ useRuntimeFetcher,
2257
+ options
2120
2258
  });
2121
2259
  const queryArguments = adapter.generateQueryArguments({
2122
2260
  operationName,
@@ -2127,7 +2265,8 @@ const generateQueryImplementation = ({ queryOption: { name, typeName: optionType
2127
2265
  queryParams,
2128
2266
  queryParam,
2129
2267
  httpClient,
2130
- useRuntimeFetcher
2268
+ useRuntimeFetcher,
2269
+ options
2131
2270
  });
2132
2271
  const queryArgumentsForOptions = adapter.generateQueryArguments({
2133
2272
  operationName,
@@ -2139,7 +2278,8 @@ const generateQueryImplementation = ({ queryOption: { name, typeName: optionType
2139
2278
  queryParam,
2140
2279
  httpClient,
2141
2280
  forQueryOptions: true,
2142
- useRuntimeFetcher
2281
+ useRuntimeFetcher,
2282
+ options
2143
2283
  });
2144
2284
  const queryOptions = getQueryOptions({
2145
2285
  isRequestOptions,
@@ -2185,7 +2325,7 @@ const generateQueryImplementation = ({ queryOption: { name, typeName: optionType
2185
2325
  const queryResultVarName = props.some((prop) => prop.name === "query") ? "_query" : "query";
2186
2326
  const infiniteParam = infiniteQueryParamType ? `, ${infiniteQueryParamType}` : "";
2187
2327
  const TData = hasQueryV5 && (type === QueryType.INFINITE || type === QueryType.SUSPENSE_INFINITE) ? `InfiniteData<Awaited<ReturnType<${dataType}>>${infiniteParam}>` : `Awaited<ReturnType<${dataType}>>`;
2188
- const queryOptionsFn = `export const ${queryOptionsFnName} = <TData = ${TData}, TError = ${errorType}>(${adapter.getHttpFirstParam(mutator)}${queryProps} ${queryArgumentsForOptions}) => {
2328
+ const queryOptionsFn = `export const ${queryOptionsFnName} = <TData = ${TData}, TError = ${errorType}>(${adapter.getHttpFirstParam(mutator)}${queryPropsBeforeRequiredOptions} ${queryArgumentsForOptions}) => {
2189
2329
 
2190
2330
  ${hookOptions}
2191
2331
 
@@ -2193,7 +2333,7 @@ ${hookOptions}
2193
2333
 
2194
2334
  ${mutator?.isHook ? `const ${operationName} = use${pascal(operationName)}Hook();` : ""}
2195
2335
 
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});
2336
+ const queryFn: QueryFunction<Awaited<ReturnType<${mutator?.isHook ? `ReturnType<typeof use${pascal(operationName)}Hook>` : `typeof ${operationName}`}>>${hasQueryV5 && hasInfiniteQueryParam ? `, QueryKey, ${infiniteQueryParamType}` : hasQueryV5 && isInfiniteQuery(type) && adapter.shouldCastQueryOptions?.() === false ? `, QueryKey, unknown` : ""}> = (${queryFnArguments}) => ${operationName}(${httpFunctionProps}${httpFunctionProps ? ", " : ""}${queryOptions});
2197
2337
 
2198
2338
  ${adapter.getQueryOptionsUnrefStatements(props)}
2199
2339
 
@@ -2215,7 +2355,7 @@ export function ${queryHookName}<TData = ${TData}, TError = ${errorType}>(\n ${q
2215
2355
  useInfinite,
2216
2356
  operationName,
2217
2357
  mutator,
2218
- queryProps,
2358
+ queryProps: queryPropsBeforeRequiredOptions,
2219
2359
  dataType,
2220
2360
  errorType,
2221
2361
  queryArguments: queryArgumentsForOptions,
@@ -2278,7 +2418,7 @@ export type ${pascal(optionTypeName)}QueryError = ${errorType}
2278
2418
  ${adapter.shouldGenerateOverrideTypes() ? overrideTypes : ""}
2279
2419
  ${doc}
2280
2420
  export function ${queryHookName}<TData = ${TData}, TError = ${errorType}>(\n ${wrapPropsBodyWithMutatorBodyType({
2281
- propsString: adapter.getHookPropsDefinitions(props),
2421
+ propsString: adapter.getHookPropsDefinitions(signatureProps),
2282
2422
  body,
2283
2423
  mutator
2284
2424
  })} ${queryArguments} ${optionalQueryClientArgument} \n ): ${returnType} {
@@ -2336,9 +2476,10 @@ const generateQueryHook = async (verbOptions, options, outputClient, adapter) =>
2336
2476
  const effectiveUseMutation = operationQueryOptions?.useMutation ?? override.query.useMutation ?? verb !== Verbs.GET;
2337
2477
  const globalSuspenseOrInfiniteOnlyForGet = (flag) => flag === true && verb === Verbs.GET;
2338
2478
  const effectiveUseSuspenseQuery = operationQueryOptions?.useSuspenseQuery ?? globalSuspenseOrInfiniteOnlyForGet(override.query.useSuspenseQuery);
2339
- const hasConfiguredInfiniteQueryParam = !query.useInfiniteQueryParam || hasQueryParam(queryParams, query.useInfiniteQueryParam);
2340
- const effectiveUseInfinite = (operationQueryOptions?.useInfinite ?? globalSuspenseOrInfiniteOnlyForGet(override.query.useInfinite)) && hasConfiguredInfiniteQueryParam;
2341
- const effectiveUseSuspenseInfiniteQuery = (operationQueryOptions?.useSuspenseInfiniteQuery ?? globalSuspenseOrInfiniteOnlyForGet(override.query.useSuspenseInfiniteQuery)) && hasConfiguredInfiniteQueryParam;
2479
+ const configuredInfiniteQueryParam = operationQueryOptions?.useInfiniteQueryParam ?? query.useInfiniteQueryParam;
2480
+ const { queryParam: infiniteQueryParam, infiniteHookAllowed } = resolveInfiniteQueryParam(queryParams, configuredInfiniteQueryParam);
2481
+ const effectiveUseInfinite = (operationQueryOptions?.useInfinite ?? globalSuspenseOrInfiniteOnlyForGet(override.query.useInfinite)) && infiniteHookAllowed;
2482
+ const effectiveUseSuspenseInfiniteQuery = (operationQueryOptions?.useSuspenseInfiniteQuery ?? globalSuspenseOrInfiniteOnlyForGet(override.query.useSuspenseInfiniteQuery)) && infiniteHookAllowed;
2342
2483
  let isQuery = effectiveUseQuery || effectiveUseSuspenseQuery || effectiveUseInfinite || effectiveUseSuspenseInfiniteQuery;
2343
2484
  let isMutation = effectiveUseMutation;
2344
2485
  if (verb !== Verbs.GET && isQuery) isMutation = false;
@@ -2377,7 +2518,7 @@ const generateQueryHook = async (verbOptions, options, outputClient, adapter) =>
2377
2518
  typeName: camel(`${typeName}-infinite`),
2378
2519
  options: query.options,
2379
2520
  type: QueryType.INFINITE,
2380
- queryParam: query.useInfiniteQueryParam,
2521
+ queryParam: infiniteQueryParam,
2381
2522
  queryKeyFnName: camel(`get-${operationName}-infinite-query-key`)
2382
2523
  }] : [],
2383
2524
  ...effectiveUseQuery ? [{
@@ -2399,7 +2540,7 @@ const generateQueryHook = async (verbOptions, options, outputClient, adapter) =>
2399
2540
  typeName: camel(`${typeName}-suspense-infinite`),
2400
2541
  options: query.options,
2401
2542
  type: QueryType.SUSPENSE_INFINITE,
2402
- queryParam: query.useInfiniteQueryParam,
2543
+ queryParam: infiniteQueryParam,
2403
2544
  queryKeyFnName: camel(`get-${operationName}-infinite-query-key`)
2404
2545
  }] : []
2405
2546
  ];
@@ -2431,6 +2572,19 @@ ${override.query.shouldExportQueryKey ? "export " : ""}const ${queryOption.query
2431
2572
  ].filter((x) => !!x).join(", ")}
2432
2573
  ]${override.query.shouldFilterQueryKey ? `.filter(${override.query.queryKeyFilter ?? "q => q !== undefined"})` : " as const"};
2433
2574
  }
2575
+ `;
2576
+ }
2577
+ else if (override.query.shouldExportQueryKey) for (const queryOption of uniqueQueryOptionsByKeys) {
2578
+ const queryKeyProps = buildKeyShapedProps({
2579
+ props,
2580
+ body,
2581
+ mutator,
2582
+ widenNonPath: makeOptionalParam,
2583
+ includeHeaders: true
2584
+ });
2585
+ queryKeyFns += `
2586
+ export const ${queryOption.queryKeyFnName} = (${queryKeyProps}) =>
2587
+ ${queryKeyMutator.name}({ ${queryProperties} }${queryKeyMutator.hasSecondArg ? `, { url: \`${route}\` }` : ""});
2434
2588
  `;
2435
2589
  }
2436
2590
  implementation += `