@kubb/plugin-react-query 5.0.0-beta.103 → 5.0.0-beta.105

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.cjs CHANGED
@@ -70,6 +70,26 @@ function operationFileEntry(node, name, extname = ".ts") {
70
70
  path: node.path
71
71
  };
72
72
  }
73
+ /**
74
+ * Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
75
+ * current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
76
+ * same dependency for the same operation in one pass (a query plugin's several hook generators, the
77
+ * MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
78
+ *
79
+ * @example Cache `plugin-ts`'s file for the current operation
80
+ * ```ts
81
+ * const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
82
+ * ```
83
+ */
84
+ function resolveDependencyOperationFile(options) {
85
+ const { cache, node, resolver, root, output, group } = options;
86
+ return cache.getOrSet(`${resolver.pluginName}:operationFile`, () => resolver.file({
87
+ ...operationFileEntry(node, node.operationId),
88
+ root,
89
+ output,
90
+ group: group ?? void 0
91
+ }));
92
+ }
73
93
  function getOperationLink(node, link) {
74
94
  if (!link) return null;
75
95
  if (typeof link === "function") return link(node) ?? null;
@@ -163,13 +183,24 @@ function buildOperationComments(node, options = {}) {
163
183
  if (!splitLines) return filteredComments;
164
184
  return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
165
185
  }
186
+ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
187
+ /**
188
+ * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
189
+ * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
190
+ * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
191
+ * same parameters once per plugin.
192
+ */
166
193
  function getOperationParameters(node) {
167
- return {
194
+ const cached = operationParameterGroupsByNode.get(node);
195
+ if (cached) return cached;
196
+ const groups = {
168
197
  path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
169
198
  query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
170
199
  header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
171
200
  cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
172
201
  };
202
+ operationParameterGroupsByNode.set(node, groups);
203
+ return groups;
173
204
  }
174
205
  function getStatusCodeNumber(statusCode) {
175
206
  const code = Number(statusCode);
@@ -407,23 +438,30 @@ function resolveContractClient(options) {
407
438
  * (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
408
439
  * path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
409
440
  * read `RequestConfig` / `ResponseErrorConfig` from.
441
+ *
442
+ * The result is cached in the current node's `cache` (`ctx.cache`) under the client plugin's name,
443
+ * so several dependents reading the same client plugin for one operation in a single pass
444
+ * (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
445
+ * one computed result instead of each re-deriving the name and path.
410
446
  */
411
447
  function resolveClientOperation(options) {
412
- const { clientPlugin, driver, node, root, output } = options;
448
+ const { clientPlugin, driver, node, root, output, cache } = options;
413
449
  if (!clientPlugin) return null;
414
- const resolver = driver.getResolver(clientPlugin.pluginName);
415
- const plugin = driver.getPlugin(clientPlugin.pluginName);
416
- const file = resolver.file({
417
- ...operationFileEntry(node, node.operationId),
418
- root,
419
- output: plugin?.options?.output ?? output,
420
- group: plugin?.options?.group ?? void 0
450
+ return cache.getOrSet(`${clientPlugin.pluginName}:clientOperation`, () => {
451
+ const resolver = driver.getResolver(clientPlugin.pluginName);
452
+ const plugin = driver.getPlugin(clientPlugin.pluginName);
453
+ const file = resolver.file({
454
+ ...operationFileEntry(node, node.operationId),
455
+ root,
456
+ output: plugin?.options?.output ?? output,
457
+ group: plugin?.options?.group ?? void 0
458
+ });
459
+ return {
460
+ name: resolver.name(node.operationId),
461
+ path: file.path,
462
+ clientPath: node_path.default.resolve(root, ".kubb/client.ts")
463
+ };
421
464
  });
422
- return {
423
- name: resolver.name(node.operationId),
424
- path: file.path,
425
- clientPath: node_path.default.resolve(root, ".kubb/client.ts")
426
- };
427
465
  }
428
466
  //#endregion
429
467
  //#region ../../internals/tanstack-query/src/utils.ts
@@ -1448,29 +1486,36 @@ function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
1448
1486
  const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1449
1487
  name: "react-infinite-query",
1450
1488
  renderer: kubb_jsx.jsxRenderer,
1489
+ match(node, ctx) {
1490
+ const operationNode = node;
1491
+ if (!kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
1492
+ const { query, mutation, infinite, hooks } = ctx.options;
1493
+ const { isQuery, isMutation } = classifyOperation(operationNode, {
1494
+ query,
1495
+ mutation
1496
+ });
1497
+ const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1498
+ if (!isQuery || isMutation || !infiniteOptions || !hooks) return false;
1499
+ const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name);
1500
+ return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false;
1501
+ },
1451
1502
  operation(node, ctx) {
1452
1503
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
1453
1504
  const { config, driver, resolver, root } = ctx;
1454
- const { output, query, mutation, infinite, client, group, customOptions, hooks } = ctx.options;
1505
+ const { output, query, infinite, client, group, customOptions } = ctx.options;
1455
1506
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1456
1507
  if (!pluginTs) return null;
1457
1508
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1458
- const { isQuery, isMutation } = classifyOperation(node, {
1459
- query,
1460
- mutation
1461
- });
1462
1509
  const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1463
- if (!isQuery || isMutation || !infiniteOptions || !hooks) return null;
1464
- const normalizeKey = (key) => key.replace(/\?$/, "");
1465
- const queryParamKeys = getOperationParameters(node).query.map((p) => p.name);
1466
- if (!(infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false)) return null;
1510
+ if (!infiniteOptions) return null;
1467
1511
  const importPath = query ? query.importPath : "@tanstack/react-query";
1468
1512
  const contractOp = resolveClientOperation({
1469
1513
  clientPlugin: { pluginName: client.pluginName },
1470
1514
  driver,
1471
1515
  node,
1472
1516
  root,
1473
- output
1517
+ output,
1518
+ cache: ctx.cache
1474
1519
  });
1475
1520
  if (!contractOp) return null;
1476
1521
  const queryName = resolver.infiniteQuery.name(node);
@@ -1484,11 +1529,13 @@ const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1484
1529
  output,
1485
1530
  group: group ?? void 0
1486
1531
  }),
1487
- fileTs: tsResolver.file({
1488
- ...operationFileEntry(node, node.operationId),
1532
+ fileTs: resolveDependencyOperationFile({
1533
+ cache: ctx.cache,
1534
+ node,
1535
+ resolver: tsResolver,
1489
1536
  root,
1490
1537
  output: pluginTs.options?.output ?? output,
1491
- group: pluginTs.options?.group ?? void 0
1538
+ group: pluginTs.options?.group
1492
1539
  })
1493
1540
  };
1494
1541
  const { queryParamsTypeName } = resolvePageParamType(node, {
@@ -1615,25 +1662,30 @@ const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1615
1662
  const mutationGenerator = (0, kubb_kit.defineGenerator)({
1616
1663
  name: "react-query-mutation",
1617
1664
  renderer: kubb_jsx.jsxRenderer,
1665
+ match(node, ctx) {
1666
+ const operationNode = node;
1667
+ if (!kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
1668
+ const { query, mutation } = ctx.options;
1669
+ return classifyOperation(operationNode, {
1670
+ query,
1671
+ mutation
1672
+ }).isMutation;
1673
+ },
1618
1674
  operation(node, ctx) {
1619
1675
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
1620
1676
  const { config, driver, resolver, root } = ctx;
1621
- const { output, query, mutation, client, group, customOptions, hooks } = ctx.options;
1677
+ const { output, mutation, client, group, customOptions, hooks } = ctx.options;
1622
1678
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1623
1679
  if (!pluginTs) return null;
1624
1680
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1625
- const { isMutation } = classifyOperation(node, {
1626
- query,
1627
- mutation
1628
- });
1629
- if (!isMutation) return null;
1630
1681
  const importPath = mutation ? mutation.importPath : "@tanstack/react-query";
1631
1682
  const contractOp = resolveClientOperation({
1632
1683
  clientPlugin: { pluginName: client.pluginName },
1633
1684
  driver,
1634
1685
  node,
1635
1686
  root,
1636
- output
1687
+ output,
1688
+ cache: ctx.cache
1637
1689
  });
1638
1690
  if (!contractOp) return null;
1639
1691
  const mutationHookName = resolver.mutation.name(node);
@@ -1647,11 +1699,13 @@ const mutationGenerator = (0, kubb_kit.defineGenerator)({
1647
1699
  output,
1648
1700
  group: group ?? void 0
1649
1701
  }),
1650
- fileTs: tsResolver.file({
1651
- ...operationFileEntry(node, node.operationId),
1702
+ fileTs: resolveDependencyOperationFile({
1703
+ cache: ctx.cache,
1704
+ node,
1705
+ resolver: tsResolver,
1652
1706
  root,
1653
1707
  output: pluginTs.options?.output ?? output,
1654
- group: pluginTs.options?.group ?? void 0
1708
+ group: pluginTs.options?.group
1655
1709
  })
1656
1710
  };
1657
1711
  const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
@@ -1755,25 +1809,31 @@ const mutationGenerator = (0, kubb_kit.defineGenerator)({
1755
1809
  const queryGenerator = (0, kubb_kit.defineGenerator)({
1756
1810
  name: "react-query",
1757
1811
  renderer: kubb_jsx.jsxRenderer,
1812
+ match(node, ctx) {
1813
+ const operationNode = node;
1814
+ if (!kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
1815
+ const { query, mutation } = ctx.options;
1816
+ const { isQuery, isMutation } = classifyOperation(operationNode, {
1817
+ query,
1818
+ mutation
1819
+ });
1820
+ return isQuery && !isMutation;
1821
+ },
1758
1822
  operation(node, ctx) {
1759
1823
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
1760
1824
  const { config, driver, resolver, root } = ctx;
1761
- const { output, query, mutation, client, group, customOptions, hooks } = ctx.options;
1825
+ const { output, query, client, group, customOptions, hooks } = ctx.options;
1762
1826
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1763
1827
  if (!pluginTs) return null;
1764
1828
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1765
- const { isQuery, isMutation } = classifyOperation(node, {
1766
- query,
1767
- mutation
1768
- });
1769
- if (!isQuery || isMutation) return null;
1770
1829
  const importPath = query ? query.importPath : "@tanstack/react-query";
1771
1830
  const contractOp = resolveClientOperation({
1772
1831
  clientPlugin: { pluginName: client.pluginName },
1773
1832
  driver,
1774
1833
  node,
1775
1834
  root,
1776
- output
1835
+ output,
1836
+ cache: ctx.cache
1777
1837
  });
1778
1838
  if (!contractOp) return null;
1779
1839
  const queryName = resolver.query.name(node);
@@ -1787,11 +1847,13 @@ const queryGenerator = (0, kubb_kit.defineGenerator)({
1787
1847
  output,
1788
1848
  group: group ?? void 0
1789
1849
  }),
1790
- fileTs: tsResolver.file({
1791
- ...operationFileEntry(node, node.operationId),
1850
+ fileTs: resolveDependencyOperationFile({
1851
+ cache: ctx.cache,
1852
+ node,
1853
+ resolver: tsResolver,
1792
1854
  root,
1793
1855
  output: pluginTs.options?.output ?? output,
1794
- group: pluginTs.options?.group ?? void 0
1856
+ group: pluginTs.options?.group
1795
1857
  })
1796
1858
  };
1797
1859
  const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
@@ -1900,30 +1962,36 @@ const queryGenerator = (0, kubb_kit.defineGenerator)({
1900
1962
  const suspenseInfiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1901
1963
  name: "react-suspense-infinite-query",
1902
1964
  renderer: kubb_jsx.jsxRenderer,
1965
+ match(node, ctx) {
1966
+ const operationNode = node;
1967
+ if (!kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
1968
+ const { query, mutation, infinite, suspense, hooks } = ctx.options;
1969
+ const { isQuery, isMutation } = classifyOperation(operationNode, {
1970
+ query,
1971
+ mutation
1972
+ });
1973
+ const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1974
+ if (!isQuery || isMutation || !suspense || !infiniteOptions || !hooks) return false;
1975
+ const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name);
1976
+ return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false;
1977
+ },
1903
1978
  operation(node, ctx) {
1904
1979
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
1905
1980
  const { config, driver, resolver, root } = ctx;
1906
- const { output, query, mutation, infinite, suspense, client, group, customOptions, hooks } = ctx.options;
1981
+ const { output, query, infinite, client, group, customOptions } = ctx.options;
1907
1982
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1908
1983
  if (!pluginTs) return null;
1909
1984
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1910
- const { isQuery, isMutation } = classifyOperation(node, {
1911
- query,
1912
- mutation
1913
- });
1914
- const isSuspense = !!suspense;
1915
1985
  const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1916
- if (!isQuery || isMutation || !isSuspense || !infiniteOptions || !hooks) return null;
1917
- const normalizeKey = (key) => key.replace(/\?$/, "");
1918
- const queryParamKeys = getOperationParameters(node).query.map((p) => p.name);
1919
- if (!(infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false)) return null;
1986
+ if (!infiniteOptions) return null;
1920
1987
  const importPath = query ? query.importPath : "@tanstack/react-query";
1921
1988
  const contractOp = resolveClientOperation({
1922
1989
  clientPlugin: { pluginName: client.pluginName },
1923
1990
  driver,
1924
1991
  node,
1925
1992
  root,
1926
- output
1993
+ output,
1994
+ cache: ctx.cache
1927
1995
  });
1928
1996
  if (!contractOp) return null;
1929
1997
  const queryName = resolver.suspenseInfiniteQuery.name(node);
@@ -1937,11 +2005,13 @@ const suspenseInfiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1937
2005
  output,
1938
2006
  group: group ?? void 0
1939
2007
  }),
1940
- fileTs: tsResolver.file({
1941
- ...operationFileEntry(node, node.operationId),
2008
+ fileTs: resolveDependencyOperationFile({
2009
+ cache: ctx.cache,
2010
+ node,
2011
+ resolver: tsResolver,
1942
2012
  root,
1943
2013
  output: pluginTs.options?.output ?? output,
1944
- group: pluginTs.options?.group ?? void 0
2014
+ group: pluginTs.options?.group
1945
2015
  })
1946
2016
  };
1947
2017
  const rawQueryParams = getOperationParameters(node).query;
@@ -2067,25 +2137,31 @@ const suspenseInfiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
2067
2137
  const suspenseQueryGenerator = (0, kubb_kit.defineGenerator)({
2068
2138
  name: "react-suspense-query",
2069
2139
  renderer: kubb_jsx.jsxRenderer,
2140
+ match(node, ctx) {
2141
+ const operationNode = node;
2142
+ if (!kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
2143
+ const { query, mutation, suspense, hooks } = ctx.options;
2144
+ const { isQuery, isMutation } = classifyOperation(operationNode, {
2145
+ query,
2146
+ mutation
2147
+ });
2148
+ return isQuery && !isMutation && !!suspense && hooks;
2149
+ },
2070
2150
  operation(node, ctx) {
2071
2151
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
2072
2152
  const { config, driver, resolver, root } = ctx;
2073
- const { output, query, mutation, suspense, client, group, customOptions, hooks } = ctx.options;
2153
+ const { output, query, client, group, customOptions } = ctx.options;
2074
2154
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
2075
2155
  if (!pluginTs) return null;
2076
2156
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
2077
- const { isQuery, isMutation } = classifyOperation(node, {
2078
- query,
2079
- mutation
2080
- });
2081
- if (!isQuery || isMutation || !!!suspense || !hooks) return null;
2082
2157
  const importPath = query ? query.importPath : "@tanstack/react-query";
2083
2158
  const contractOp = resolveClientOperation({
2084
2159
  clientPlugin: { pluginName: client.pluginName },
2085
2160
  driver,
2086
2161
  node,
2087
2162
  root,
2088
- output
2163
+ output,
2164
+ cache: ctx.cache
2089
2165
  });
2090
2166
  if (!contractOp) return null;
2091
2167
  const queryName = resolver.suspenseQuery.name(node);
@@ -2099,11 +2175,13 @@ const suspenseQueryGenerator = (0, kubb_kit.defineGenerator)({
2099
2175
  output,
2100
2176
  group: group ?? void 0
2101
2177
  }),
2102
- fileTs: tsResolver.file({
2103
- ...operationFileEntry(node, node.operationId),
2178
+ fileTs: resolveDependencyOperationFile({
2179
+ cache: ctx.cache,
2180
+ node,
2181
+ resolver: tsResolver,
2104
2182
  root,
2105
2183
  output: pluginTs.options?.output ?? output,
2106
- group: pluginTs.options?.group ?? void 0
2184
+ group: pluginTs.options?.group
2107
2185
  })
2108
2186
  };
2109
2187
  const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {