@kubb/plugin-cypress 5.0.0-beta.56 → 5.0.0-beta.73

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
@@ -1,8 +1,31 @@
1
- import { t as __name } from "./chunk-C0LytTxp.js";
2
- import { Exclude, Generator, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ast } from "@kubb/core";
1
+ import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
2
+ import { Exclude, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ast } from "@kubb/core";
3
3
  import { ResolverTs } from "@kubb/plugin-ts";
4
4
  import { KubbReactNode } from "@kubb/renderer-jsx/types";
5
5
 
6
+ //#region src/components/Request.d.ts
7
+ type Props = {
8
+ /**
9
+ * Name of the function
10
+ */
11
+ name: string;
12
+ /**
13
+ * AST operation node
14
+ */
15
+ node: ast.OperationNode;
16
+ /**
17
+ * TypeScript resolver for resolving param/data/response type names
18
+ */
19
+ resolver: ResolverTs;
20
+ baseURL: string | null | undefined;
21
+ };
22
+ declare function Request({
23
+ baseURL,
24
+ name,
25
+ resolver,
26
+ node
27
+ }: Props): KubbReactNode;
28
+ //#endregion
6
29
  //#region src/types.d.ts
7
30
  /**
8
31
  * Resolver for Cypress that provides naming methods for test functions.
@@ -20,32 +43,6 @@ type ResolverCypress = Resolver & {
20
43
  */
21
44
  resolvePathName(this: ResolverCypress, name: string, type?: 'file' | 'function' | 'type' | 'const'): string;
22
45
  };
23
- /**
24
- * Parameter handling mode that determines how path params and query/body params are arranged in function signatures.
25
- */
26
- type ParamsTypeOptions = {
27
- /**
28
- * Every operation parameter is wrapped in a single destructured object argument.
29
- */
30
- paramsType: 'object';
31
- /**
32
- * `pathParamsType` has no effect when `paramsType` is `'object'`.
33
- */
34
- pathParamsType?: never;
35
- } | {
36
- /**
37
- * Each parameter group is emitted as a separate positional function argument.
38
- */
39
- paramsType?: 'inline';
40
- /**
41
- * How URL path parameters are arranged inside the inline argument list.
42
- * - `'object'` groups them into one destructured object.
43
- * - `'inline'` emits each path param as its own argument.
44
- *
45
- * @default 'inline'
46
- */
47
- pathParamsType?: 'object' | 'inline';
48
- };
49
46
  /**
50
47
  * Where the generated Cypress helpers are written and how they are exported, plus the optional
51
48
  * `group` strategy. The `group` option organizes `output.mode: 'directory'` output into per-tag or per-path subdirectories.
@@ -53,20 +50,6 @@ type ParamsTypeOptions = {
53
50
  * @default { path: 'cypress', barrel: { type: 'named' } }
54
51
  */
55
52
  type Options = OutputOptions & {
56
- /**
57
- * Shape of the value returned from each helper.
58
- * - `'data'` — only the response body.
59
- * - `'full'` — the full Cypress response object (headers, status, body).
60
- *
61
- * @default 'data'
62
- */
63
- dataReturnType?: 'data' | 'full';
64
- /**
65
- * Rename parameter properties in the generated helpers (path, query, headers).
66
- *
67
- * @note Must match the value of `paramsCasing` on `@kubb/plugin-ts`.
68
- */
69
- paramsCasing?: 'camelcase';
70
53
  /**
71
54
  * Base URL prepended to every request URL. When omitted, falls back to the
72
55
  * adapter's server URL (typically `servers[0].url`).
@@ -89,14 +72,10 @@ type Options = OutputOptions & {
89
72
  */
90
73
  resolver?: Partial<ResolverCypress> & ThisType<ResolverCypress>;
91
74
  /**
92
- * AST visitor applied to each operation node before printing.
93
- */
94
- transformer?: ast.Visitor;
95
- /**
96
- * Custom generators that run alongside the built-in Cypress generators.
75
+ * Macros applied to each operation node before printing.
97
76
  */
98
- generators?: Array<Generator<PluginCypress>>;
99
- } & ParamsTypeOptions;
77
+ macros?: Array<ast.Macro>;
78
+ };
100
79
  type ResolvedOptions = {
101
80
  output: Output;
102
81
  exclude: Array<Exclude>;
@@ -104,10 +83,6 @@ type ResolvedOptions = {
104
83
  override: Array<Override<ResolvedOptions>>;
105
84
  group: Group | null;
106
85
  baseURL: Options['baseURL'] | undefined;
107
- dataReturnType: NonNullable<Options['dataReturnType']>;
108
- pathParamsType: NonNullable<NonNullable<Options['pathParamsType']>>;
109
- paramsType: NonNullable<Options['paramsType']>;
110
- paramsCasing: Options['paramsCasing'];
111
86
  resolver: ResolverCypress;
112
87
  };
113
88
  type PluginCypress = PluginFactoryOptions<'plugin-cypress', Options, ResolvedOptions, ResolverCypress>;
@@ -119,37 +94,6 @@ declare global {
119
94
  }
120
95
  }
