@kubb/plugin-react-query 5.3.0-canary.20261012T181005 → 5.3.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.ts CHANGED
@@ -119,7 +119,51 @@ type Infinite = {
119
119
  * @default 0
120
120
  */
121
121
  initialPageParam?: unknown;
122
+ /**
123
+ * Whether `initialPageParam` was explicitly configured rather than defaulted.
124
+ * When omitted or false, the default previous page threshold remains 1 (legacy 1-based default).
125
+ */
126
+ hasExplicitInitialPageParam?: boolean;
127
+ /**
128
+ * Source of TanStack Query's `getNextPageParam`, inlined verbatim as a function expression. Use it
129
+ * when the next page has to be computed rather than read from a field. Takes precedence over
130
+ * `nextParam` and `cursorParam`.
131
+ *
132
+ * Note: Because functions are inlined verbatim into generated code via `.toString()`, they cannot
133
+ * reference local closures or external variables from the config file.
134
+ *
135
+ * @example
136
+ * `'(lastPage) => (lastPage.hasNext ? lastPage.number + 1 : undefined)'`
137
+ * // or with definePageParam:
138
+ * `definePageParam<MyResponse, number>((lastPage) => (lastPage.hasNext ? lastPage.number + 1 : undefined))`
139
+ */
140
+ getNextPageParam?: string | PageParamFn | null;
141
+ /**
142
+ * Source of TanStack Query's `getPreviousPageParam`, inlined verbatim as a function expression.
143
+ * Takes precedence over `previousParam` and `cursorParam`.
144
+ *
145
+ * Note: Because functions are inlined verbatim into generated code via `.toString()`, they cannot
146
+ * reference local closures or external variables from the config file.
147
+ *
148
+ * @example
149
+ * `'(firstPage) => (firstPage.number > 0 ? firstPage.number - 1 : undefined)'`
150
+ * // or with definePageParam:
151
+ * `definePageParam<MyResponse, number>((firstPage) => (firstPage.number > 0 ? firstPage.number - 1 : undefined))`
152
+ */
153
+ getPreviousPageParam?: string | PageParamFn | null;
122
154
  };
155
+ type PageParamFn<TPage = any, TParam = any> = (page: TPage, allPages: Array<TPage>, pageParam: TParam, allPageParams: Array<TParam>) => TParam | undefined | null;
156
+ //#endregion
157
+ //#region ../../internals/tanstack-query/src/utils.d.ts
158
+ /**
159
+ * Helper to define a typed page param function for `infinite.getNextPageParam` or
160
+ * `infinite.getPreviousPageParam`. Serializes the function to a string for inlining in generated code.
161
+ *
162
+ * Note: Because the function is inlined verbatim into the generated file via `.toString()`,
163
+ * it must be self-contained and cannot reference local closures or external variables from
164
+ * the config file.
165
+ */
166
+ export declare function definePageParam<TPage = any, TParam = any>(fn: PageParamFn<TPage, TParam>): string;
123
167
  //#endregion
124
168
  //#region src/types.d.ts
125
169
  /**
@@ -506,5 +550,5 @@ export declare const pluginReactQuery: import("kubb/kit").PluginFactory<PluginRe
506
550
  */
507
551
  export declare const resolverReactQuery: ResolverReactQuery;
508
552
  //#endregion
