@kubb/plugin-react-query 5.3.0-canary.20261012T190229 → 5.3.1

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
@@ -323,8 +323,14 @@ function createGroupConfig(group) {
323
323
  };
324
324
  }
325
325
  //#endregion
326
+ //#region kubb-extension.json
327
+ var compatibility = {
328
+ "kubb": ">=5.8.0",
329
+ "node": ">=22"
330
+ };
331
+ //#endregion
326
332
  //#region package.json
327
- var version = "5.3.0-canary.20261012T190229";
333
+ var version = "5.3.1";
328
334
  //#endregion
329
335
  //#region ../../internals/client/src/resolveClient.ts
330
336
  /**
@@ -664,21 +670,60 @@ function classifyOperation(node, { query, mutation }) {
664
670
  };
665
671
  }
666
672
  /**
673
+ * Helper to define a typed page param function for `infinite.getNextPageParam` or
674
+ * `infinite.getPreviousPageParam`. Serializes the function to a string for inlining in generated code.
675
+ *
676
+ * Note: Because the function is inlined verbatim into the generated file via `.toString()`,
677
+ * it must be self-contained and cannot reference local closures or external variables from
678
+ * the config file.
679
+ */
680
+ function definePageParam(fn) {
681
+ return fn.toString();
682
+ }
683
+ /**
667
684
  * Applies the shared infinite-query defaults during plugin setup: a falsy value disables infinite
668
685
  * queries, and an object merges over `queryParam: 'id'` and `initialPageParam: 0` with the cursor
669
686
  * paths cleared.
670
687
  */
671
688
  function resolveInfiniteConfig(infinite) {
672
689
  if (!infinite) return false;
690
+ const hasExplicitInitialPageParam = infinite.hasExplicitInitialPageParam ?? infinite.initialPageParam !== void 0;
691
+ const getNextPageParam = infinite.getNextPageParam ? typeof infinite.getNextPageParam === "function" ? infinite.getNextPageParam.toString() : infinite.getNextPageParam : null;
692
+ const getPreviousPageParam = infinite.getPreviousPageParam ? typeof infinite.getPreviousPageParam === "function" ? infinite.getPreviousPageParam.toString() : infinite.getPreviousPageParam : null;
673
693
  return {
674
694
  queryParam: "id",
675
695
  initialPageParam: 0,
696
+ hasExplicitInitialPageParam,
676
697
  cursorParam: null,
677
698
  nextParam: null,
678
699
  previousParam: null,
679
- ...infinite
700
+ getNextPageParam,
701
+ getPreviousPageParam,
702
+ ...infinite,
703
+ ...getNextPageParam ? { getNextPageParam } : {},
704
+ ...getPreviousPageParam ? { getPreviousPageParam } : {}
680
705
  };
681
706
  }