121
96
  //#endregion
122
- //#region src/components/Request.d.ts
123
- type Props = {
124
- /**
125
- * Name of the function
126
- */
127
- name: string;
128
- /**
129
- * AST operation node
130
- */
131
- node: ast.OperationNode;
132
- /**
133
- * TypeScript resolver for resolving param/data/response type names
134
- */
135
- resolver: ResolverTs;
136
- baseURL: string | null | undefined;
137
- dataReturnType: PluginCypress['resolvedOptions']['dataReturnType'];
138
- paramsCasing: PluginCypress['resolvedOptions']['paramsCasing'];
139
- paramsType: PluginCypress['resolvedOptions']['paramsType'];
140
- pathParamsType: PluginCypress['resolvedOptions']['pathParamsType'];
141
- };
142
- declare function Request({
143
- baseURL,
144
- name,
145
- dataReturnType,
146
- resolver,
147
- node,
148
- paramsType,
149
- pathParamsType,
150
- paramsCasing
151
- }: Props): KubbReactNode;
152
- //#endregion
153
97
  //#region src/generators/cypressGenerator.d.ts
154
98
  /**
155
99
  * Built-in generator for `@kubb/plugin-cypress`. Emits one typed
@@ -193,7 +137,7 @@ declare const pluginCypress: (options?: Options | undefined) => import("@kubb/co
193
137
  /**
194
138
  * Default resolver used by `@kubb/plugin-cypress`. Decides the names and file
195
139
  * paths for every generated `cy.request()` wrapper. Functions and files use
196
- * camelCase, matching the convention from `@kubb/plugin-client`.
140
+ * camelCase, matching the convention from `@kubb/plugin-axios` and `@kubb/plugin-fetch`.
197
141
  *
198
142
  * @example Resolve a helper name
199
143
  * ```ts
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import "./chunk-C0LytTxp.js";
1
+ import "./rolldown-runtime-C0LytTxp.js";
2
2
  import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
3
- import { functionPrinter, pluginTsName } from "@kubb/plugin-ts";
4
3
  import { File, Function, jsxRenderer } from "@kubb/renderer-jsx";
5
4
  import { jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
5
+ import { pluginTsName } from "@kubb/plugin-ts";
6
6
  //#region ../../internals/utils/src/casing.ts
7
7
  /**
8
8
  * Shared implementation for camelCase and PascalCase conversion.
@@ -215,6 +215,22 @@ var Url = class Url {
215
215
  return `\`${prefix ?? ""}${result}\``;
216
216
  }
217
217
  /**
218
+ * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
219
+ * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
220
+ * names are camelCased to match the generated `path` type, and `prefix` is prepended inside the
221
+ * literal. Shared by the client and cypress generators that pass a grouped `path` object.
222
+ *
223
+ * @example
224
+ * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
225
+ */
226
+ static toGroupedTemplateString(path, { prefix } = {}) {
227
+ return Url.toTemplateString(path, {
228
+ prefix,
229
+ casing: "camelcase",
230
+ replacer: (name) => `path.${name}`
231
+ });
232
+ }
233
+ /**
218
234
  * Returns the path and its extracted params as a structured `URLObject`, or as a stringified
219
235
  * expression when `stringify` is set.
220
236
  *
@@ -242,9 +258,108 @@ var Url = class Url {
242
258
  }
243
259
  };
244
260
  //#endregion
261
+ //#region ../../internals/shared/src/params.ts
262
+ const caseParamsCache = /* @__PURE__ */ new WeakMap();
263
+ /**
264
+ * Applies camelCase to parameter names and returns a new array without mutating the input.
265
+ *
266
+ * Run it before handing parameters to schema builders so output property keys get the right casing
267
+ * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
268
+ * original array is returned unchanged. Results are cached per input array.
269
+ */
270
+ function caseParams(params, casing) {
271
+ if (!casing) return params;
272
+ const cached = caseParamsCache.get(params);
273
+ if (cached) return cached;
274
+ const result = params.map((param) => ({
275
+ ...param,
276
+ name: camelCase(param.name)
277
+ }));
278
+ caseParamsCache.set(params, result);
279
+ return result;
280
+ }
281
+ function buildParamsMapping(originalParams, mappedParams) {
282
+ const mapping = {};
283
+ let hasChanged = false;
284
+ originalParams.forEach((param, i) => {
285
+ const mappedName = mappedParams[i]?.name ?? param.name;
286
+ mapping[param.name] = mappedName;
287
+ if (param.name !== mappedName) hasChanged = true;
288
+ });
289
+ return hasChanged ? mapping : null;
290
+ }
291
+ //#endregion
245
292
  //#region ../../internals/shared/src/operation.ts