509
- export { type PluginReactQuery, type ResolverReactQuery, pluginReactQuery as default };
553
+ export { type PageParamFn, type PluginReactQuery, type ResolverReactQuery, pluginReactQuery as default };
510
554
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./rolldown-runtime-C0LytTxp.js";
2
- import { Resolver, Url, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
2
+ import { Resolver, Url, addGenerator, ast, createResolver, defineGenerator, definePlugin, setMacros, setResolver, useConfig } from "kubb/kit";
3
3
  import path from "node:path";
4
4
  import { createFunctionParameter, createFunctionParameters, createObjectBindingPattern, createTypeLiteral, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
5
5
  import { File, Function, Type, jsxRenderer } from "kubb/jsx";
@@ -324,7 +324,7 @@ function createGroupConfig(group) {
324
324
  }
325
325
  //#endregion
326
326
  //#region package.json
327
- var version = "5.3.0-canary.20261012T181005";
327
+ var version = "5.3.0";
328
328
  //#endregion
329
329
  //#region ../../internals/client/src/resolveClient.ts
330
330
  /**
@@ -664,21 +664,60 @@ function classifyOperation(node, { query, mutation }) {
664
664
  };
665
665
  }
666
666
  /**
667
+ * Helper to define a typed page param function for `infinite.getNextPageParam` or
668
+ * `infinite.getPreviousPageParam`. Serializes the function to a string for inlining in generated code.
669
+ *
670
+ * Note: Because the function is inlined verbatim into the generated file via `.toString()`,
671
+ * it must be self-contained and cannot reference local closures or external variables from
672
+ * the config file.
673
+ */
674
+ function definePageParam(fn) {
675
+ return fn.toString();
676
+ }
677
+ /**
667
678
  * Applies the shared infinite-query defaults during plugin setup: a falsy value disables infinite
668
679
  * queries, and an object merges over `queryParam: 'id'` and `initialPageParam: 0` with the cursor
669
680
  * paths cleared.
670
681
  */
671
682
  function resolveInfiniteConfig(infinite) {
672
683
  if (!infinite) return false;
684
+ const hasExplicitInitialPageParam = infinite.hasExplicitInitialPageParam ?? infinite.initialPageParam !== void 0;
685
+ const getNextPageParam = infinite.getNextPageParam ? typeof infinite.getNextPageParam === "function" ? infinite.getNextPageParam.toString() : infinite.getNextPageParam : null;
686
+ const getPreviousPageParam = infinite.getPreviousPageParam ? typeof infinite.getPreviousPageParam === "function" ? infinite.getPreviousPageParam.toString() : infinite.getPreviousPageParam : null;
673
687
  return {
674
688
  queryParam: "id",
675
689
  initialPageParam: 0,
690
+ hasExplicitInitialPageParam,
676
691
  cursorParam: null,
677
692
  nextParam: null,
678
693
  previousParam: null,
679
- ...infinite
694
+ getNextPageParam,
695
+ getPreviousPageParam,
696
+ ...infinite,
697
+ ...getNextPageParam ? { getNextPageParam } : {},
698
+ ...getPreviousPageParam ? { getPreviousPageParam } : {}
680
699
  };
681
700
  }
701
+ /**
702
+ * Whether the infinite hook for `node` should be generated: the operation takes the configured
703
+ * `queryParam`.
704
+ */
705
+ function matchesInfinite(node, infinite) {
706
+ if (!infinite.queryParam) return false;
707
+ return getOperationParameters(node).query.some((param) => param.name.replace(/\?$/, "") === infinite.queryParam);
708
+ }
709
+ /**
710
+ * Warning for an infinite hook that falls back to the built-in page params on a response that
711
+ * isn't an array. Those params only stop on an empty array, so `hasNextPage` never turns false.
712
+ */
713
+ function getDefaultPageParamsWarning(node, infinite) {
714
+ if (!(infinite.getNextPageParam == null && infinite.getPreviousPageParam == null && infinite.nextParam == null && infinite.previousParam == null && !infinite.cursorParam)) return null;
715
+ const content = getPrimarySuccessResponse(node)?.content;
716
+ let resolved = (content?.find((item) => item.contentType?.includes("json")) ?? content?.[0])?.schema;
717
+ while (resolved?.type === "ref" || resolved?.type === "intersection" && resolved.members?.length === 1) resolved = resolved.type === "ref" ? resolved.schema : resolved.members?.[0];
718
+ if (!resolved || resolved.type === "array") return null;
719
+ return `${node.operationId}: the default infinite page params expect an array response and never end for this one. Set \`infinite.getNextPageParam\` (or \`nextParam\`) to read the next page from the response.`;
720
+ }
682
721
  function matchesPattern(node, ov) {
683
722
  const { type, pattern } = ov;
684
723
  const matches = (value) => typeof pattern === "string" ? value === pattern : pattern.test(value);
@@ -736,7 +775,7 @@ function buildQueryKeyParams(node, options) {
736
775
  //#region ../../internals/tanstack-query/src/components/InfiniteQueryOptions.tsx
737
776
  const declarationPrinter$7 = functionPrinter({ mode: "declaration" });
738
777
  const callPrinter$3 = functionPrinter({ mode: "call" });
739
- function InfiniteQueryOptions({ name, clientName, initialPageParam, cursorParam, nextParam, previousParam, node, tsResolver, queryParam, queryKeyName, queryKeyType = "typeof queryKey", memberTypeWrapper, unwrapName, returnType = "full" }) {
778
+ function InfiniteQueryOptions({ name, clientName, initialPageParam, hasExplicitInitialPageParam, cursorParam, nextParam, previousParam, getNextPageParam, getPreviousPageParam, node, tsResolver, queryParam, queryKeyName, queryKeyType = "typeof queryKey", memberTypeWrapper, unwrapName, returnType = "full" }) {
740
779
  const { TData: queryFnDataType, TError: errorType } = buildResponseTypes(node, tsResolver);
741
780
  const { queryParamsTypeName, pageParamType } = resolvePageParamType(node, {
742
781
  resolver: tsResolver,
@@ -760,18 +799,25 @@ function InfiniteQueryOptions({ name, clientName, initialPageParam, cursorParam,
760
799
  signal: true,
761
800
  unwrapName
762
801
  }), { returnType });
763
- const hasNewParams = nextParam != null || previousParam != null;
764
- const [getNextPageParamExpr, getPreviousPageParamExpr] = (() => {
765
- if (hasNewParams) {
766
- const nextAccessor = nextParam ? getNestedAccessor(nextParam, "lastPage") : null;
767
- const prevAccessor = previousParam ? getNestedAccessor(previousParam, "firstPage") : null;
768
- return [nextAccessor ? `getNextPageParam: (lastPage) => ${nextAccessor}` : null, prevAccessor ? `getPreviousPageParam: (firstPage) => ${prevAccessor}` : null];
769
- }
770
- if (cursorParam) return [`getNextPageParam: (lastPage) => lastPage['${cursorParam}']`, `getPreviousPageParam: (firstPage) => firstPage['${cursorParam}']`];
771
- return ["getNextPageParam: (lastPage, _allPages, lastPageParam) => Array.isArray(lastPage) && lastPage.length === 0 ? undefined : lastPageParam + 1", "getPreviousPageParam: (_firstPage, _allPages, firstPageParam) => firstPageParam <= 1 ? undefined : firstPageParam - 1"];
802
+ const initialPageParamLiteral = typeof initialPageParam === "string" || typeof initialPageParam === "object" && initialPageParam !== null ? JSON.stringify(initialPageParam) : String(initialPageParam === void 0 ? 0 : initialPageParam);
803
+ const serializedGetNextPageParam = typeof getNextPageParam === "function" ? getNextPageParam.toString() : getNextPageParam;
804
+ const getNextPageParamExpr = (() => {
805
+ if (serializedGetNextPageParam) return `getNextPageParam: ${serializedGetNextPageParam}`;
806
+ if (nextParam) return `getNextPageParam: (lastPage) => ${getNestedAccessor(nextParam, "lastPage")}`;
807
+ if (cursorParam) return `getNextPageParam: (lastPage) => lastPage['${cursorParam}']`;
808
+ return "getNextPageParam: (lastPage, _allPages, lastPageParam) => Array.isArray(lastPage) && lastPage.length === 0 ? undefined : lastPageParam + 1";
809
+ })();
810
+ const serializedGetPreviousPageParam = typeof getPreviousPageParam === "function" ? getPreviousPageParam.toString() : getPreviousPageParam;
811
+ const defaultPreviousThreshold = hasExplicitInitialPageParam ? initialPageParamLiteral : "1";
812
+ const getPreviousPageParamExpr = (() => {
813
+ if (serializedGetPreviousPageParam) return `getPreviousPageParam: ${serializedGetPreviousPageParam}`;
814
+ if (previousParam) return `getPreviousPageParam: (firstPage) => ${getNestedAccessor(previousParam, "firstPage")}`;
815
+ if (cursorParam) return `getPreviousPageParam: (firstPage) => firstPage['${cursorParam}']`;
816
+ if (serializedGetNextPageParam || nextParam) return null;
817
+ return `getPreviousPageParam: (_firstPage, _allPages, firstPageParam) => firstPageParam <= ${defaultPreviousThreshold} ? undefined : firstPageParam - 1`;
772
818
  })();
773
819
  const queryOptionsArr = [
774
- `initialPageParam: ${typeof initialPageParam === "string" ? JSON.stringify(initialPageParam) : initialPageParam}`,
820
+ `initialPageParam: ${initialPageParamLiteral}`,
775
821
  getNextPageParamExpr,
776
822
  getPreviousPageParamExpr
777
823
  ].filter(Boolean);
@@ -1522,8 +1568,7 @@ const infiniteQueryGenerator = defineGenerator({
1522
1568
  });
1523
1569
  const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1524
1570
  if (!isQuery || isMutation || !infiniteOptions || !hooks) return false;
1525
- const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name);
1526
- return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false;
1571
+ return matchesInfinite(operationNode, infiniteOptions);
1527
1572
  },
1528
1573
  operation(node, ctx) {
1529
1574
  if (!ast.isHttpOperationNode(node)) return null;
@@ -1533,6 +1578,8 @@ const infiniteQueryGenerator = defineGenerator({
1533
1578
  const tsResolver = driver.getResolver(pluginTsName);
1534
1579
  const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1535
1580
  if (!infiniteOptions) return null;
1581
+ const pageParamsWarning = getDefaultPageParamsWarning(node, infiniteOptions);
1582
+ if (pageParamsWarning) ctx.warn(pageParamsWarning);
1536
1583
  const importPath = query ? query.importPath : "@tanstack/react-query";
1537
1584
  const contractOp = resolveClientOperation({
1538
1585
  clientPlugin: { pluginName: client.pluginName },
@@ -1646,7 +1693,10 @@ const infiniteQueryGenerator = defineGenerator({
1646
1693
  cursorParam: infiniteOptions.cursorParam,
1647
1694
  nextParam: infiniteOptions.nextParam,
1648
1695
  previousParam: infiniteOptions.previousParam,
1696
+ getNextPageParam: infiniteOptions.getNextPageParam,
1697
+ getPreviousPageParam: infiniteOptions.getPreviousPageParam,
1649
1698
  initialPageParam: infiniteOptions.initialPageParam,
1699
+ hasExplicitInitialPageParam: infiniteOptions.hasExplicitInitialPageParam,
1650
1700
  queryParam: infiniteOptions.queryParam,
1651
1701
  returnType: contractOp.returnType
1652
1702
  }),
@@ -2000,8 +2050,7 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
2000
2050
  });
2001
2051
  const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
2002
2052
  if (!isQuery || isMutation || !suspense || !infiniteOptions || !hooks) return false;
2003
- const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name);
2004
- return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false;
2053
+ return matchesInfinite(operationNode, infiniteOptions);
2005
2054
  },
2006
2055
  operation(node, ctx) {
2007
2056
  if (!ast.isHttpOperationNode(node)) return null;
@@ -2041,12 +2090,16 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
2041
2090
  group: pluginTs.options?.group
2042
2091
  })
2043
2092
  };
2044
- const rawQueryParams = getOperationParameters(node).query;
2045
- const queryParamsTypeName = rawQueryParams.length > 0 && tsResolver.param.query(node, rawQueryParams[0]) !== tsResolver.param.name(node, rawQueryParams[0]) ? tsResolver.param.query(node, rawQueryParams[0]) : null;
2093
+ const { queryParamsTypeName } = resolvePageParamType(node, {
2094
+ resolver: tsResolver,
2095
+ initialPageParam: infiniteOptions.initialPageParam,
2096
+ queryParam: infiniteOptions.queryParam
2097
+ });
2046
2098
  const importedTypeNames = [
2047
2099
  tsResolver.response.options(node),
2048
2100
  queryParamsTypeName,
2049
2101
  ...resolveOperationTypeNames(node, tsResolver, {
2102
+ exclude: [queryKeyTypeName],
2050
2103
  order: "body-response-first",
2051
2104
  includeParams: false
2052
2105
  })
@@ -2120,7 +2173,10 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
2120
2173
  cursorParam: infiniteOptions.cursorParam,
2121
2174
  nextParam: infiniteOptions.nextParam,
2122
2175
  previousParam: infiniteOptions.previousParam,
2176
+ getNextPageParam: infiniteOptions.getNextPageParam,
2177
+ getPreviousPageParam: infiniteOptions.getPreviousPageParam,
2123
2178
  initialPageParam: infiniteOptions.initialPageParam,
2179
+ hasExplicitInitialPageParam: infiniteOptions.hasExplicitInitialPageParam,
2124
2180
  queryParam: infiniteOptions.queryParam,
2125
2181
  returnType: contractOp.returnType
2126
2182
  }),
@@ -2389,23 +2445,23 @@ const pluginReactQuery = definePlugin({
2389
2445
  meta: {
2390
2446
  name: pluginReactQueryName,
2391
2447
  version,
2392
- compatibility: { kubb: ">=5.7.0" }
2448
+ compatibility: { kubb: ">=5.8.0" }
2393
2449
  },
2394
2450
  dependencies: { [pluginTsName]: {} },
2395
- setup(options, kubb) {
2451
+ setup(options) {
2396
2452
  const { output = {
2397
2453
  path: "hooks",
2398
2454
  barrel: { type: "named" }
2399
2455
  }, group, exclude = [], include, override = [], suspense = false, infinite = false, mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, customOptions, hooks = false, client, resolver: userResolver, macros: userMacros } = options;
2400
2456
  const resolver = userResolver ? Resolver.merge(resolverReactQuery, userResolver) : resolverReactQuery;
2401
- kubb.setResolver(resolver);
2402
- if (userMacros?.length) kubb.setMacros(userMacros);
2403
- kubb.addGenerator(queryGenerator, suspenseQueryGenerator, infiniteQueryGenerator, suspenseInfiniteQueryGenerator, mutationGenerator, hookOptionsGenerator, customHookOptionsFileGenerator);
2457
+ setResolver(resolver);
2458
+ if (userMacros?.length) setMacros(userMacros);
2459
+ addGenerator(queryGenerator, suspenseQueryGenerator, infiniteQueryGenerator, suspenseInfiniteQueryGenerator, mutationGenerator, hookOptionsGenerator, customHookOptionsFileGenerator);
2404
2460
  return {
2405
2461
  output,
2406
2462
  client: resolveContractClient({
2407
2463
  client,
2408
- plugins: kubb.config.plugins
2464
+ plugins: useConfig().plugins
2409
2465
  }),
2410
2466
  queryKey,
2411
2467
  query: resolveQueryConfig(query, { importPath: "@tanstack/react-query" }),
@@ -2427,6 +2483,6 @@ const pluginReactQuery = definePlugin({
2427
2483
  }
2428
2484
  });
2429
2485
  //#endregion
2430
- export { pluginReactQuery as default, pluginReactQuery, pluginReactQueryName, resolverReactQuery };
2486
+ export { pluginReactQuery as default, pluginReactQuery, definePageParam, pluginReactQueryName, resolverReactQuery };
2431
2487
 
2432
2488
  //# sourceMappingURL=index.js.map