@kubb/plugin-cypress 5.0.0-beta.3 → 5.0.0-beta.31

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
@@ -16,26 +16,32 @@ type ResolverCypress = Resolver & {
16
16
  * `resolver.resolveName('show pet by id') // -> 'showPetById'`
17
17
  */
18
18
  resolveName(this: ResolverCypress, name: string): string;
19
+ /**
20
+ * Resolves the output file name for a Cypress request module.
21
+ */
22
+ resolvePathName(this: ResolverCypress, name: string, type?: 'file' | 'function' | 'type' | 'const'): string;
19
23
  };
20
24
  /**
21
25
  * Parameter handling mode that determines how path params and query/body params are arranged in function signatures.
22
26
  */
23
27
  type ParamsTypeOptions = {
24
28
  /**
25
- * All parameters merged into a single destructured object.
29
+ * Every operation parameter is wrapped in a single destructured object argument.
26
30
  */
27
31
  paramsType: 'object';
28
32
  /**
29
- * Not applicable when all parameters are merged into a single object.
33
+ * `pathParamsType` has no effect when `paramsType` is `'object'`.
30
34
  */
31
35
  pathParamsType?: never;
32
36
  } | {
33
37
  /**
34
- * Each parameter group emitted as a separate function argument.
38
+ * Each parameter group is emitted as a separate positional function argument.
35
39
  */
36
40
  paramsType?: 'inline';
37
41
  /**
38
- * How path parameters are arranged: grouped in an object or spread inline.
42
+ * How URL path parameters are arranged inside the inline argument list.
43
+ * - `'object'` groups them into one destructured object.
44
+ * - `'inline'` emits each path param as its own argument.
39
45
  *
40
46
  * @default 'inline'
41
47
  */
@@ -43,50 +49,56 @@ type ParamsTypeOptions = {
43
49
  };
44
50
  type Options = {
45
51
  /**
46
- * Specify the export location for the files and define the behavior of the output.
47
- * @default { path: 'cypress', barrelType: 'named' }
52
+ * Where the generated Cypress helpers are written and how they are exported.
53
+ *
54
+ * @default { path: 'cypress', barrel: { type: 'named' } }
48
55
  */
49
56
  output?: Output;
50
57
  /**
51
- * Return type when calling cy.request: response data only or full response.
58
+ * Shape of the value returned from each helper.
59
+ * - `'data'` — only the response body.
60
+ * - `'full'` — the full Cypress response object (headers, status, body).
52
61
  *
53
62
  * @default 'data'
54
63
  */
55
64
  dataReturnType?: 'data' | 'full';
56
65
  /**
57
- * Apply casing to parameter names.
66
+ * Rename parameter properties in the generated helpers (path, query, headers).
67
+ *
68
+ * @note Must match the value of `paramsCasing` on `@kubb/plugin-ts`.
58
69
  */
59
70
  paramsCasing?: 'camelcase';
60
71
  /**
61
- * Base URL prepended to every generated request URL.
72
+ * Base URL prepended to every request URL. When omitted, falls back to the
73
+ * adapter's server URL (typically `servers[0].url`).
62
74
  */
63
75
  baseURL?: string;
64
76
  /**
65
- * Group the Cypress requests based on the provided name.
77
+ * Split generated files into subfolders based on the operation's tag.
66
78
  */
67
79
  group?: Group;
68
80
  /**
69
- * Tags, operations, or paths to exclude from generation.
81
+ * Skip operations matching at least one entry in the list.
70
82
  */
71
83
  exclude?: Array<Exclude>;
72
84
  /**
73
- * Tags, operations, or paths to include in generation.
85
+ * Restrict generation to operations matching at least one entry in the list.
74
86
  */
75
87
  include?: Array<Include>;
76
88
  /**
77
- * Override options for specific tags, operations, or paths.
89
+ * Apply a different options object to operations matching a pattern.
78
90
  */
79
91
  override?: Array<Override<ResolvedOptions>>;
80
92
  /**
81
- * Override naming conventions for function names and types.
93
+ * Override how helper names and file paths are built.
82
94
  */
83
95
  resolver?: Partial<ResolverCypress> & ThisType<ResolverCypress>;
84
96
  /**
85
- * AST visitor to transform generated nodes.
97
+ * AST visitor applied to each operation node before printing.
86
98
  */
87
99
  transformer?: ast.Visitor;
88
100
  /**
89
- * Additional generators alongside the default generators.
101
+ * Custom generators that run alongside the built-in Cypress generators.
90
102
  */
91
103
  generators?: Array<Generator<PluginCypress>>;
92
104
  } & ParamsTypeOptions;
@@ -95,7 +107,7 @@ type ResolvedOptions = {
95
107
  exclude: Array<Exclude>;
96
108
  include: Array<Include> | undefined;
97
109
  override: Array<Override<ResolvedOptions>>;
98
- group: Group | undefined;
110
+ group: Group | null;
99
111
  baseURL: Options['baseURL'] | undefined;
100
112
  dataReturnType: NonNullable<Options['dataReturnType']>;
101
113
  pathParamsType: NonNullable<NonNullable<Options['pathParamsType']>>;
@@ -126,7 +138,7 @@ type Props = {
126
138
  * TypeScript resolver for resolving param/data/response type names
127
139
  */
128
140
  resolver: ResolverTs;
129
- baseURL: string | undefined;
141
+ baseURL: string | null | undefined;
130
142
  dataReturnType: PluginCypress['resolvedOptions']['dataReturnType'];
131
143
  paramsCasing: PluginCypress['resolvedOptions']['paramsCasing'];
132
144
  paramsType: PluginCypress['resolvedOptions']['paramsType'];
@@ -144,27 +156,39 @@ declare function Request({
144
156
  }: Props): KubbReactNode;
145
157
  //#endregion
146
158
  //#region src/generators/cypressGenerator.d.ts
159
+ /**
160
+ * Built-in generator for `@kubb/plugin-cypress`. Emits one typed
161
+ * `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress
162
+ * test specs and custom commands.
163
+ */
147
164
  declare const cypressGenerator: _$_kubb_core0.Generator<PluginCypress, unknown>;
148
165
  //#endregion
149
166
  //#region src/plugin.d.ts
150
167
  /**
151
- * Canonical plugin name for `@kubb/plugin-cypress`, used to identify the plugin
152
- * in driver lookups and warnings.
168
+ * Canonical plugin name for `@kubb/plugin-cypress`. Used for driver lookups and
169
+ * cross-plugin dependency references.
153
170
  */
154
171
  declare const pluginCypressName = "plugin-cypress";
155
172
  /**
156
- * The `@kubb/plugin-cypress` plugin factory.
157
- *
158
- * Generates Cypress `cy.request()` test functions from an OpenAPI/AST `RootNode`.
159
- * Walks operations, delegates rendering to the active generators,
160
- * and writes barrel files based on `output.barrelType`.
173
+ * Generates one typed `cy.request()` wrapper per OpenAPI operation. Each helper
174
+ * has typed path params, body, query, and a typed response, so failing API
175
+ * calls in Cypress show up at compile time instead of inside the test runner.
161
176
  *
162
177
  * @example
163
178
  * ```ts
164
- * import pluginCypress from '@kubb/plugin-cypress'
179
+ * import { defineConfig } from 'kubb'
180
+ * import { pluginTs } from '@kubb/plugin-ts'
181
+ * import { pluginCypress } from '@kubb/plugin-cypress'
165
182
  *
166
183
  * export default defineConfig({
167
- * plugins: [pluginCypress({ output: { path: 'cypress' } })],
184
+ * input: { path: './petStore.yaml' },
185
+ * output: { path: './src/gen' },
186
+ * plugins: [
187
+ * pluginTs(),
188
+ * pluginCypress({
189
+ * output: { path: './cypress' },
190
+ * }),
191
+ * ],
168
192
  * })
169
193
  * ```
170
194
  */
@@ -172,12 +196,16 @@ declare const pluginCypress: (options?: Options | undefined) => _$_kubb_core0.Pl
172
196
  //#endregion
173
197
  //#region src/resolvers/resolverCypress.d.ts
174
198
  /**
175
- * Naming convention resolver for Cypress plugin.
199
+ * Default resolver used by `@kubb/plugin-cypress`. Decides the names and file
200
+ * paths for every generated `cy.request()` wrapper. Functions and files use
201
+ * camelCase, matching the convention from `@kubb/plugin-client`.
176
202
  *
177
- * Provides default naming helpers using camelCase for functions and file paths.
203
+ * @example Resolve a helper name
204
+ * ```ts
205
+ * import { resolverCypress } from '@kubb/plugin-cypress'
178
206
  *
179
- * @example
180
- * `resolverCypress.default('list pets', 'function') // → 'listPets'`
207
+ * resolverCypress.default('list pets', 'function') // 'listPets'
208
+ * ```
181
209
  */
182
210
  declare const resolverCypress: ResolverCypress;
183
211
  //#endregion
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import "./chunk--u3MIqq1.js";
2
2
  import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
3
3
  import { functionPrinter, pluginTsName } from "@kubb/plugin-ts";
4
- import { File, Function, jsxRenderer } from "@kubb/renderer-jsx";
4
+ import { File, Function, jsxRendererSync } from "@kubb/renderer-jsx";
5
5
  import { jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
6
6
  //#region ../../internals/utils/src/casing.ts
7
7
  /**
@@ -214,16 +214,16 @@ var URLPath = class {
214
214
  get object() {
215
215
  return this.toObject();
216
216
  }
217
- /** Returns a map of path parameter names, or `undefined` when the path has no parameters.
217
+ /** Returns a map of path parameter names, or `null` when the path has no parameters.
218
218
  *
219
219
  * @example
220
220
  * ```ts
221
221
  * new URLPath('/pet/{petId}').params // { petId: 'petId' }
222
- * new URLPath('/pet').params // undefined
222
+ * new URLPath('/pet').params // null
223
223
  * ```
224
224
  */
225
225
  get params() {
226
- return this.getParams();
226
+ return this.toParamsObject();
227
227
  }
228
228
  #transformParam(raw) {
229
229
  const param = isValidVarName(raw) ? raw : camelCase(raw);
@@ -241,7 +241,7 @@ var URLPath = class {
241
241
  toObject({ type = "path", replacer, stringify } = {}) {
242
242
  const object = {
243
243
  url: type === "path" ? this.toURLPath() : this.toTemplateString({ replacer }),
244
- params: this.getParams()
244
+ params: this.toParamsObject()
245
245
  };
246
246
  if (stringify) {
247
247
  if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
@@ -257,12 +257,13 @@ var URLPath = class {
257
257
  * @example
258
258
  * new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
259
259
  */
260
- toTemplateString({ prefix = "", replacer } = {}) {
261
- return `\`${prefix}${this.path.split(/\{([^}]+)\}/).map((part, i) => {
260
+ toTemplateString({ prefix, replacer } = {}) {
261
+ const result = this.path.split(/\{([^}]+)\}/).map((part, i) => {
262
262
  if (i % 2 === 0) return part;
263
263
  const param = this.#transformParam(part);
264
264
  return `\${${replacer ? replacer(param) : param}}`;
265
- }).join("")}\``;
265
+ }).join("");
266
+ return `\`${prefix ?? ""}${result}\``;
266
267
  }
267
268
  /**
268
269
  * Extracts all `{param}` segments from the path and returns them as a key-value map.
@@ -271,17 +272,17 @@ var URLPath = class {
271
272
  *
272
273
  * @example
273
274
  * ```ts
274
- * new URLPath('/pet/{petId}/tag/{tagId}').getParams()
275
+ * new URLPath('/pet/{petId}/tag/{tagId}').toParamsObject()
275
276
  * // { petId: 'petId', tagId: 'tagId' }
276
277
  * ```
277
278
  */
278
- getParams(replacer) {
279
+ toParamsObject(replacer) {
279
280
  const params = {};
280
281
  this.#eachParam((_raw, param) => {
281
282
  const key = replacer ? replacer(param) : param;
282
283
  params[key] = key;
283
284
  });
284
- return Object.keys(params).length > 0 ? params : void 0;
285
+ return Object.keys(params).length > 0 ? params : null;
285
286
  }
286
287
  /** Converts the OpenAPI path to Express-style colon syntax.
287
288
  *
@@ -295,9 +296,100 @@ var URLPath = class {
295
296
  }
296
297
  };
297
298
  //#endregion
299
+ //#region ../../internals/shared/src/operation.ts
300
+ function getOperationParameters(node, options = {}) {
301
+ const params = ast.caseParams(node.parameters, options.paramsCasing);
302
+ return {
303
+ path: params.filter((param) => param.in === "path"),
304
+ query: params.filter((param) => param.in === "query"),
305
+ header: params.filter((param) => param.in === "header"),
306
+ cookie: params.filter((param) => param.in === "cookie")
307
+ };
308
+ }
309
+ function getStatusCodeNumber(statusCode) {
310
+ const code = Number(statusCode);
311
+ return Number.isNaN(code) ? null : code;
312
+ }
313
+ function isErrorStatusCode(statusCode) {
314
+ const code = getStatusCodeNumber(statusCode);
315
+ return code !== null && code >= 400;
316
+ }
317
+ function resolveErrorNames(node, resolver) {
318
+ return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
319
+ }
320
+ function resolveStatusCodeNames(node, resolver) {
321
+ return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
322
+ }
323
+ const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
324
+ function resolveOperationTypeNames(node, resolver, options = {}) {
325
+ const cacheKey = `${node.operationId}\0${options.paramsCasing ?? ""}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${(options.exclude ?? []).join(",")}`;
326
+ let byResolver = typeNamesByResolver.get(resolver);
327
+ if (byResolver) {
328
+ const cached = byResolver.get(cacheKey);
329
+ if (cached) return cached;
330
+ } else {
331
+ byResolver = /* @__PURE__ */ new Map();
332
+ typeNamesByResolver.set(resolver, byResolver);
333
+ }
334
+ const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing });
335
+ const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
336
+ const exclude = new Set(options.exclude ?? []);
337
+ const paramNames = [
338
+ ...path.map((param) => resolver.resolvePathParamsName(node, param)),
339
+ ...query.map((param) => resolver.resolveQueryParamsName(node, param)),
340
+ ...header.map((param) => resolver.resolveHeaderParamsName(node, param))
341
+ ];
342
+ const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null, resolver.resolveResponseName(node)];
343
+ const result = (options.order === "body-response-first" ? [
344
+ ...bodyAndResponseNames,
345
+ ...paramNames,
346
+ ...responseStatusNames
347
+ ] : [
348
+ ...paramNames,
349
+ ...bodyAndResponseNames,
350
+ ...responseStatusNames
351
+ ]).filter((name) => Boolean(name) && !exclude.has(name));
352
+ byResolver.set(cacheKey, result);
353
+ return result;
354
+ }
355
+ //#endregion
356
+ //#region ../../internals/shared/src/group.ts
357
+ /**
358
+ * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
359
+ * shared default naming so every plugin groups output consistently:
360
+ *
361
+ * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
362
+ * - other groups use `${camelCase(group)}${suffix}` (e.g. `petController`).
363
+ *
364
+ * Returns `null` when grouping is disabled, matching the per-plugin convention.
365
+ *
366
+ * @param group - The user-supplied group option, or `undefined` to disable grouping.
367
+ * @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.
368
+ * @param options.honorName - When `true`, a user-provided `group.name` overrides the default namer.
369
+ *
370
+ * @example
371
+ * ```ts
372
+ * createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-zod
373
+ * createGroupConfig(group, { suffix: 'Controller', honorName: true }) // plugin-faker, plugin-client, …
374
+ * createGroupConfig(group, { suffix: 'Requests', honorName: true }) // plugin-cypress, plugin-mcp
375
+ * ```
376
+ */
377
+ function createGroupConfig(group, options) {
378
+ if (!group) return null;
379
+ const defaultName = (ctx) => {
380
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
381
+ return `${camelCase(ctx.group)}${options.suffix}`;
382
+ };
383
+ return {
384
+ ...group,
385
+ name: options.honorName && group.name ? group.name : defaultName
386
+ };
387
+ }
388
+ //#endregion
298
389
  //#region src/components/Request.tsx