293
+ function getContentTypeInfo(node) {
294
+ const contentTypes = node.requestBody?.content?.map((e) => e.contentType) ?? [];
295
+ const isMultipleContentTypes = contentTypes.length > 1;
296
+ return {
297
+ contentTypes,
298
+ isMultipleContentTypes,
299
+ contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
300
+ defaultContentType: contentTypes[0] ?? "application/json",
301
+ hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
302
+ };
303
+ }
304
+ function buildRequestConfigType(node) {
305
+ const { isMultipleContentTypes, contentTypeUnion } = getContentTypeInfo(node);
306
+ const configType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`;
307
+ const contentTypeProp = isMultipleContentTypes ? `contentType?: ${contentTypeUnion}` : null;
308
+ return contentTypeProp ? `${configType} & { ${contentTypeProp} }` : configType;
309
+ }
310
+ /**
311
+ * Which of the grouped request options an operation carries.
312
+ */
313
+ function getRequestGroups(node) {
314
+ const { path, query, header } = getOperationParameters(node);
315
+ return {
316
+ path: path.length > 0,
317
+ query: query.length > 0,
318
+ body: Boolean(node.requestBody?.content?.[0]?.schema),
319
+ headers: header.length > 0
320
+ };
321
+ }
322
+ /**
323
+ * Resolves which grouped request options an operation carries together with whether each group
324
+ * holds a required member. The grouped parameter stays optional only when nothing inside it is
325
+ * required, matching the generated `RequestConfig` type.
326
+ */
327
+ function getRequestGroupOptionality(node) {
328
+ const groups = getRequestGroups(node);
329
+ const { path, query, header } = getOperationParameters(node);
330
+ const hasRequiredPath = path.some((param) => param.required);
331
+ const hasRequiredQuery = query.some((param) => param.required);
332
+ const hasRequiredHeader = header.some((param) => param.required);
333
+ return {
334
+ groups,
335
+ hasRequiredPath,
336
+ hasRequiredQuery,
337
+ hasRequiredHeader,
338
+ isOptional: !hasRequiredPath && !hasRequiredQuery && !hasRequiredHeader && !groups.body
339
+ };
340
+ }
341
+ /**
342
+ * Builds the grouped `{ path, query, body, headers }` parameter for a generated client
343
+ * function, typed from the operation's `RequestConfig` (minus `url`). Only the groups the
344
+ * operation actually has are destructured. The trailing `config` parameter carries the
345
+ * runtime `RequestConfig` overrides plus `client`.
346
+ */
347
+ function buildRequestParamsSignature(node, resolver, options = {}) {
348
+ const { isConfigurable = true } = options;
349
+ const { groups, isOptional } = getRequestGroupOptionality(node);
350
+ const names = [
351
+ "path",
352
+ "query",
353
+ "body",
354
+ "headers"
355
+ ].filter((key) => groups[key]);
356
+ return {
357
+ signature: [names.length > 0 ? `{ ${names.join(", ")} }: ${resolver.resolveRequestConfigName(node)}${isOptional ? " = {}" : ""}` : null, isConfigurable ? `config: ${buildRequestConfigType(node)} = {}` : null].filter(Boolean).join(", "),
358
+ groups
359
+ };
360
+ }
246
361
  function getOperationParameters(node, options = {}) {
247
- const params = ast.caseParams(node.parameters, options.paramsCasing);
362
+ const params = caseParams(node.parameters, options.paramsCasing === "original" ? void 0 : "camelcase");
248
363
  return {
249
364
  path: params.filter((param) => param.in === "path"),
250
365
  query: params.filter((param) => param.in === "query"),
@@ -268,7 +383,7 @@ function resolveStatusCodeNames(node, resolver) {
268
383
  }
269
384
  const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
270
385
  function resolveOperationTypeNames(node, resolver, options = {}) {
271
- const cacheKey = `${node.operationId}\0${options.paramsCasing ?? ""}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${(options.exclude ?? []).join(",")}`;
386
+ const cacheKey = `${node.operationId}\0${options.paramsCasing ?? ""}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${options.includeParams === false ? "noparams" : ""}\0${(options.exclude ?? []).join(",")}`;
272
387
  let byResolver = typeNamesByResolver.get(resolver);
273
388
  if (byResolver) {
274
389
  const cached = byResolver.get(cacheKey);
@@ -280,7 +395,7 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
280
395
  const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing });
281
396
  const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
282
397
  const exclude = new Set(options.exclude ?? []);
283
- const paramNames = [
398
+ const paramNames = options.includeParams === false ? [] : [
284
399
  ...path.map((param) => resolver.resolvePathParamsName(node, param)),
285
400
  ...query.map((param) => resolver.resolveQueryParamsName(node, param)),
286
401
  ...header.map((param) => resolver.resolveHeaderParamsName(node, param))
@@ -331,52 +446,31 @@ function createGroupConfig(group) {
331
446
  }
332
447
  //#endregion
333
448
  //#region src/components/Request.tsx
334
- const declarationPrinter = functionPrinter({ mode: "declaration" });
335
- function Request({ baseURL = "", name, dataReturnType, resolver, node, paramsType, pathParamsType, paramsCasing }) {
449
+ function Request({ baseURL = "", name, resolver, node }) {
336
450
  if (!ast.isHttpOperationNode(node)) return null;
337
- const paramsNode = ast.createOperationParams(node, {
338
- paramsType,
339
- pathParamsType,
340
- paramsCasing,
341
- resolver,
342
- extraParams: [ast.createFunctionParameter({
343
- name: "options",
344
- type: ast.createParamsType({
345
- variant: "reference",
346
- name: "Partial<Cypress.RequestOptions>"
347
- }),
348
- default: "{}"
349
- })]
350
- });
351
- const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
451
+ const { query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node, { paramsCasing: "original" });
452
+ const { query: casedQueryParams, header: casedHeaderParams } = getOperationParameters(node);
453
+ const queryParamsMapping = buildParamsMapping(originalQueryParams, casedQueryParams);
454
+ const headerParamsMapping = buildParamsMapping(originalHeaderParams, casedHeaderParams);
455
+ const { signature, groups } = buildRequestParamsSignature(node, resolver, { isConfigurable: false });
456
+ const paramsSignature = [signature, "options: Partial<Cypress.RequestOptions> = {}"].filter(Boolean).join(", ");
352
457
  const responseType = resolver.resolveResponseName(node);
353
- const returnType = dataReturnType === "data" ? `Cypress.Chainable<${responseType}>` : `Cypress.Chainable<Cypress.Response<${responseType}>>`;
354
- const casedPathParams = getOperationParameters(node, { paramsCasing }).path;
355
- const pathParamNameMap = new Map(casedPathParams.map((p) => [camelCase(p.name), p.name]));
356
- const urlTemplate = Url.toTemplateString(node.path, {
357
- prefix: baseURL,
358
- replacer: (param) => pathParamNameMap.get(camelCase(param)) ?? param,
359
- casing: paramsCasing
360
- });
458
+ const returnType = `Cypress.Chainable<${responseType}>`;
459
+ const urlTemplate = Url.toGroupedTemplateString(node.path, { prefix: baseURL });
361
460
  const requestOptions = [`method: '${node.method}'`, `url: ${urlTemplate}`];
362
- const queryParams = getOperationParameters(node).query;
363
- if (queryParams.length > 0) {
364
- const casedQueryParams = getOperationParameters(node, { paramsCasing }).query;
365
- if (casedQueryParams.some((p, i) => p.name !== queryParams[i].name)) {
366
- const pairs = queryParams.map((orig, i) => `${orig.name}: params.${casedQueryParams[i].name}`).join(", ");
367
- requestOptions.push(`qs: params ? { ${pairs} } : undefined`);
368
- } else requestOptions.push("qs: params");
369
- }
370
- const headerParams = getOperationParameters(node).header;
371
- if (headerParams.length > 0) {
372
- const casedHeaderParams = getOperationParameters(node, { paramsCasing }).header;
373
- if (casedHeaderParams.some((p, i) => p.name !== headerParams[i].name)) {
374
- const pairs = headerParams.map((orig, i) => `'${orig.name}': headers.${casedHeaderParams[i].name}`).join(", ");
375
- requestOptions.push(`headers: headers ? { ${pairs} } : undefined`);
376
- } else requestOptions.push("headers");
377
- }
378
- if (node.requestBody?.content?.[0]?.schema) requestOptions.push("body: data");
461
+ if (groups.query) if (queryParamsMapping) {
462
+ const pairs = Object.entries(queryParamsMapping).map(([originalName, camelCaseName]) => `${originalName}: query.${camelCaseName}`).join(", ");
463
+ requestOptions.push(`qs: query ? { ${pairs} } : undefined`);
464
+ } else requestOptions.push("qs: query");
465
+ if (groups.headers) if (headerParamsMapping) {
466
+ const pairs = Object.entries(headerParamsMapping).map(([originalName, camelCaseName]) => `'${originalName}': headers.${camelCaseName}`).join(", ");
467
+ requestOptions.push(`headers: headers ? { ${pairs} } : undefined`);
468
+ } else requestOptions.push("headers");
469
+ if (groups.body) requestOptions.push("body");
379
470
  requestOptions.push("...options");
471
+ const requestCall = `return cy.request<${responseType}>({
472
+ ${requestOptions.join(",\n ")}
473
+ }).then((res) => res.body)`;
380
474
  return /* @__PURE__ */ jsx(File.Source, {
381
475
  name,
382
476
  isIndexable: true,
@@ -386,11 +480,7 @@ function Request({ baseURL = "", name, dataReturnType, resolver, node, paramsTyp
386
480
  export: true,
387
481
  params: paramsSignature,
388
482
  returnType,
389
- children: dataReturnType === "data" ? `return cy.request<${responseType}>({
390
- ${requestOptions.join(",\n ")}
391
- }).then((res) => res.body)` : `return cy.request<${responseType}>({
392
- ${requestOptions.join(",\n ")}
393
- })`
483
+ children: requestCall
394
484
  })
395
485
  });
396
486
  }
@@ -407,11 +497,11 @@ const cypressGenerator = defineGenerator({
407
497
  operation(node, ctx) {
408
498
  if (!ast.isHttpOperationNode(node)) return null;
409
499
  const { config, resolver, driver, root } = ctx;
410
- const { output, baseURL, dataReturnType, paramsCasing, paramsType, pathParamsType, group } = ctx.options;
500
+ const { output, baseURL, group } = ctx.options;
411
501
  const pluginTs = driver.getPlugin(pluginTsName);
412
502
  if (!pluginTs) return null;
413
503
  const tsResolver = driver.getResolver(pluginTsName);
414
- const importedTypeNames = resolveOperationTypeNames(node, tsResolver, { paramsCasing });
504
+ const importedTypeNames = [tsResolver.resolveRequestConfigName(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })];
415
505
  const meta = {
416
506
  name: resolver.resolveName(node.operationId),
417
507
  file: resolver.resolveFile({
@@ -464,10 +554,6 @@ const cypressGenerator = defineGenerator({
464
554
  name: meta.name,
465
555
  node,
466
556
  resolver: tsResolver,
467
- dataReturnType,
468
- paramsCasing,
469
- paramsType,
470
- pathParamsType,
471
557
  baseURL
472
558
  })]
473
559
  });
@@ -478,7 +564,7 @@ const cypressGenerator = defineGenerator({
478
564
  /**
479
565
  * Default resolver used by `@kubb/plugin-cypress`. Decides the names and file
480
566
  * paths for every generated `cy.request()` wrapper. Functions and files use
481
- * camelCase, matching the convention from `@kubb/plugin-client`.
567
+ * camelCase, matching the convention from `@kubb/plugin-axios` and `@kubb/plugin-fetch`.
482
568
  *
483
569
  * @example Resolve a helper name
484
570
  * ```ts
@@ -534,7 +620,7 @@ const pluginCypress = definePlugin((options) => {
534
620
  const { output = {
535
621
  path: "cypress",
536
622
  barrel: { type: "named" }
537
- }, group, exclude = [], include, override = [], dataReturnType = "data", baseURL, paramsCasing, paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
623
+ }, group, exclude = [], include, override = [], baseURL, resolver: userResolver, macros: userMacros } = options;
538
624
  const groupConfig = createGroupConfig(group);
539
625
  return {
540
626
  name: pluginCypressName,
@@ -550,18 +636,13 @@ const pluginCypress = definePlugin((options) => {
550
636
  exclude,
551
637
  include,
552
638
  override,
553
- dataReturnType,
554
639
  group: groupConfig,
555
640
  baseURL,
556
- paramsCasing,
557
- paramsType,
558
- pathParamsType,
559
641
  resolver
560
642
  });
561
643
  ctx.setResolver(resolver);
562
- if (userTransformer) ctx.setTransformer(userTransformer);
644
+ if (userMacros?.length) ctx.setMacros(userMacros);
563
645
  ctx.addGenerator(cypressGenerator);
564
- for (const gen of userGenerators) ctx.addGenerator(gen);
565
646
  } }
566
647
  };
567
648
  });