@orval/query 8.15.0 → 8.17.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, 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, isString, isSyntheticDefaultImportsAllow, jsDoc, kebab, 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";
@@ -130,7 +130,9 @@ const ANGULAR_HTTP_DEPENDENCIES = [
130
130
  dependency: "rxjs/operators"
131
131
  }
132
132
  ];
133
- const generateAngularHttpRequestFunction = ({ headers, queryParams, operationName, response, mutator, body, props, verb, formData, formUrlEncoded, override }, { route, context }) => {
133
+ const generateAngularHttpRequestFunction = ({ headers, queryParams, operationName, response, mutator, body, props, verb, formData, formUrlEncoded, override }, { route: _route, context }) => {
134
+ let route = _route;
135
+ if (context.output.urlEncodeParameters) route = makeRouteSafe(route);
134
136
  const isRequestOptions = override.requestOptions !== false;
135
137
  const isFormData = !override.formData.disabled;
136
138
  const isFormUrlEncoded = override.formUrlEncoded !== false;
@@ -144,6 +146,7 @@ const generateAngularHttpRequestFunction = ({ headers, queryParams, operationNam
144
146
  isFormUrlEncoded
145
147
  });
146
148
  if (mutator) {
149
+ const isExactOptionalPropertyTypes = !!context.output.tsconfig?.compilerOptions?.exactOptionalPropertyTypes;
147
150
  const mutatorConfig = generateMutatorConfig({
148
151
  route,
149
152
  body,
@@ -155,7 +158,7 @@ const generateAngularHttpRequestFunction = ({ headers, queryParams, operationNam
155
158
  isFormUrlEncoded,
156
159
  hasSignal,
157
160
  hasSignalParam,
158
- isExactOptionalPropertyTypes: !!context.output.tsconfig?.compilerOptions?.exactOptionalPropertyTypes,
161
+ isExactOptionalPropertyTypes,
159
162
  isVue: false,
160
163
  isAngular: context.output.httpClient === OutputHttpClient.ANGULAR
161
164
  });
@@ -677,11 +680,16 @@ const VUE_QUERY_DEPENDENCIES = [{
677
680
  name: "useMutation",
678
681
  values: true
679
682
  },
683
+ {
684
+ name: "useQueryClient",
685
+ values: true
686
+ },
680
687
  { name: "UseQueryOptions" },
681
688
  { name: "UseInfiniteQueryOptions" },
682
689
  { name: "UseMutationOptions" },
683
690
  { name: "QueryFunction" },
684
691
  { name: "MutationFunction" },
692
+ { name: "MutationFunctionContext" },
685
693
  { name: "QueryKey" },
686
694
  { name: "UseQueryReturnType" },
687
695
  { name: "UseInfiniteQueryReturnType" },
@@ -742,6 +750,12 @@ const getSolidQueryImports = (prefix, hasRenamedOptionsTypes) => {
742
750
  { name: "InvalidateOptions" }
743
751
  ],
744
752
  dependency: "@tanstack/solid-query"
753
+ }, {
754
+ exports: [{
755
+ name: "mergeProps",
756
+ values: true
757
+ }],
758
+ dependency: "solid-js"
745
759
  }];
746
760
  };
747
761
  const ANGULAR_QUERY_DEPENDENCIES = [{
@@ -1176,7 +1190,7 @@ const createSolidAdapter = ({ hasQueryV5, hasQueryV5WithDataTagError, hasQueryV5
1176
1190
  >`;
1177
1191
  },
1178
1192
  getQueryReturnStatement({ queryResultVarName, queryOptionsVarName }) {
1179
- return `return Object.assign(${queryResultVarName}, { queryKey: ${queryOptionsVarName}.queryKey }) as any;`;
1193
+ return `return mergeProps(${queryResultVarName}, { queryKey: ${queryOptionsVarName}.queryKey }) as any;`;
1180
1194
  },
1181
1195
  generateQueryInvocationArgs({ queryOptionsFnName, queryProperties, isRequestOptions, optionalQueryClientArgument }) {
1182
1196
  const optionsArg = isRequestOptions ? "options" : "queryOptions";
@@ -1362,17 +1376,39 @@ const createVueAdapter = ({ hasVueQueryV4, hasQueryV5, hasQueryV5WithDataTagErro
1362
1376
  getQueryKeyPrefix() {
1363
1377
  return hasVueQueryV4 ? "" : "queryOptions?.queryKey ?? ";
1364
1378
  },
1365
- generateMutationImplementation({ mutationOptionsFnName, isRequestOptions }) {
1366
- return `${mutationOptionsFnName}(${isRequestOptions ? "options" : "mutationOptions"})`;
1379
+ generateMutationImplementation({ mutationOptionsFnName, hasInvalidation, isRequestOptions }) {
1380
+ return `${mutationOptionsFnName}(${hasInvalidation ? `queryClient ?? backupQueryClient, ` : ""}${isRequestOptions ? "options" : "mutationOptions"})`;
1367
1381
  },
1368
1382
  supportsMutationInvalidation() {
1369
- return false;
1383
+ return hasQueryV5;
1370
1384
  },
1371
- generateMutationOnSuccess() {
1372
- return "";
1385
+ generateMutationOnSuccess({ operationName, definitions, isRequestOptions, generateInvalidateCall, uniqueInvalidates }) {
1386
+ const invalidateCalls = uniqueInvalidates.map((t) => generateInvalidateCall(t)).join("\n");
1387
+ if (hasQueryV5WithMutationContextOnSuccess) {
1388
+ if (isRequestOptions) return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, onMutateResult: TContext, context: MutationFunctionContext) => {
1389
+ if (!options?.skipInvalidation) {
1390
+ ${invalidateCalls}
1391
+ }
1392
+ unref(unref(typeof mutationOptions === 'function' ? mutationOptions() : mutationOptions)?.onSuccess)?.(data, variables, onMutateResult, context);
1393
+ };`;
1394
+ return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, onMutateResult: TContext, context: MutationFunctionContext) => {
1395
+ ${invalidateCalls}
1396
+ unref(unref(typeof mutationOptions === 'function' ? mutationOptions() : mutationOptions)?.onSuccess)?.(data, variables, onMutateResult, context);
1397
+ };`;
1398
+ }
1399
+ if (isRequestOptions) return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, context: TContext${hasQueryV5WithRequiredContextOnSuccess ? "" : " | undefined"}) => {
1400
+ if (!options?.skipInvalidation) {
1401
+ ${invalidateCalls}
1402
+ }
1403
+ unref(unref(typeof mutationOptions === 'function' ? mutationOptions() : mutationOptions)?.onSuccess)?.(data, variables, context);
1404
+ };`;
1405
+ return ` const onSuccess = (data: Awaited<ReturnType<typeof ${operationName}>>, variables: ${definitions ? `{${definitions}}` : "void"}, context: TContext${hasQueryV5WithRequiredContextOnSuccess ? "" : " | undefined"}) => {
1406
+ ${invalidateCalls}
1407
+ unref(unref(typeof mutationOptions === 'function' ? mutationOptions() : mutationOptions)?.onSuccess)?.(data, variables, context);
1408
+ };`;
1373
1409
  },
1374
- generateMutationHookBody({ operationPrefix, mutationImplementation, optionalQueryClientArgument }) {
1375
- return ` return ${operationPrefix}Mutation(${mutationImplementation}${optionalQueryClientArgument ? `, queryClient` : ""});`;
1410
+ generateMutationHookBody({ operationPrefix, mutationImplementation, hasInvalidation, optionalQueryClientArgument }) {
1411
+ return ` ${hasInvalidation ? `const backupQueryClient = useQueryClient();\n ` : ""}return ${operationPrefix}Mutation(${mutationImplementation}${optionalQueryClientArgument ? `, queryClient` : ""});`;
1376
1412
  },
1377
1413
  generateRequestFunction(verbOptions, options) {
1378
1414
  return options.context.output.httpClient === OutputHttpClient.AXIOS ? generateAxiosRequestFunction(verbOptions, options, true) : generateRequestFunction(verbOptions, options);
@@ -1600,6 +1636,31 @@ const getStaticRoutePrefix = (route) => {
1600
1636
  const prefix = route.slice(0, idx);
1601
1637
  return prefix.split("/").some((segment) => segment.length > 0) ? prefix : void 0;
1602
1638
  };
1639
+ const getMutationOptionsUrl = (route, pathParamNames, pathRoute) => {
1640
+ const pathParams = new Set(pathParamNames);
1641
+ if (pathParams.size === 0) return route;
1642
+ const formatPathRoute = (value) => value.replace(/\$\{([^}]+)\}/g, (match, expression) => pathParams.has(expression) ? `{${expression}}` : match);
1643
+ if (pathRoute) {
1644
+ if (route.endsWith(pathRoute)) return `${route.slice(0, -pathRoute.length)}${formatPathRoute(pathRoute)}`;
1645
+ const routeWithoutLeadingSlash = pathRoute.startsWith("/") ? pathRoute.slice(1) : void 0;
1646
+ if (routeWithoutLeadingSlash && route.endsWith(routeWithoutLeadingSlash)) return `${route.slice(0, -routeWithoutLeadingSlash.length)}${formatPathRoute(routeWithoutLeadingSlash)}`;
1647
+ }
1648
+ return pathRoute ? route : formatPathRoute(route);
1649
+ };
1650
+ const getMutationOptionsNamedPathParamName = (param) => {
1651
+ const trimmedParam = param.trim();
1652
+ if (!trimmedParam || trimmedParam.startsWith("...")) return void 0;
1653
+ const [name] = trimmedParam.split(/[=:]/);
1654
+ return name?.trim() || void 0;
1655
+ };
1656
+ const getMutationOptionsPathParamNames = (props) => props.flatMap((prop) => {
1657
+ if (prop.type === GetterPropType.PARAM) return [prop.name];
1658
+ if (prop.type === GetterPropType.NAMED_PATH_PARAMS) return prop.destructured.replace(/^\{\s*|\s*\}$/g, "").split(",").flatMap((param) => {
1659
+ const name = getMutationOptionsNamedPathParamName(param);
1660
+ return name ? [name] : [];
1661
+ });
1662
+ return [];
1663
+ });
1603
1664
  /**
1604
1665
  * Check whether the target invalidation needs to call the query key function.
1605
1666
  * Returns false when no params are specified and the route has required path
@@ -1627,10 +1688,18 @@ const generateParamArgs = (params) => {
1627
1688
  return Object.values(params).map((v) => generateParamArg(v)).join(", ");
1628
1689
  };
1629
1690
  /**
1691
+ * Build the code-literal form of a static route prefix for use inside a
1692
+ * `.startsWith(...)` predicate. A prefix derived from a runtime `baseUrl`
1693
+ * contains a `${...}` interpolation, so it must be emitted as a template
1694
+ * literal; otherwise a plain single-quoted string is enough and keeps the
1695
+ * output byte-identical to the no-baseUrl case.
1696
+ */
1697
+ const toPrefixLiteral = (prefix) => prefix.includes("${") ? `\`${prefix}\`` : `'${prefix}'`;
1698
+ /**
1630
1699
  * Create a generateInvalidateCall function that has access to the OpenAPI spec
1631
1700
  * for intelligent route-based invalidation when params are not specified.
1632
1701
  */
1633
- const createGenerateInvalidateCall = (spec, shouldSplitQueryKey, useOperationIdAsQueryKey) => {
1702
+ const createGenerateInvalidateCall = (spec, shouldSplitQueryKey, useOperationIdAsQueryKey, baseUrl, servers) => {
1634
1703
  return (target) => {
1635
1704
  const method = target.invalidateMode === "reset" ? "resetQueries" : "invalidateQueries";
1636
1705
  const queryKeyFn = camel(`get-${target.query}-query-key`);
@@ -1639,23 +1708,25 @@ const createGenerateInvalidateCall = (spec, shouldSplitQueryKey, useOperationIdA
1639
1708
  if (info?.hasRequiredPathParams) {
1640
1709
  const prefix = getStaticRoutePrefix(info.route);
1641
1710
  if (prefix !== void 0) {
1711
+ const prefixWithBase = getFullRoute(prefix, servers, baseUrl);
1642
1712
  const verbPrefix = getQueryKeyVerbPrefix({
1643
1713
  verb: info.method,
1644
1714
  useOperationIdAsQueryKey
1645
1715
  });
1646
1716
  if (shouldSplitQueryKey) {
1647
- const segments = prefix.split("/").filter((s) => s !== "").map((s) => `'${s}'`).join(", ");
1717
+ const segments = getRouteAsArray(prefixWithBase);
1648
1718
  return ` queryClient.${method}({ queryKey: ${verbPrefix ? `['${verbPrefix}', ${segments}]` : `[${segments}]`} });`;
1649
1719
  }
1650
- if (verbPrefix) return ` queryClient.${method}({ predicate: (query) => query.queryKey[0] === '${verbPrefix}' && typeof query.queryKey[1] === 'string' && query.queryKey[1].startsWith('${prefix}') });`;
1651
- return ` queryClient.${method}({ predicate: (query) => typeof query.queryKey[0] === 'string' && query.queryKey[0].startsWith('${prefix}') });`;
1720
+ const prefixLiteral = toPrefixLiteral(prefixWithBase);
1721
+ if (verbPrefix) return ` queryClient.${method}({ predicate: (query) => query.queryKey[0] === '${verbPrefix}' && typeof query.queryKey[1] === 'string' && query.queryKey[1].startsWith(${prefixLiteral}) });`;
1722
+ return ` queryClient.${method}({ predicate: (query) => typeof query.queryKey[0] === 'string' && query.queryKey[0].startsWith(${prefixLiteral}) });`;
1652
1723
  }
1653
1724
  }
1654
1725
  return ` queryClient.${method}({ queryKey: ${queryKeyFn}() });`;
1655
1726
  };
1656
1727
  };
1657
1728
  const generateMutationHook = async ({ verbOptions, options, isRequestOptions, httpClient, doc, adapter }) => {
1658
- const { operationName, body, props, mutator, response, operationId, override } = verbOptions;
1729
+ const { operationName, body, props, mutator, response, operationId, route: pathRoute, override } = verbOptions;
1659
1730
  const { route, context, output } = options;
1660
1731
  const query = override.query;
1661
1732
  const mutationOptionsMutator = query.mutationOptions ? await generateMutator({
@@ -1729,11 +1800,11 @@ ${hasInvalidation ? adapter.generateMutationOnSuccess({
1729
1800
  operationName,
1730
1801
  definitions,
1731
1802
  isRequestOptions,
1732
- generateInvalidateCall: createGenerateInvalidateCall(context.spec, !!query.shouldSplitQueryKey, !!query.useOperationIdAsQueryKey),
1803
+ generateInvalidateCall: createGenerateInvalidateCall(context.spec, !!query.shouldSplitQueryKey, !!query.useOperationIdAsQueryKey, context.output.baseUrl, context.spec.servers),
1733
1804
  uniqueInvalidates
1734
1805
  }) : ""}
1735
1806
 
1736
- ${mutationOptionsMutator ? `const customOptions = ${mutationOptionsMutator.name}({...mutationOptions, mutationFn}${mutationOptionsMutator.hasSecondArg ? `, { url: \`${route.replaceAll("/${", "/{")}\` }` : ""}${mutationOptionsMutator.hasThirdArg ? `, { operationId: '${operationId}', operationName: '${operationName}' }` : ""});` : ""}
1807
+ ${mutationOptionsMutator ? `const customOptions = ${mutationOptionsMutator.name}({...mutationOptions, mutationFn}${mutationOptionsMutator.hasSecondArg ? `, { url: \`${getMutationOptionsUrl(route, getMutationOptionsPathParamNames(props), pathRoute)}\` }` : ""}${mutationOptionsMutator.hasThirdArg ? `, { operationId: '${operationId}', operationName: '${operationName}' }` : ""});` : ""}
1737
1808
 
1738
1809
 
1739
1810
  return ${mutationOptionsMutator ? "customOptions" : hasInvalidation ? "{ ...mutationOptions, mutationFn, onSuccess }" : "{ mutationFn, ...mutationOptions }"}}`;