707
+ /**
708
+ * Whether the infinite hook for `node` should be generated: the operation takes the configured
709
+ * `queryParam`.
710
+ */
711
+ function matchesInfinite(node, infinite) {
712
+ if (!infinite.queryParam) return false;
713
+ return getOperationParameters(node).query.some((param) => param.name.replace(/\?$/, "") === infinite.queryParam);
714
+ }
715
+ /**
716
+ * Warning for an infinite hook that falls back to the built-in page params on a response that
717
+ * isn't an array. Those params only stop on an empty array, so `hasNextPage` never turns false.
718
+ */
719
+ function getDefaultPageParamsWarning(node, infinite) {
720
+ if (!(infinite.getNextPageParam == null && infinite.getPreviousPageParam == null && infinite.nextParam == null && infinite.previousParam == null && !infinite.cursorParam)) return null;
721
+ const content = getPrimarySuccessResponse(node)?.content;
722
+ let resolved = (content?.find((item) => item.contentType?.includes("json")) ?? content?.[0])?.schema;
723
+ while (resolved?.type === "ref" || resolved?.type === "intersection" && resolved.members?.length === 1) resolved = resolved.type === "ref" ? resolved.schema : resolved.members?.[0];
724
+ if (!resolved || resolved.type === "array") return null;
725
+ 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.`;
726
+ }
682
727
  function matchesPattern(node, ov) {
683
728
  const { type, pattern } = ov;
684
729
  const matches = (value) => typeof pattern === "string" ? value === pattern : pattern.test(value);
@@ -736,7 +781,7 @@ function buildQueryKeyParams(node, options) {
736
781
  //#region ../../internals/tanstack-query/src/components/InfiniteQueryOptions.tsx
737
782
  const declarationPrinter$7 = functionPrinter({ mode: "declaration" });
738
783
  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" }) {
784
+ function InfiniteQueryOptions({ name, clientName, initialPageParam, hasExplicitInitialPageParam, cursorParam, nextParam, previousParam, getNextPageParam, getPreviousPageParam, node, tsResolver, queryParam, queryKeyName, queryKeyType = "typeof queryKey", memberTypeWrapper, unwrapName, returnType = "full" }) {
740
785
  const { TData: queryFnDataType, TError: errorType } = buildResponseTypes(node, tsResolver);
741
786
  const { queryParamsTypeName, pageParamType } = resolvePageParamType(node, {
742
787
  resolver: tsResolver,
@@ -760,18 +805,25 @@ function InfiniteQueryOptions({ name, clientName, initialPageParam, cursorParam,
760
805
  signal: true,
761
806
  unwrapName
762
807
  }), { 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"];
808
+ const initialPageParamLiteral = typeof initialPageParam === "string" || typeof initialPageParam === "object" && initialPageParam !== null ? JSON.stringify(initialPageParam) : String(initialPageParam === void 0 ? 0 : initialPageParam);
809
+ const serializedGetNextPageParam = typeof getNextPageParam === "function" ? getNextPageParam.toString() : getNextPageParam;
810
+ const getNextPageParamExpr = (() => {
811
+ if (serializedGetNextPageParam) return `getNextPageParam: ${serializedGetNextPageParam}`;
812
+ if (nextParam) return `getNextPageParam: (lastPage) => ${getNestedAccessor(nextParam, "lastPage")}`;
813
+ if (cursorParam) return `getNextPageParam: (lastPage) => lastPage['${cursorParam}']`;
814
+ return "getNextPageParam: (lastPage, _allPages, lastPageParam) => Array.isArray(lastPage) && lastPage.length === 0 ? undefined : lastPageParam + 1";
815
+ })();
816
+ const serializedGetPreviousPageParam = typeof getPreviousPageParam === "function" ? getPreviousPageParam.toString() : getPreviousPageParam;
817
+ const defaultPreviousThreshold = hasExplicitInitialPageParam ? initialPageParamLiteral : "1";
818
+ const getPreviousPageParamExpr = (() => {
819
+ if (serializedGetPreviousPageParam) return `getPreviousPageParam: ${serializedGetPreviousPageParam}`;
820
+ if (previousParam) return `getPreviousPageParam: (firstPage) => ${getNestedAccessor(previousParam, "firstPage")}`;
821
+ if (cursorParam) return `getPreviousPageParam: (firstPage) => firstPage['${cursorParam}']`;
822
+ if (serializedGetNextPageParam || nextParam) return null;
823
+ return `getPreviousPageParam: (_firstPage, _allPages, firstPageParam) => firstPageParam <= ${defaultPreviousThreshold} ? undefined : firstPageParam - 1`;
772
824
  })();
773
825
  const queryOptionsArr = [
774
- `initialPageParam: ${typeof initialPageParam === "string" ? JSON.stringify(initialPageParam) : initialPageParam}`,
826
+ `initialPageParam: ${initialPageParamLiteral}`,
775
827
  getNextPageParamExpr,
776
828
  getPreviousPageParamExpr
777
829
  ].filter(Boolean);
@@ -1522,8 +1574,7 @@ const infiniteQueryGenerator = defineGenerator({
1522
1574
  });
1523
1575
  const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1524
1576
  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;
1577
+ return matchesInfinite(operationNode, infiniteOptions);
1527
1578
  },
1528
1579
  operation(node, ctx) {
1529
1580
  if (!ast.isHttpOperationNode(node)) return null;
@@ -1533,6 +1584,8 @@ const infiniteQueryGenerator = defineGenerator({
1533
1584
  const tsResolver = driver.getResolver(pluginTsName);
1534
1585
  const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1535
1586
  if (!infiniteOptions) return null;
1587
+ const pageParamsWarning = getDefaultPageParamsWarning(node, infiniteOptions);
1588
+ if (pageParamsWarning) ctx.warn(pageParamsWarning);
1536
1589
  const importPath = query ? query.importPath : "@tanstack/react-query";
1537
1590
  const contractOp = resolveClientOperation({
1538
1591
  clientPlugin: { pluginName: client.pluginName },
@@ -1646,7 +1699,10 @@ const infiniteQueryGenerator = defineGenerator({
1646
1699
  cursorParam: infiniteOptions.cursorParam,
1647
1700
  nextParam: infiniteOptions.nextParam,
1648
1701
  previousParam: infiniteOptions.previousParam,
1702
+ getNextPageParam: infiniteOptions.getNextPageParam,
1703
+ getPreviousPageParam: infiniteOptions.getPreviousPageParam,
1649
1704
  initialPageParam: infiniteOptions.initialPageParam,
1705
+ hasExplicitInitialPageParam: infiniteOptions.hasExplicitInitialPageParam,
1650
1706
  queryParam: infiniteOptions.queryParam,
1651
1707
  returnType: contractOp.returnType
1652
1708
  }),
@@ -2000,8 +2056,7 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
2000
2056
  });
2001
2057
  const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
2002
2058
  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;
2059
+ return matchesInfinite(operationNode, infiniteOptions);
2005
2060
  },
2006
2061
  operation(node, ctx) {
2007
2062
  if (!ast.isHttpOperationNode(node)) return null;
@@ -2041,12 +2096,16 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
2041
2096
  group: pluginTs.options?.group
2042
2097
  })
2043
2098
  };
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;
2099
+ const { queryParamsTypeName } = resolvePageParamType(node, {
2100
+ resolver: tsResolver,
2101
+ initialPageParam: infiniteOptions.initialPageParam,
2102
+ queryParam: infiniteOptions.queryParam
2103
+ });
2046
2104
  const importedTypeNames = [
2047
2105
  tsResolver.response.options(node),
2048
2106
  queryParamsTypeName,
2049
2107
  ...resolveOperationTypeNames(node, tsResolver, {
2108
+ exclude: [queryKeyTypeName],
2050
2109
  order: "body-response-first",
2051
2110
  includeParams: false
2052
2111
  })
@@ -2120,7 +2179,10 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
2120
2179
  cursorParam: infiniteOptions.cursorParam,
2121
2180
  nextParam: infiniteOptions.nextParam,
2122
2181
  previousParam: infiniteOptions.previousParam,
2182
+ getNextPageParam: infiniteOptions.getNextPageParam,
2183
+ getPreviousPageParam: infiniteOptions.getPreviousPageParam,
2123
2184
  initialPageParam: infiniteOptions.initialPageParam,
2185
+ hasExplicitInitialPageParam: infiniteOptions.hasExplicitInitialPageParam,
2124
2186
  queryParam: infiniteOptions.queryParam,
2125
2187
  returnType: contractOp.returnType
2126
2188
  }),
@@ -2389,7 +2451,7 @@ const pluginReactQuery = definePlugin({
2389
2451
  meta: {
2390
2452
  name: pluginReactQueryName,
2391
2453
  version,
2392
- compatibility: { kubb: ">=5.8.0" }
2454
+ compatibility
2393
2455
  },
2394
2456
  dependencies: { [pluginTsName]: {} },
2395
2457
  setup(options) {
@@ -2427,6 +2489,6 @@ const pluginReactQuery = definePlugin({
2427
2489
  }
2428
2490
  });
2429
2491
  //#endregion
2430
- export { pluginReactQuery as default, pluginReactQuery, pluginReactQueryName, resolverReactQuery };
2492
+ export { pluginReactQuery as default, pluginReactQuery, definePageParam, pluginReactQueryName, resolverReactQuery };
2431
2493
 
2432
2494
  //# sourceMappingURL=index.js.map