@kubb/plugin-swr 5.0.0-beta.103 → 5.0.0-beta.106

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.js CHANGED
@@ -42,6 +42,26 @@ function operationFileEntry(node, name, extname = ".ts") {
42
42
  path: node.path
43
43
  };
44
44
  }
45
+ /**
46
+ * Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
47
+ * current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
48
+ * same dependency for the same operation in one pass (a query plugin's several hook generators, the
49
+ * MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
50
+ *
51
+ * @example Cache `plugin-ts`'s file for the current operation
52
+ * ```ts
53
+ * const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
54
+ * ```
55
+ */
56
+ function resolveDependencyOperationFile(options) {
57
+ const { cache, node, resolver, root, output, group } = options;
58
+ return cache.getOrSet(`${resolver.pluginName}:operationFile`, () => resolver.file({
59
+ ...operationFileEntry(node, node.operationId),
60
+ root,
61
+ output,
62
+ group: group ?? void 0
63
+ }));
64
+ }
45
65
  function getOperationLink(node, link) {
46
66
  if (!link) return null;
47
67
  if (typeof link === "function") return link(node) ?? null;
@@ -135,13 +155,24 @@ function buildOperationComments(node, options = {}) {
135
155
  if (!splitLines) return filteredComments;
136
156
  return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
137
157
  }
158
+ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
159
+ /**
160
+ * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
161
+ * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
162
+ * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
163
+ * same parameters once per plugin.
164
+ */
138
165
  function getOperationParameters(node) {
139
- return {
166
+ const cached = operationParameterGroupsByNode.get(node);
167
+ if (cached) return cached;
168
+ const groups = {
140
169
  path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
141
170
  query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
142
171
  header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
143
172
  cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
144
173
  };
174
+ operationParameterGroupsByNode.set(node, groups);
175
+ return groups;
145
176
  }
146
177
  function getStatusCodeNumber(statusCode) {
147
178
  const code = Number(statusCode);
@@ -359,23 +390,30 @@ function resolveContractClient(options) {
359
390
  * (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
360
391
  * path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
361
392
  * read `RequestConfig` / `ResponseErrorConfig` from.
393
+ *
394
+ * The result is cached in the current node's `cache` (`ctx.cache`) under the client plugin's name,
395
+ * so several dependents reading the same client plugin for one operation in a single pass
396
+ * (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
397
+ * one computed result instead of each re-deriving the name and path.
362
398
  */
363
399
  function resolveClientOperation(options) {
364
- const { clientPlugin, driver, node, root, output } = options;
400
+ const { clientPlugin, driver, node, root, output, cache } = options;
365
401
  if (!clientPlugin) return null;
366
- const resolver = driver.getResolver(clientPlugin.pluginName);
367
- const plugin = driver.getPlugin(clientPlugin.pluginName);
368
- const file = resolver.file({
369
- ...operationFileEntry(node, node.operationId),
370
- root,
371
- output: plugin?.options?.output ?? output,
372
- group: plugin?.options?.group ?? void 0
402
+ return cache.getOrSet(`${clientPlugin.pluginName}:clientOperation`, () => {
403
+ const resolver = driver.getResolver(clientPlugin.pluginName);
404
+ const plugin = driver.getPlugin(clientPlugin.pluginName);
405
+ const file = resolver.file({
406
+ ...operationFileEntry(node, node.operationId),
407
+ root,
408
+ output: plugin?.options?.output ?? output,
409
+ group: plugin?.options?.group ?? void 0
410
+ });
411
+ return {
412
+ name: resolver.name(node.operationId),
413
+ path: file.path,
414
+ clientPath: path.resolve(root, ".kubb/client.ts")
415
+ };
373
416
  });
374
- return {
375
- name: resolver.name(node.operationId),
376
- path: file.path,
377
- clientPath: path.resolve(root, ".kubb/client.ts")
378
- };
379
417
  }
380
418
  //#endregion
381
419
  //#region ../../internals/tanstack-query/src/utils.ts
@@ -443,14 +481,16 @@ function buildGroupedRequestParam(node, options) {
443
481
  */
444
482
  function buildQueryOptionsParams(node, options) {
445
483
  const { resolver, memberTypeWrapper } = options;
446
- return createFunctionParameters({ params: [buildGroupedRequestParam(node, {
484
+ const groupedParam = buildGroupedRequestParam(node, {
447
485
  resolver,
448
486
  memberTypeWrapper
449
- }), createFunctionParameter({
487
+ });
488
+ const configParam = createFunctionParameter({
450
489
  name: "config",
451
490
  type: `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`,
452
491
  default: "{}"
453
- })].filter((param) => param !== null) });
492
+ });
493
+ return createFunctionParameters({ params: [groupedParam, configParam].filter((param) => param !== null) });
454
494
  }
455
495
  /**
456
496
  * Builds the call to a client `<op>` function inside a query/mutation hook body. The function takes
@@ -667,10 +707,12 @@ function buildMutationParamsNode(node, options) {
667
707
  const { mutationKeyTypeName, mutationArgTypeName, resolver } = options;
668
708
  const responseName = resolver.response.response(node);
669
709
  const errorNames = resolveErrorNames(node, resolver);
710
+ const TData = responseName;
711
+ const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
670
712
  return createFunctionParameters({ params: [createFunctionParameter({
671
713
  name: "options",
672
714
  type: `{
673
- mutation?: SWRMutationConfiguration<${responseName}, ${`ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`}, ${mutationKeyTypeName} | null, ${mutationArgTypeName}> & { throwOnError?: boolean },
715
+ mutation?: SWRMutationConfiguration<${TData}, ${TError}, ${mutationKeyTypeName} | null, ${mutationArgTypeName}> & { throwOnError?: boolean },
674
716
  client?: ${buildRequestConfigType(node)},
675
717
  shouldFetch?: boolean,
676
718
  }`,
@@ -765,17 +807,20 @@ function buildQueryParamsNode(node, options) {
765
807
  const { resolver } = options;
766
808
  const responseName = resolver.response.response(node);
767
809
  const errorNames = resolveErrorNames(node, resolver);
810
+ const TData = responseName;
811
+ const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
768
812
  const optionsParam = createFunctionParameter({
769
813
  name: "options",
770
814
  type: `{
771
- query?: SWRConfiguration<${[responseName, `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`].join(", ")}>,
815
+ query?: SWRConfiguration<${[TData, TError].join(", ")}>,
772
816
  client?: ${buildClientOptionType()},
773
817
  shouldFetch?: boolean,
774
818
  immutable?: boolean
775
819
  }`,
776
820
  default: "{}"
777
821
  });
778
- return createFunctionParameters({ params: [buildGroupedRequestParam(node, { resolver }), optionsParam].filter((param) => param !== null) });
822
+ const groupedParam = buildGroupedRequestParam(node, { resolver });
823
+ return createFunctionParameters({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
779
824
  }
780
825
  function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver }) {
781
826
  const responseName = tsResolver.response.response(node);
@@ -878,7 +923,8 @@ const mutationGenerator = defineGenerator({
878
923
  driver,
879
924
  node,
880
925
  root,
881
- output
926
+ output,
927
+ cache: ctx.cache
882
928
  });
883
929
  if (!contractOp) return null;
884
930
  const mutationHookName = resolver.mutation.name(node);
@@ -895,11 +941,10 @@ const mutationGenerator = defineGenerator({
895
941
  output,
896
942
  group
897
943
  }),
898
- fileTs: tsResolver.file({
899
- name: node.operationId,
900
- extname: ".ts",
901
- tag: node.tags[0] ?? "default",
902
- path: node.path,
944
+ fileTs: resolveDependencyOperationFile({
945
+ cache: ctx.cache,
946
+ node,
947
+ resolver: tsResolver,
903
948
  root,
904
949
  output: pluginTs.options?.output ?? output,
905
950
  group: pluginTs.options?.group
@@ -1005,7 +1050,8 @@ const queryGenerator = defineGenerator({
1005
1050
  driver,
1006
1051
  node,
1007
1052
  root,
1008
- output
1053
+ output,
1054
+ cache: ctx.cache
1009
1055
  });
1010
1056
  if (!contractOp) return null;
1011
1057
  const queryName = resolver.query.name(node);
@@ -1022,11 +1068,10 @@ const queryGenerator = defineGenerator({
1022
1068
  output,
1023
1069
  group
1024
1070
  }),
1025
- fileTs: tsResolver.file({
1026
- name: node.operationId,
1027
- extname: ".ts",
1028
- tag: node.tags[0] ?? "default",
1029
- path: node.path,
1071
+ fileTs: resolveDependencyOperationFile({
1072
+ cache: ctx.cache,
1073
+ node,
1074
+ resolver: tsResolver,
1030
1075
  root,
1031
1076
  output: pluginTs.options?.output ?? output,
1032
1077
  group: pluginTs.options?.group