299
390
  const declarationPrinter = functionPrinter({ mode: "declaration" });
300
391
  function Request({ baseURL = "", name, dataReturnType, resolver, node, paramsType, pathParamsType, paramsCasing }) {
392
+ if (!ast.isHttpOperationNode(node)) return null;
301
393
  const paramsNode = ast.createOperationParams(node, {
302
394
  paramsType,
303
395
  pathParamsType,
@@ -315,24 +407,24 @@ function Request({ baseURL = "", name, dataReturnType, resolver, node, paramsTyp
315
407
  const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
316
408
  const responseType = resolver.resolveResponseName(node);
317
409
  const returnType = dataReturnType === "data" ? `Cypress.Chainable<${responseType}>` : `Cypress.Chainable<Cypress.Response<${responseType}>>`;
318
- const casedPathParams = ast.caseParams(node.parameters.filter((p) => p.in === "path"), paramsCasing);
410
+ const casedPathParams = getOperationParameters(node, { paramsCasing }).path;
319
411
  const pathParamNameMap = new Map(casedPathParams.map((p) => [camelCase(p.name), p.name]));
320
412
  const urlTemplate = new URLPath(node.path, { casing: paramsCasing }).toTemplateString({
321
413
  prefix: baseURL,
322
414
  replacer: (param) => pathParamNameMap.get(camelCase(param)) ?? param
323
415
  });
324
416
  const requestOptions = [`method: '${node.method}'`, `url: ${urlTemplate}`];
325
- const queryParams = node.parameters.filter((p) => p.in === "query");
417
+ const queryParams = getOperationParameters(node).query;
326
418
  if (queryParams.length > 0) {
327
- const casedQueryParams = ast.caseParams(queryParams, paramsCasing);
419
+ const casedQueryParams = getOperationParameters(node, { paramsCasing }).query;
328
420
  if (casedQueryParams.some((p, i) => p.name !== queryParams[i].name)) {
329
421
  const pairs = queryParams.map((orig, i) => `${orig.name}: params.${casedQueryParams[i].name}`).join(", ");
330
422
  requestOptions.push(`qs: params ? { ${pairs} } : undefined`);
331
423
  } else requestOptions.push("qs: params");
332
424
  }
333
- const headerParams = node.parameters.filter((p) => p.in === "header");
425
+ const headerParams = getOperationParameters(node).header;
334
426
  if (headerParams.length > 0) {
335
- const casedHeaderParams = ast.caseParams(headerParams, paramsCasing);
427
+ const casedHeaderParams = getOperationParameters(node, { paramsCasing }).header;
336
428
  if (casedHeaderParams.some((p, i) => p.name !== headerParams[i].name)) {
337
429
  const pairs = headerParams.map((orig, i) => `'${orig.name}': headers.${casedHeaderParams[i].name}`).join(", ");
338
430
  requestOptions.push(`headers: headers ? { ${pairs} } : undefined`);
@@ -359,26 +451,22 @@ function Request({ baseURL = "", name, dataReturnType, resolver, node, paramsTyp
359
451
  }
360
452
  //#endregion
361
453
  //#region src/generators/cypressGenerator.tsx
454
+ /**
455
+ * Built-in generator for `@kubb/plugin-cypress`. Emits one typed
456
+ * `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress
457
+ * test specs and custom commands.
458
+ */
362
459
  const cypressGenerator = defineGenerator({
363
460
  name: "cypress",
364
- renderer: jsxRenderer,
461
+ renderer: jsxRendererSync,
365
462
  operation(node, ctx) {
366
- const { adapter, config, resolver, driver, root } = ctx;
463
+ if (!ast.isHttpOperationNode(node)) return null;
464
+ const { config, resolver, driver, root } = ctx;
367
465
  const { output, baseURL, dataReturnType, paramsCasing, paramsType, pathParamsType, group } = ctx.options;
368
466
  const pluginTs = driver.getPlugin(pluginTsName);
369
467
  if (!pluginTs) return null;
370
468
  const tsResolver = driver.getResolver(pluginTsName);
371
- const casedParams = ast.caseParams(node.parameters, paramsCasing);
372
- const pathParams = casedParams.filter((p) => p.in === "path");
373
- const queryParams = casedParams.filter((p) => p.in === "query");
374
- const headerParams = casedParams.filter((p) => p.in === "header");
375
- const importedTypeNames = [
376
- ...pathParams.map((p) => tsResolver.resolvePathParamsName(node, p)),
377
- ...queryParams.map((p) => tsResolver.resolveQueryParamsName(node, p)),
378
- ...headerParams.map((p) => tsResolver.resolveHeaderParamsName(node, p)),
379
- node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0,
380
- tsResolver.resolveResponseName(node)
381
- ].filter(Boolean);
469
+ const importedTypeNames = resolveOperationTypeNames(node, tsResolver, { paramsCasing });
382
470
  const meta = {
383
471
  name: resolver.resolveName(node.operationId),
384
472
  file: resolver.resolveFile({
@@ -389,7 +477,7 @@ const cypressGenerator = defineGenerator({
389
477
  }, {
390
478
  root,
391
479
  output,
392
- group
480
+ group: group ?? void 0
393
481
  }),
394
482
  fileTs: tsResolver.resolveFile({
395
483
  name: node.operationId,
@@ -399,23 +487,31 @@ const cypressGenerator = defineGenerator({
399
487
  }, {
400
488
  root,
401
489
  output: pluginTs.options?.output ?? output,
402
- group: pluginTs.options?.group
490
+ group: pluginTs.options?.group ?? void 0
403
491
  })
404
492
  };
405
493
  return /* @__PURE__ */ jsxs(File, {
406
494
  baseName: meta.file.baseName,
407
495
  path: meta.file.path,
408
496
  meta: meta.file.meta,
409
- banner: resolver.resolveBanner(adapter.inputNode, {
497
+ banner: resolver.resolveBanner(ctx.meta, {
410
498
  output,
411
- config
499
+ config,
500
+ file: {
501
+ path: meta.file.path,
502
+ baseName: meta.file.baseName
503
+ }
412
504
  }),
413
- footer: resolver.resolveFooter(adapter.inputNode, {
505
+ footer: resolver.resolveFooter(ctx.meta, {
414
506
  output,
415
- config
507
+ config,
508
+ file: {
509
+ path: meta.file.path,
510
+ baseName: meta.file.baseName
511
+ }
416
512
  }),
417
513
  children: [meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
418
- name: Array.from(new Set(importedTypeNames)),
514
+ name: importedTypeNames,
419
515
  root: meta.file.path,
420
516
  path: meta.fileTs.path,
421
517
  isTypeOnly: true
@@ -435,43 +531,57 @@ const cypressGenerator = defineGenerator({
435
531
  //#endregion
436
532
  //#region src/resolvers/resolverCypress.ts
437
533
  /**
438
- * Naming convention resolver for Cypress plugin.
534
+ * Default resolver used by `@kubb/plugin-cypress`. Decides the names and file
535
+ * paths for every generated `cy.request()` wrapper. Functions and files use
536
+ * camelCase, matching the convention from `@kubb/plugin-client`.
439
537
  *
440
- * Provides default naming helpers using camelCase for functions and file paths.
538
+ * @example Resolve a helper name
539
+ * ```ts
540
+ * import { resolverCypress } from '@kubb/plugin-cypress'
441
541
  *
442
- * @example
443
- * `resolverCypress.default('list pets', 'function') // → 'listPets'`
542
+ * resolverCypress.default('list pets', 'function') // 'listPets'
543
+ * ```
444
544
  */
445
- const resolverCypress = defineResolver((ctx) => ({
545
+ const resolverCypress = defineResolver(() => ({
446
546
  name: "default",
447
547
  pluginName: "plugin-cypress",
448
548
  default(name, type) {
449
549
  return camelCase(name, { isFile: type === "file" });
450
550
  },
451
551
  resolveName(name) {
452
- return ctx.default(name, "function");
552
+ return this.default(name, "function");
553
+ },
554
+ resolvePathName(name, type) {
555
+ return this.default(name, type);
453
556
  }
454
557
  }));
455
558
  //#endregion
456
559
  //#region src/plugin.ts
457
560
  /**
458
- * Canonical plugin name for `@kubb/plugin-cypress`, used to identify the plugin
459
- * in driver lookups and warnings.
561
+ * Canonical plugin name for `@kubb/plugin-cypress`. Used for driver lookups and
562
+ * cross-plugin dependency references.
460
563
  */
461
564
  const pluginCypressName = "plugin-cypress";
462
565
  /**
463
- * The `@kubb/plugin-cypress` plugin factory.
464
- *
465
- * Generates Cypress `cy.request()` test functions from an OpenAPI/AST `RootNode`.
466
- * Walks operations, delegates rendering to the active generators,
467
- * and writes barrel files based on `output.barrelType`.
566
+ * Generates one typed `cy.request()` wrapper per OpenAPI operation. Each helper
567
+ * has typed path params, body, query, and a typed response, so failing API
568
+ * calls in Cypress show up at compile time instead of inside the test runner.
468
569
  *
469
570
  * @example
470
571
  * ```ts
471
- * import pluginCypress from '@kubb/plugin-cypress'
572
+ * import { defineConfig } from 'kubb'
573
+ * import { pluginTs } from '@kubb/plugin-ts'
574
+ * import { pluginCypress } from '@kubb/plugin-cypress'
472
575
  *
473
576
  * export default defineConfig({
474
- * plugins: [pluginCypress({ output: { path: 'cypress' } })],
577
+ * input: { path: './petStore.yaml' },
578
+ * output: { path: './src/gen' },
579
+ * plugins: [
580
+ * pluginTs(),
581
+ * pluginCypress({
582
+ * output: { path: './cypress' },
583
+ * }),
584
+ * ],
475
585
  * })
476
586
  * ```
477
587
  */
@@ -480,13 +590,10 @@ const pluginCypress = definePlugin((options) => {
480
590
  path: "cypress",
481
591
  barrelType: "named"
482
592
  }, group, exclude = [], include, override = [], dataReturnType = "data", baseURL, paramsCasing, paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
483
- const groupConfig = group ? {
484
- ...group,
485
- name: group.name ? group.name : (ctx) => {
486
- if (group.type === "path") return `${ctx.group.split("/")[1]}`;
487
- return `${camelCase(ctx.group)}Requests`;
488
- }
489
- } : void 0;
593
+ const groupConfig = createGroupConfig(group, {
594
+ suffix: "Requests",
595
+ honorName: true
596
+ });
490
597
  return {
491
598
  name: pluginCypressName,
492
599
  options,