@kubb/plugin-cypress 5.0.0-beta.85 → 5.0.0-beta.87

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
@@ -34,31 +34,6 @@ function camelCase(text, { prefix = "", suffix = "" } = {}) {
34
34
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
35
35
  }
36
36
  //#endregion
37
- //#region ../../internals/utils/src/fs.ts
38
- /**
39
- * Builds a nested file path from a dotted name. Splits on dots that precede a letter
40
- * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
41
- * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
42
- *
43
- * Empty segments are dropped before joining. They arise when the name starts with a dot
44
- * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
45
- * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
46
- * absolute path, letting generated files escape the configured output directory.
47
- *
48
- * @example Nested path from a dotted name
49
- * `toFilePath('pet.petId') // 'pet/petId'`
50
- *
51
- * @example PascalCase the final segment
52
- * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
53
- *
54
- * @example Suffix applied to the final segment only
55
- * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
56
- */
57
- function toFilePath(name, caseLast = camelCase) {
58
- const parts = name.split(/\.(?=[a-zA-Z])/);
59
- return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
60
- }
61
- //#endregion
62
37
  //#region ../../internals/utils/src/reserved.ts
63
38
  /**
64
39
  * JavaScript and Java reserved words.
@@ -159,6 +134,22 @@ const reservedWords = /* @__PURE__ */ new Set([
159
134
  */
160
135
  function isValidVarName(name) {
161
136
  if (!name || reservedWords.has(name)) return false;
137
+ return isIdentifier(name);
138
+ }
139
+ /**
140
+ * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
141
+ *
142
+ * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
143
+ * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
144
+ * deciding whether an object key needs quoting.
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * isIdentifier('name') // true
149
+ * isIdentifier('x-total')// false
150
+ * ```
151
+ */
152
+ function isIdentifier(name) {
162
153
  return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
163
154
  }
164
155
  //#endregion
@@ -340,8 +331,11 @@ function buildParamsRemapExpression({ source, mapping }) {
340
331
  }
341
332
  //#endregion
342
333
  //#region ../../internals/shared/src/operation.ts
343
- function getContentTypeInfo(node) {
344
- const contentTypes = node.requestBody?.content?.map((e) => e.contentType) ?? [];
334
+ /**
335
+ * Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
336
+ * are present and the union, default, and form-data flags the client uses to pick one.
337
+ */
338
+ function buildContentTypeInfo(contentTypes) {
345
339
  const isMultipleContentTypes = contentTypes.length > 1;
346
340
  return {
347
341
  contentTypes,
@@ -351,20 +345,15 @@ function getContentTypeInfo(node) {
351
345
  hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
352
346
  };
353
347
  }
348
+ function getContentTypeInfo(node) {
349
+ return buildContentTypeInfo(node.requestBody?.content?.map((e) => e.contentType) ?? []);
350
+ }
354
351
  /**
355
352
  * The request-body counterpart for the primary success response: the content types it documents and
356
353
  * whether several are present, so the client can let a caller pick which one to accept.
357
354
  */
358
355
  function getResponseContentTypeInfo(node) {
359
- const contentTypes = getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? [];
360
- const isMultipleContentTypes = contentTypes.length > 1;
361
- return {
362
- contentTypes,
363
- isMultipleContentTypes,
364
- contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
365
- defaultContentType: contentTypes[0] ?? "application/json",
366
- hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
367
- };
356
+ return buildContentTypeInfo(getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? []);
368
357
  }
369
358
  function buildRequestConfigType(node) {
370
359
  const request = getContentTypeInfo(node);
@@ -406,7 +395,7 @@ function getRequestGroupOptionality(node) {
406
395
  }
407
396
  /**
408
397
  * Builds the grouped `{ path, query, body, headers }` parameter for a generated client
409
- * function, typed from the operation's `RequestConfig` (minus `url`). Only the groups the
398
+ * function, typed from the operation's `Options` (minus `url`). Only the groups the
410
399
  * operation actually has are destructured. The trailing `config` parameter carries the
411
400
  * runtime `RequestConfig` overrides plus `client`.
412
401
  */
@@ -420,7 +409,7 @@ function buildRequestParamsSignature(node, resolver, options = {}) {
420
409
  "headers"
421
410
  ].filter((key) => groups[key]);
422
411
  return {
423
- signature: [names.length > 0 ? `{ ${names.join(", ")} }: ${resolver.resolveRequestConfigName(node)}${isOptional ? " = {}" : ""}` : null, isConfigurable ? `config: ${buildRequestConfigType(node)} = {}` : null].filter(Boolean).join(", "),
412
+ signature: [names.length > 0 ? `{ ${names.join(", ")} }: ${resolver.response.options(node)}${isOptional ? " = {}" : ""}` : null, isConfigurable ? `config: ${buildRequestConfigType(node)} = {}` : null].filter(Boolean).join(", "),
424
413
  groups
425
414
  };
426
415
  }
@@ -455,10 +444,10 @@ function getPrimarySuccessResponse(node) {
455
444
  return getOperationSuccessResponses(node)[0] ?? null;
456
445
  }
457
446
  function resolveErrorNames(node, resolver) {
458
- return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
447
+ return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.response.status(node, response.statusCode));
459
448
  }
460
449
  function resolveStatusCodeNames(node, resolver) {
461
- return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
450
+ return node.responses.map((response) => resolver.response.status(node, response.statusCode));
462
451
  }
463
452
  const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
464
453
  function resolveOperationTypeNames(node, resolver, options = {}) {
@@ -475,11 +464,11 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
475
464
  const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
476
465
  const exclude = new Set(options.exclude ?? []);
477
466
  const paramNames = options.includeParams === false ? [] : [
478
- ...path.map((param) => resolver.resolvePathParamsName(node, param)),
479
- ...query.map((param) => resolver.resolveQueryParamsName(node, param)),
480
- ...header.map((param) => resolver.resolveHeaderParamsName(node, param))
467
+ ...path.map((param) => resolver.param.path(node, param)),
468
+ ...query.map((param) => resolver.param.query(node, param)),
469
+ ...header.map((param) => resolver.param.headers(node, param))
481
470
  ];
482
- const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null, resolver.resolveResponseName(node)];
471
+ const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.response.body(node) : null, resolver.response.response(node)];
483
472
  const result = (options.order === "body-response-first" ? [
484
473
  ...bodyAndResponseNames,
485
474
  ...paramNames,
@@ -533,7 +522,7 @@ function Request({ baseURL = "", name, resolver, node }) {
533
522
  const headerParamsMapping = buildParamsMapping(originalHeaderParams, casedHeaderParams);
534
523
  const { signature, groups } = buildRequestParamsSignature(node, resolver, { isConfigurable: false });
535
524
  const paramsSignature = [signature, "options: Partial<Cypress.RequestOptions> = {}"].filter(Boolean).join(", ");
536
- const responseType = resolver.resolveResponseName(node);
525
+ const responseType = resolver.response.response(node);
537
526
  const returnType = `Cypress.Chainable<${responseType}>`;
538
527
  const urlTemplate = Url.toGroupedTemplateString(node.path, { prefix: baseURL });
539
528
  const requestOptions = [`method: '${node.method}'`, `url: ${urlTemplate}`];
@@ -580,25 +569,23 @@ const cypressGenerator = (0, kubb_kit.defineGenerator)({
580
569
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
581
570
  if (!pluginTs) return null;
582
571
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
583
- const importedTypeNames = [tsResolver.resolveRequestConfigName(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })];
572
+ const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })];
584
573
  const meta = {
585
- name: resolver.resolveName(node.operationId),
586
- file: resolver.resolveFile({
574
+ name: resolver.name(node.operationId),
575
+ file: resolver.file({
587
576
  name: node.operationId,
588
577
  extname: ".ts",
589
578
  tag: node.tags[0] ?? "default",
590
- path: node.path
591
- }, {
579
+ path: node.path,
592
580
  root,
593
581
  output,
594
582
  group: group ?? void 0
595
583
  }),
596
- fileTs: tsResolver.resolveFile({
584
+ fileTs: tsResolver.file({
597
585
  name: node.operationId,
598
586
  extname: ".ts",
599
587
  tag: node.tags[0] ?? "default",
600
- path: node.path
601
- }, {
588
+ path: node.path,
602
589
  root,
603
590
  output: pluginTs.options?.output ?? output,
604
591
  group: pluginTs.options?.group ?? void 0
@@ -608,7 +595,7 @@ const cypressGenerator = (0, kubb_kit.defineGenerator)({
608
595
  baseName: meta.file.baseName,
609
596
  path: meta.file.path,
610
597
  meta: meta.file.meta,
611
- banner: resolver.resolveBanner(ctx.meta, {
598
+ banner: resolver.default.banner(ctx.meta, {
612
599
  output,
613
600
  config,
614
601
  file: {
@@ -616,7 +603,7 @@ const cypressGenerator = (0, kubb_kit.defineGenerator)({
616
603
  baseName: meta.file.baseName
617
604
  }
618
605
  }),
619
- footer: resolver.resolveFooter(ctx.meta, {
606
+ footer: resolver.default.footer(ctx.meta, {
620
607
  output,
621
608
  config,
622
609
  file: {
@@ -624,7 +611,7 @@ const cypressGenerator = (0, kubb_kit.defineGenerator)({
624
611
  baseName: meta.file.baseName
625
612
  }
626
613
  }),
627
- children: [meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
614
+ children: [importedTypeNames.length > 0 && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
628
615
  name: importedTypeNames,
629
616
  root: meta.file.path,
630
617
  path: meta.fileTs.path,
@@ -649,22 +636,10 @@ const cypressGenerator = (0, kubb_kit.defineGenerator)({
649
636
  * ```ts
650
637
  * import { resolverCypress } from '@kubb/plugin-cypress'
651
638
  *
652
- * resolverCypress.default('list pets', 'function') // 'listPets'
639
+ * resolverCypress.name('list pets') // 'listPets'
653
640
  * ```
654
641
  */
655
- const resolverCypress = (0, kubb_kit.defineResolver)(() => ({
656
- name: "default",
657
- pluginName: "plugin-cypress",
658
- default(name, type) {
659
- return type === "file" ? toFilePath(name) : camelCase(name);
660
- },
661
- resolveName(name) {
662
- return this.default(name, "function");
663
- },
664
- resolvePathName(name, type) {
665
- return this.default(name, type);
666
- }
667
- }));
642
+ const resolverCypress = (0, kubb_kit.createResolver)({ pluginName: "plugin-cypress" });
668
643
  //#endregion
669
644
  //#region src/plugin.ts
670
645
  /**
@@ -706,10 +681,7 @@ const pluginCypress = (0, kubb_kit.definePlugin)((options) => {
706
681
  options,
707
682
  dependencies: [_kubb_plugin_ts.pluginTsName],
708
683
  hooks: { "kubb:plugin:setup"(ctx) {
709
- const resolver = userResolver ? {
710
- ...resolverCypress,
711
- ...userResolver
712
- } : resolverCypress;
684
+ const resolver = userResolver ? kubb_kit.Resolver.merge(resolverCypress, userResolver) : resolverCypress;
713
685
  ctx.setOptions({
714
686
  output,
715
687
  exclude,
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["ast","File","Function","jsxRenderer","ast","pluginTsName","File","pluginTsName"],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/fs.ts","../../../internals/utils/src/reserved.ts","../../../internals/utils/src/url.ts","../../../internals/shared/src/params.ts","../../../internals/shared/src/operation.ts","../../../internals/shared/src/group.ts","../src/components/Request.tsx","../src/generators/cypressGenerator.tsx","../src/resolvers/resolverCypress.ts","../src/plugin.ts"],"sourcesContent":["type Options = {\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n return text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n .split(/[\\s\\-_./\\\\:]+/)\n .filter(Boolean)\n .map((word, i) => {\n if (word.length > 1 && word === word.toUpperCase()) return word\n const head = i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()\n return head + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Converts `text` to camelCase.\n *\n * @example Word boundaries\n * `camelCase('hello-world') // 'helloWorld'`\n *\n * @example With a prefix\n * `camelCase('tag', { prefix: 'create' }) // 'createTag'`\n */\nexport function camelCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n *\n * @example Word boundaries\n * `pascalCase('hello-world') // 'HelloWorld'`\n *\n * @example With a suffix\n * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`\n */\nexport function pascalCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n\n/**\n * Converts `text` to snake_case.\n *\n * @example From camelCase\n * `snakeCase('helloWorld') // 'hello_world'`\n *\n * @example From mixed separators\n * `snakeCase('Hello-World') // 'hello_world'`\n */\nexport function snakeCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n const processed = `${prefix} ${text} ${suffix}`.trim()\n return processed\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s\\-.]+/g, '_')\n .replace(/[^a-zA-Z0-9_]/g, '')\n .toLowerCase()\n .split('_')\n .filter(Boolean)\n .join('_')\n}\n\n/**\n * Converts `text` to SCREAMING_SNAKE_CASE.\n *\n * @example From camelCase\n * `screamingSnakeCase('helloWorld') // 'HELLO_WORLD'`\n */\nexport function screamingSnakeCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return snakeCase(text, { prefix, suffix }).toUpperCase()\n}\n","import { posix } from 'node:path'\nimport { camelCase } from './casing.ts'\n\nfunction toSlash(p: string): string {\n if (p.startsWith('\\\\\\\\?\\\\')) return p\n return p.replaceAll('\\\\', '/')\n}\n\n/**\n * Returns the relative path from `rootDir` to `filePath`, always using forward slashes\n * and prefixed with `./` when not already traversing upward.\n *\n * @example\n * ```ts\n * getRelativePath('/src/components', '/src/components/Button.tsx') // './Button.tsx'\n * getRelativePath('/src/components', '/src/utils/helpers.ts') // '../utils/helpers.ts'\n * ```\n */\nexport function getRelativePath(rootDir?: string | null, filePath?: string | null): string {\n if (!rootDir || !filePath) {\n throw new Error(`Root and file should be filled in when retrieving the relativePath, ${rootDir || ''} ${filePath || ''}`)\n }\n\n const relativePath = posix.relative(toSlash(rootDir), toSlash(filePath))\n\n return relativePath.startsWith('../') ? relativePath : `./${relativePath}`\n}\n\n/**\n * Builds a nested file path from a dotted name. Splits on dots that precede a letter\n * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases\n * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.\n *\n * Empty segments are dropped before joining. They arise when the name starts with a dot\n * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to\n * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an\n * absolute path, letting generated files escape the configured output directory.\n *\n * @example Nested path from a dotted name\n * `toFilePath('pet.petId') // 'pet/petId'`\n *\n * @example PascalCase the final segment\n * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`\n *\n * @example Suffix applied to the final segment only\n * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`\n */\nexport function toFilePath(name: string, caseLast: (part: string) => string = camelCase): string {\n const parts = name.split(/\\.(?=[a-zA-Z])/)\n return parts\n .map((part, i) => (i === parts.length - 1 ? caseLast(part) : camelCase(part)))\n .filter(Boolean)\n .join('/')\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n\n/**\n * Returns `name` when it's a syntactically valid JavaScript variable name,\n * otherwise prefixes it with `_` so the result is a valid identifier.\n *\n * Useful for sanitizing OpenAPI schema names or operation IDs that start with\n * a digit (e.g. `409`, `504AccountCancel`) before using them as exported\n * variable, type, or function names.\n *\n * @example\n * ```ts\n * ensureValidVarName('409') // '_409'\n * ensureValidVarName('504AccountCancel') // '_504AccountCancel'\n * ensureValidVarName('Pet') // 'Pet'\n * ensureValidVarName('class') // '_class'\n * ```\n */\nexport function ensureValidVarName(name: string): string {\n if (!name || isValidVarName(name)) {\n return name\n }\n return `_${name}`\n}\n","import { camelCase } from './casing.ts'\nimport { isValidVarName } from './reserved.ts'\n\nexport type URLObject = {\n /**\n * The resolved URL string (Express-style or template literal, depending on context).\n */\n url: string\n /**\n * Extracted path parameters as a key-value map, or `null` when the path has none.\n */\n params: Record<string, string> | null\n}\n\n/**\n * Supported identifier casing strategies for path parameters.\n */\nexport type PathCasing = 'camelcase'\n\ntype TemplateOptions = {\n /**\n * Literal text prepended inside the template literal, e.g. a base URL.\n */\n prefix?: string | null\n /**\n * Transform applied to each extracted parameter name before interpolation.\n */\n replacer?: (pathParam: string) => string\n /**\n * Casing strategy applied to path parameter names.\n */\n casing?: PathCasing\n}\n\ntype ObjectOptions = {\n /**\n * Controls whether the `url` is rendered as an Express path or a template literal.\n * @default 'path'\n */\n type?: 'path' | 'template'\n /**\n * Transform applied to each extracted parameter name.\n */\n replacer?: (pathParam: string) => string\n /**\n * When `true`, the result is serialized to a string expression instead of a plain object.\n */\n stringify?: boolean\n /**\n * Casing strategy applied to path parameter names.\n */\n casing?: PathCasing\n}\n\nfunction transformParam(raw: string, casing?: PathCasing): string {\n const param = isValidVarName(raw) ? raw : camelCase(raw)\n return casing === 'camelcase' ? camelCase(param) : param\n}\n\nfunction toParamsObject(\n path: string,\n { replacer, casing }: { replacer?: (pathParam: string) => string; casing?: PathCasing } = {},\n): Record<string, string> | null {\n const params: Record<string, string> = {}\n\n for (const match of path.matchAll(/\\{([^}]+)\\}/g)) {\n const param = transformParam(match[1]!, casing)\n const key = replacer ? replacer(param) : param\n params[key] = key\n }\n\n return Object.keys(params).length > 0 ? params : null\n}\n\n/**\n * Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.\n */\nexport class Url {\n /**\n * Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.\n *\n * @example\n * Url.canParse('https://petstore.swagger.io/v2') // true\n * Url.canParse('/pet/{petId}') // false\n */\n static canParse(url: string, base?: string | URL): boolean {\n return URL.canParse(url, base)\n }\n\n /**\n * Converts an OpenAPI/Swagger path to Express-style colon syntax.\n *\n * @example\n * Url.toPath('/pet/{petId}') // '/pet/:petId'\n */\n static toPath(path: string): string {\n return path.replace(/\\{([^}]+)\\}/g, ':$1')\n }\n\n /**\n * Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`\n * literal aligns with the grouped `path` request option that the runtime client interpolates by\n * key.\n *\n * @example\n * Url.toCasedTemplate('/projects/{project_id}', { casing: 'camelcase' }) // '/projects/{projectId}'\n */\n static toCasedTemplate(path: string, { casing }: { casing?: PathCasing } = {}): string {\n return path.replace(/\\{([^}]+)\\}/g, (_, name: string) => `{${transformParam(name, casing)}}`)\n }\n\n /**\n * Converts an OpenAPI/Swagger path to a TypeScript template literal string.\n * `prefix` is prepended inside the literal, `replacer` transforms each parameter name,\n * and `casing` controls parameter identifier casing.\n *\n * @example\n * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'\n *\n * @example\n * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'\n */\n static toTemplateString(path: string, { prefix, replacer, casing }: TemplateOptions = {}): string {\n const parts = path.split(/\\{([^}]+)\\}/)\n const result = parts\n .map((part, i) => {\n if (i % 2 === 0) return part\n const param = transformParam(part, casing)\n return `\\${${replacer ? replacer(param) : param}}`\n })\n .join('')\n\n return `\\`${prefix ?? ''}${result}\\``\n }\n\n /**\n * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the\n * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter\n * names are camelCased to match the generated `path` type, and `prefix` is prepended inside the\n * literal. Shared by the client and cypress generators that pass a grouped `path` object.\n *\n * @example\n * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'\n */\n static toGroupedTemplateString(path: string, { prefix }: { prefix?: string | null } = {}): string {\n return Url.toTemplateString(path, { prefix, casing: 'camelcase', replacer: (name) => `path.${name}` })\n }\n\n /**\n * Returns the path and its extracted params as a structured `URLObject`, or as a stringified\n * expression when `stringify` is set.\n *\n * @example\n * Url.toObject('/pet/{petId}')\n * // { url: '/pet/:petId', params: { petId: 'petId' } }\n */\n static toObject(path: string, { type = 'path', replacer, stringify, casing }: ObjectOptions = {}): URLObject | string {\n const object: URLObject = {\n url: type === 'path' ? Url.toPath(path) : Url.toTemplateString(path, { replacer, casing }),\n params: toParamsObject(path, { replacer, casing }),\n }\n\n if (stringify) {\n if (type === 'template') {\n return JSON.stringify(object).replaceAll(\"'\", '').replaceAll(`\"`, '')\n }\n\n if (object.params) {\n return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll(\"'\", '').replaceAll(`\"`, '')} }`\n }\n\n return `{ url: '${object.url}' }`\n }\n\n return object\n }\n}\n","import { camelCase, isValidVarName } from '@internals/utils'\nimport type { ast } from 'kubb/kit'\n\nconst caseParamsCache = new WeakMap<Array<ast.ParameterNode>, Array<ast.ParameterNode>>()\n\n/**\n * Applies camelCase to parameter names and returns a new array without mutating the input.\n *\n * Run it before handing parameters to schema builders so output property keys get the right casing\n * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the\n * original array is returned unchanged. Results are cached per input array.\n */\nexport function caseParams(params: Array<ast.ParameterNode>, casing: 'camelcase' | undefined): Array<ast.ParameterNode> {\n if (!casing) return params\n\n const cached = caseParamsCache.get(params)\n if (cached) return cached\n\n const result = params.map((param) => ({ ...param, name: camelCase(param.name) }))\n caseParamsCache.set(params, result)\n return result\n}\n\n/**\n * Drops parameters that collapse to the same property identity once camelCased, keeping the first.\n *\n * Some specs declare the same parameter twice under different casings (for example AWS S3 lists both\n * `max-uploads` and `MaxUploads`). Both resolve to one output property, so emitting both would yield\n * an object type with a duplicate member, which TypeScript rejects. De-duplicate by the camelCased\n * identity so the resulting group is collision-free regardless of the names each caller carries.\n */\nexport function dedupeByCasedName(params: Array<ast.ParameterNode>): Array<ast.ParameterNode> {\n const seen = new Set<string>()\n\n return params.filter((param) => {\n const key = camelCase(param.name)\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\nexport function buildParamsMapping<TParam extends { name: string }>(\n originalParams: ReadonlyArray<TParam>,\n mappedParams: ReadonlyArray<TParam>,\n): Record<string, string> | null {\n const mapping: Record<string, string> = {}\n let hasChanged = false\n\n originalParams.forEach((param, i) => {\n const mappedName = mappedParams[i]?.name ?? param.name\n mapping[param.name] = mappedName\n\n if (param.name !== mappedName) {\n hasChanged = true\n }\n })\n\n return hasChanged ? mapping : null\n}\n\nexport function buildTransformedParamsMapping<TParam extends { name: string }>(\n params: ReadonlyArray<TParam>,\n transformName: (name: string) => string,\n): Record<string, string> | null {\n if (!params.length) {\n return null\n }\n\n return buildParamsMapping(\n params,\n params.map((param) => ({ ...param, name: transformName(param.name) })),\n )\n}\n\nfunction toAccess(object: string, name: string): string {\n return isValidVarName(name) ? `${object}.${name}` : `${object}[${JSON.stringify(name)}]`\n}\n\n/**\n * Renders the object-literal expression that renames the camelCased keys of a grouped request\n * option back to the names the OpenAPI document declares, guarded so an omitted optional group\n * stays omitted. Shared by the client and cypress generators, which pass a `buildParamsMapping`\n * result and the source expression to read the keys from.\n *\n * @example\n * ```ts\n * buildParamsRemapExpression({ source: 'config.query', mapping: { include_deleted: 'includeDeleted' } })\n * // 'config.query ? { \"include_deleted\": config.query.includeDeleted } : config.query'\n * ```\n */\nexport function buildParamsRemapExpression({ source, mapping }: { source: string; mapping: Record<string, string> }): string {\n const pairs = Object.entries(mapping)\n .map(([originalName, casedName]) => `${JSON.stringify(originalName)}: ${toAccess(source, casedName)}`)\n .join(', ')\n\n return `${source} ? { ${pairs} } : ${source}`\n}\n","import { Url } from '@internals/utils'\nimport { ast, type ResolverFileParams } from 'kubb/kit'\nimport { caseParams, dedupeByCasedName } from './params.ts'\n\n/**\n * Builds the `ResolverFileParams` every operation generator passes to\n * `resolver.resolveFile`: a file named `name`, tagged by the operation's first\n * tag (or `'default'`), at the operation's path. Centralizes the entry object\n * that was repeated at dozens of call sites across the client and query plugins.\n *\n * @example\n * ```ts\n * resolver.resolveFile(operationFileEntry(node, node.operationId), { root, output, group })\n * ```\n */\nexport function operationFileEntry(node: ast.OperationNode, name: string, extname: ResolverFileParams['extname'] = '.ts'): ResolverFileParams {\n return {\n name,\n extname,\n tag: node.tags[0] ?? 'default',\n path: node.path,\n }\n}\n\nexport type ContentTypeInfo = {\n contentTypes: string[]\n isMultipleContentTypes: boolean\n contentTypeUnion: string\n defaultContentType: string\n hasFormData: boolean\n}\n\nexport type RequestConfigResolver = {\n resolveDataName(node: ast.OperationNode): string\n}\n\nexport type ResponseStatusNameResolver = {\n resolveResponseStatusName(node: ast.OperationNode, statusCode: ast.StatusCode): string\n}\n\nexport type ResponseNameResolver = ResponseStatusNameResolver & {\n resolveResponseName(node: ast.OperationNode): string\n}\n\nexport type OperationTypeNameResolver = RequestConfigResolver &\n ResponseNameResolver & {\n resolvePathParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n resolveQueryParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n resolveHeaderParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n }\n\n/**\n * Resolver interface for building operation parameters.\n *\n * `ResolverTs` from `@kubb/plugin-ts` satisfies this interface and can be passed directly.\n */\nexport type OperationParamsResolver = {\n /**\n * Resolves the type name for an individual parameter.\n *\n * @example Individual path parameter name\n * `resolver.resolveParamName(node, param) // → 'DeletePetPathPetId'`\n */\n resolveParamName(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the request body type name.\n *\n * @example Request body type name\n * `resolver.resolveDataName(node) // → 'CreatePetData'`\n */\n resolveDataName(node: ast.OperationNode): string\n /**\n * Resolves the grouped path parameters type name.\n * When the return value equals `resolveParamName`, no indexed access is emitted.\n *\n * @example Grouped path params type name\n * `resolver.resolvePathParamsName(node, param) // → 'DeletePetPathParams'`\n */\n resolvePathParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the grouped query parameters type name.\n * When the return value equals `resolveParamName`, an inline struct type is emitted instead.\n *\n * @example Grouped query params type name\n * `resolver.resolveQueryParamsName(node, param) // → 'FindPetsByStatusQueryParams'`\n */\n resolveQueryParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the grouped header parameters type name.\n * When the return value equals `resolveParamName`, an inline struct type is emitted instead.\n *\n * @example Grouped header params type name\n * `resolver.resolveHeaderParamsName(node, param) // → 'DeletePetHeaderParams'`\n */\n resolveHeaderParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n}\n\nexport type OperationCommentLink = 'pathTemplate' | 'urlPath' | false | ((node: ast.OperationNode) => string | undefined)\n\nexport type BuildOperationCommentsOptions = {\n link?: OperationCommentLink\n linkPosition?: 'beforeDeprecated' | 'afterDeprecated'\n splitLines?: boolean\n}\n\ntype ResponseLike = {\n statusCode: ast.StatusCode | number | string\n}\n\nexport type OperationParameterGroups = Record<ast.ParameterNode['in'], Array<ast.ParameterNode>>\n\nexport type ResolveOperationTypeNameOptions = {\n paramsCasing?: 'camelcase' | 'original'\n responseStatusNames?: boolean | 'error'\n exclude?: ReadonlyArray<string | undefined>\n order?: 'params-first' | 'body-response-first'\n /**\n * Include the individual `PathParams`/`QueryParams`/`HeaderParams` type names. Set to `false`\n * for clients that reference the grouped `RequestConfig` type instead of the per-group types.\n */\n includeParams?: boolean\n}\n\nfunction getOperationLink(node: ast.OperationNode, link: OperationCommentLink): string | null {\n if (!link) {\n return null\n }\n\n if (typeof link === 'function') {\n return link(node) ?? null\n }\n\n if (link === 'urlPath') {\n return node.path ? `{@link ${Url.toPath(node.path)}}` : null\n }\n\n return node.path ? `{@link ${node.path.replaceAll('{', ':').replaceAll('}', '')}}` : null\n}\n\nexport function getContentTypeInfo(node: ast.OperationNode): ContentTypeInfo {\n const contentTypes = node.requestBody?.content?.map((e) => e.contentType) ?? []\n const isMultipleContentTypes = contentTypes.length > 1\n\n return {\n contentTypes,\n isMultipleContentTypes,\n contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(' | ') : '',\n defaultContentType: contentTypes[0] ?? 'application/json',\n hasFormData: contentTypes.some((ct) => ct === 'multipart/form-data'),\n }\n}\n\n/**\n * The request-body counterpart for the primary success response: the content types it documents and\n * whether several are present, so the client can let a caller pick which one to accept.\n */\nexport function getResponseContentTypeInfo(node: ast.OperationNode): ContentTypeInfo {\n const contentTypes = getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? []\n const isMultipleContentTypes = contentTypes.length > 1\n\n return {\n contentTypes,\n isMultipleContentTypes,\n contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(' | ') : '',\n defaultContentType: contentTypes[0] ?? 'application/json',\n hasFormData: contentTypes.some((ct) => ct === 'multipart/form-data'),\n }\n}\n\nexport type ResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n\n/**\n * Reads the single base content type of an operation's primary success response, lowercased and\n * stripped of any `; charset=...` suffix. Returns `undefined` when the response declares zero or\n * more than one content type, since neither case has a single type to act on.\n */\nfunction getPrimarySuccessContentType(node: ast.OperationNode): string | undefined {\n const contentTypes = getPrimarySuccessResponse(node)?.content?.map((entry) => entry.contentType) ?? []\n if (contentTypes.length !== 1) return undefined\n return contentTypes[0]!.split(';')[0]!.trim().toLowerCase()\n}\n\n/**\n * Whether an operation streams its primary success response as Server-Sent Events\n * (`text/event-stream`). The client generator uses this to return a typed event stream instead of a\n * one-shot `RequestResult`.\n */\nexport function isEventStream(node: ast.OperationNode): boolean {\n return getPrimarySuccessContentType(node) === 'text/event-stream'\n}\n\n/**\n * Derives the default `responseType` for an operation from its primary success response.\n *\n * Returns a value only when that response declares a single non-JSON content type. `text/event-stream`\n * and other binary types (`application/octet-stream`, `application/pdf`, `image/*`, `audio/*`,\n * `video/*`) map to a stream or `'blob'`, and other `text/*` maps to `'text'`. Otherwise `undefined`,\n * leaving the runtime client's `Content-Type` auto-detection in charge.\n */\nexport function getResponseType(node: ast.OperationNode): ResponseType | undefined {\n const baseType = getPrimarySuccessContentType(node)\n if (!baseType) return undefined\n\n if (baseType === 'application/json' || baseType.endsWith('+json') || baseType === 'text/json') return undefined\n if (baseType === 'text/event-stream') return 'stream'\n if (baseType.startsWith('text/')) return 'text'\n if (baseType === 'application/octet-stream' || baseType === 'application/pdf' || /^(image|audio|video)\\//.test(baseType)) return 'blob'\n return undefined\n}\n\n/**\n * Maps a content type to the PascalCase suffix used to name per-content-type variants\n * (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).\n */\nfunction getContentTypeSuffix(contentType: string): string {\n const baseType = contentType.split(';')[0]!.trim()\n if (baseType === 'application/json') return 'Json'\n if (baseType === 'multipart/form-data') return 'FormData'\n if (baseType === 'application/x-www-form-urlencoded') return 'FormUrlEncoded'\n const subtype = baseType.split('/').pop() ?? baseType\n const parts = subtype.split(/[^a-zA-Z0-9]+/).filter(Boolean)\n if (parts.length === 0) return 'Unknown'\n return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('')\n}\n\n/**\n * Appends a content-type suffix to a base name, keeping a trailing `Data` segment last\n * (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).\n */\nexport function getPerContentTypeName(baseName: string, suffix: string): string {\n if (baseName.endsWith('Data')) {\n return suffix.endsWith('Data') ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`\n }\n return baseName + suffix\n}\n\nexport type ContentVariantInput = { contentType: string; schema?: ast.SchemaNode | null; keysToOmit?: Array<string> | null }\nexport type ContentVariant = { name: string; suffix: string; schema: ast.SchemaNode; keysToOmit?: Array<string> | null; contentType: string }\n\n/**\n * Resolves per-content-type variant names for a set of content entries, deduplicating suffix\n * collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is\n * the final (possibly counter-augmented) value, so callers can derive parallel names in another\n * namespace (e.g. plugin-faker deriving the matching plugin-ts type name).\n */\nexport function resolveContentTypeVariants(entries: Array<ContentVariantInput>, baseName: string): Array<ContentVariant> {\n const usedNames = new Set<string>()\n return entries\n .filter((entry) => entry.schema)\n .map((entry) => {\n const baseSuffix = getContentTypeSuffix(entry.contentType)\n let suffix = baseSuffix\n let name = getPerContentTypeName(baseName, suffix)\n let counter = 2\n while (usedNames.has(name)) {\n suffix = `${baseSuffix}${counter++}`\n name = getPerContentTypeName(baseName, suffix)\n }\n usedNames.add(name)\n return { name, suffix, schema: entry.schema!, keysToOmit: entry.keysToOmit, contentType: entry.contentType }\n })\n}\n\nexport function buildRequestConfigType(node: ast.OperationNode): string {\n const request = getContentTypeInfo(node)\n const response = getResponseContentTypeInfo(node)\n // The request groups come from the grouped params, so `config` drops the data-shape keys to stay\n // assignable to `Options`, which omits them from `RequestConfig`.\n const configType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n\n // Only the ambiguous side is offered: a single-type side has nothing to pick, so it stays baked in\n // the generated call.\n const members = [\n request.isMultipleContentTypes ? `request?: ${request.contentTypeUnion}` : null,\n response.isMultipleContentTypes ? `response?: ${response.contentTypeUnion}` : null,\n ].filter(Boolean)\n\n return members.length ? `${configType} & { contentType?: { ${members.join('; ')} } }` : configType\n}\n\n/**\n * Builds the `client?:` option type shared by the generated query hooks (`useQuery`,\n * `useInfiniteQuery`, `useSWR`, ...). Unlike {@link buildRequestConfigType}, it never adds a\n * `contentType?:` member: query hooks wrap GET operations, which carry no request body to select a\n * content type for.\n */\nexport function buildClientOptionType(): string {\n return `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n}\n\nexport type RequestGroups = {\n path: boolean\n query: boolean\n body: boolean\n headers: boolean\n}\n\n/**\n * Which of the grouped request options an operation carries.\n */\nexport function getRequestGroups(node: ast.OperationNode): RequestGroups {\n const { path, query, header } = getOperationParameters(node)\n return {\n path: path.length > 0,\n query: query.length > 0,\n body: Boolean(node.requestBody?.content?.[0]?.schema),\n headers: header.length > 0,\n }\n}\n\nexport type RequestGroupOptionality = {\n groups: RequestGroups\n hasRequiredPath: boolean\n hasRequiredQuery: boolean\n hasRequiredHeader: boolean\n /**\n * Whether the grouped request parameter can default to `{}`. True only when no group carries a\n * required member, so every member is safe to omit.\n */\n isOptional: boolean\n}\n\n/**\n * Resolves which grouped request options an operation carries together with whether each group\n * holds a required member. The grouped parameter stays optional only when nothing inside it is\n * required, matching the generated `RequestConfig` type.\n */\nexport function getRequestGroupOptionality(node: ast.OperationNode): RequestGroupOptionality {\n const groups = getRequestGroups(node)\n const { path, query, header } = getOperationParameters(node)\n const hasRequiredPath = path.some((param) => param.required)\n const hasRequiredQuery = query.some((param) => param.required)\n const hasRequiredHeader = header.some((param) => param.required)\n\n return {\n groups,\n hasRequiredPath,\n hasRequiredQuery,\n hasRequiredHeader,\n isOptional: !hasRequiredPath && !hasRequiredQuery && !hasRequiredHeader && !groups.body,\n }\n}\n\nexport type RequestConfigNameResolver = RequestConfigResolver & {\n resolveRequestConfigName(node: ast.OperationNode): string\n}\n\n/**\n * Builds the grouped `{ path, query, body, headers }` parameter for a generated client\n * function, typed from the operation's `RequestConfig` (minus `url`). Only the groups the\n * operation actually has are destructured. The trailing `config` parameter carries the\n * runtime `RequestConfig` overrides plus `client`.\n */\nexport function buildRequestParamsSignature(\n node: ast.OperationNode,\n resolver: RequestConfigNameResolver,\n options: { isConfigurable?: boolean } = {},\n): { signature: string; groups: RequestGroups } {\n const { isConfigurable = true } = options\n const { groups, isOptional } = getRequestGroupOptionality(node)\n\n const names = (['path', 'query', 'body', 'headers'] as const).filter((key) => groups[key])\n\n const firstParam = names.length > 0 ? `{ ${names.join(', ')} }: ${resolver.resolveRequestConfigName(node)}${isOptional ? ' = {}' : ''}` : null\n const configParam = isConfigurable ? `config: ${buildRequestConfigType(node)} = {}` : null\n\n return {\n signature: [firstParam, configParam].filter(Boolean).join(', '),\n groups,\n }\n}\n\nexport function buildOperationComments(node: ast.OperationNode, options: BuildOperationCommentsOptions = {}): Array<string> {\n const { link = 'pathTemplate', linkPosition = 'afterDeprecated', splitLines = false } = options\n const linkComment = getOperationLink(node, link)\n const comments =\n linkPosition === 'beforeDeprecated'\n ? [node.description && `@description ${node.description}`, node.summary && `@summary ${node.summary}`, linkComment, node.deprecated && '@deprecated']\n : [node.description && `@description ${node.description}`, node.summary && `@summary ${node.summary}`, node.deprecated && '@deprecated', linkComment]\n\n const filteredComments = comments.filter((comment): comment is string => Boolean(comment))\n\n if (!splitLines) {\n return filteredComments\n }\n\n return filteredComments.flatMap((text) => text.split(/\\r?\\n/).map((line) => line.trim())).filter((comment): comment is string => Boolean(comment))\n}\n\nexport function getOperationParameters(node: ast.OperationNode, options: { paramsCasing?: 'camelcase' | 'original' } = {}): OperationParameterGroups {\n const params = caseParams(node.parameters, options.paramsCasing === 'original' ? undefined : 'camelcase')\n\n return {\n path: dedupeByCasedName(params.filter((param) => param.in === 'path')),\n query: dedupeByCasedName(params.filter((param) => param.in === 'query')),\n header: dedupeByCasedName(params.filter((param) => param.in === 'header')),\n cookie: dedupeByCasedName(params.filter((param) => param.in === 'cookie')),\n }\n}\n\nexport function getStatusCodeNumber(statusCode: ast.StatusCode | number | string): number | null {\n const code = Number(statusCode)\n\n return Number.isNaN(code) ? null : code\n}\n\nexport function isSuccessStatusCode(statusCode: ast.StatusCode | number | string): boolean {\n const code = getStatusCodeNumber(statusCode)\n\n return code !== null && code >= 200 && code < 300\n}\n\nexport function isErrorStatusCode(statusCode: ast.StatusCode | number | string): boolean {\n const code = getStatusCodeNumber(statusCode)\n\n return code !== null && code >= 400\n}\n\nexport function getSuccessResponses<TResponse extends ResponseLike>(responses: ReadonlyArray<TResponse>): Array<TResponse> {\n return responses.filter((response) => isSuccessStatusCode(response.statusCode))\n}\n\nexport function getOperationSuccessResponses(node: ast.OperationNode): Array<ast.ResponseNode> {\n return getSuccessResponses(node.responses)\n}\n\nexport function getPrimarySuccessResponse(node: ast.OperationNode): ast.ResponseNode | null {\n return getOperationSuccessResponses(node)[0] ?? null\n}\n\nexport function resolveErrorNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses\n .filter((response) => isErrorStatusCode(response.statusCode))\n .map((response) => resolver.resolveResponseStatusName(node, response.statusCode))\n}\n\nexport function resolveSuccessNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses\n .filter((response) => isSuccessStatusCode(response.statusCode))\n .map((response) => resolver.resolveResponseStatusName(node, response.statusCode))\n}\n\nexport function resolveStatusCodeNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode))\n}\n\nconst typeNamesByResolver = new WeakMap<OperationTypeNameResolver, Map<string, string[]>>()\n\nexport function resolveOperationTypeNames(\n node: ast.OperationNode,\n resolver: OperationTypeNameResolver,\n options: ResolveOperationTypeNameOptions = {},\n): string[] {\n const cacheKey = `${node.operationId}\\0${options.paramsCasing ?? ''}\\0${options.order ?? ''}\\0${options.responseStatusNames ?? ''}\\0${options.includeParams === false ? 'noparams' : ''}\\0${(options.exclude ?? []).join(',')}`\n let byResolver = typeNamesByResolver.get(resolver)\n if (byResolver) {\n const cached = byResolver.get(cacheKey)\n if (cached) return cached\n } else {\n byResolver = new Map()\n typeNamesByResolver.set(resolver, byResolver)\n }\n\n const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing })\n const responseStatusNames =\n options.responseStatusNames === 'error'\n ? resolveErrorNames(node, resolver)\n : options.responseStatusNames === false\n ? []\n : resolveStatusCodeNames(node, resolver)\n const exclude = new Set(options.exclude ?? [])\n const paramNames =\n options.includeParams === false\n ? []\n : [\n ...path.map((param) => resolver.resolvePathParamsName(node, param)),\n ...query.map((param) => resolver.resolveQueryParamsName(node, param)),\n ...header.map((param) => resolver.resolveHeaderParamsName(node, param)),\n ]\n const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null, resolver.resolveResponseName(node)]\n const names =\n options.order === 'body-response-first'\n ? [...bodyAndResponseNames, ...paramNames, ...responseStatusNames]\n : [...paramNames, ...bodyAndResponseNames, ...responseStatusNames]\n\n const result = names.filter((name): name is string => Boolean(name) && !exclude.has(name as string))\n byResolver.set(cacheKey, result)\n return result\n}\n\nexport function resolveResponseTypes(node: ast.OperationNode, resolver: ResponseNameResolver): Array<[statusCode: number | 'default', typeName: string]> {\n const types: Array<[number | 'default', string]> = []\n\n for (const response of node.responses) {\n if (response.statusCode === 'default') {\n types.push(['default', resolver.resolveResponseName(node)])\n continue\n }\n\n const code = getStatusCodeNumber(response.statusCode)\n if (code === null) {\n continue\n }\n\n types.push([code, isSuccessStatusCode(code) ? resolver.resolveResponseName(node) : resolver.resolveResponseStatusName(node, response.statusCode)])\n }\n\n return types\n}\n\nexport function findSuccessStatusCode(responses: Array<{ statusCode: ast.StatusCode | number | string }>): ast.StatusCode | null {\n for (const response of responses) {\n if (isSuccessStatusCode(response.statusCode)) {\n return response.statusCode as ast.StatusCode\n }\n }\n\n return null\n}\n","import { camelCase } from '@internals/utils'\nimport type { Group } from 'kubb/kit'\n\n/**\n * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the\n * shared default naming so every plugin groups output consistently:\n *\n * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).\n * - other groups use the camelCased group (`pet store` → `petStore`).\n *\n * A user-provided `group.name` always wins over the default namer, so callers stay in\n * control of their output folders. Returns `null` when grouping is disabled, matching the\n * per-plugin convention.\n *\n * @param group - The user-supplied group option, or `undefined` to disable grouping.\n *\n * @example\n * ```ts\n * createGroupConfig(group) // shared across every plugin\n * ```\n */\nexport function createGroupConfig(group: Group | undefined): Group | null {\n if (!group) {\n return null\n }\n\n const defaultName = (ctx: { group: string }): string => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n\n return camelCase(ctx.group)\n }\n\n return {\n ...group,\n name: group.name ? group.name : defaultName,\n } satisfies Group\n}\n","import { buildParamsMapping, buildParamsRemapExpression, buildRequestParamsSignature, getOperationParameters } from '@internals/shared'\nimport { Url } from '@internals/utils'\nimport { ast } from 'kubb/kit'\nimport type { ResolverTs } from '@kubb/plugin-ts'\nimport { File, Function } from 'kubb/jsx'\nimport type { KubbReactNode } from 'kubb/jsx'\n\ntype Props = {\n /**\n * Name of the function\n */\n name: string\n /**\n * AST operation node\n */\n node: ast.OperationNode\n /**\n * TypeScript resolver for resolving param/data/response type names\n */\n resolver: ResolverTs\n baseURL: string | null | undefined\n}\n\nexport function Request({ baseURL = '', name, resolver, node }: Props): KubbReactNode {\n if (!ast.isHttpOperationNode(node)) return null\n\n const { query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node, { paramsCasing: 'original' })\n const { query: casedQueryParams, header: casedHeaderParams } = getOperationParameters(node)\n\n const queryParamsMapping = buildParamsMapping(originalQueryParams, casedQueryParams)\n const headerParamsMapping = buildParamsMapping(originalHeaderParams, casedHeaderParams)\n\n const { signature, groups } = buildRequestParamsSignature(node, resolver, { isConfigurable: false })\n const paramsSignature = [signature, 'options: Partial<Cypress.RequestOptions> = {}'].filter(Boolean).join(', ')\n\n const responseType = resolver.resolveResponseName(node)\n const returnType = `Cypress.Chainable<${responseType}>`\n\n // Reference the path object straight in the URL with camelCase placeholders.\n const urlTemplate = Url.toGroupedTemplateString(node.path, { prefix: baseURL })\n\n const requestOptions: Array<string> = [`method: '${node.method}'`, `url: ${urlTemplate}`]\n\n if (groups.query) {\n requestOptions.push(queryParamsMapping ? `qs: ${buildParamsRemapExpression({ source: 'query', mapping: queryParamsMapping })}` : 'qs: query')\n }\n\n if (groups.headers) {\n requestOptions.push(headerParamsMapping ? `headers: ${buildParamsRemapExpression({ source: 'headers', mapping: headerParamsMapping })}` : 'headers')\n }\n\n if (groups.body) {\n requestOptions.push('body')\n }\n\n requestOptions.push('...options')\n\n const requestCall = `return cy.request<${responseType}>({\n ${requestOptions.join(',\\n ')}\n}).then((res) => res.body)`\n\n return (\n <File.Source name={name} isIndexable isExportable>\n <Function name={name} export params={paramsSignature} returnType={returnType}>\n {requestCall}\n </Function>\n </File.Source>\n )\n}\n","import { resolveOperationTypeNames } from '@internals/shared'\nimport { ast, defineGenerator } from 'kubb/kit'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { File, jsxRenderer } from 'kubb/jsx'\nimport { Request } from '../components/Request.tsx'\nimport type { PluginCypress } from '../types.ts'\n\n/**\n * Built-in generator for `@kubb/plugin-cypress`. Emits one typed\n * `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress\n * test specs and custom commands.\n */\nexport const cypressGenerator = defineGenerator<PluginCypress>({\n name: 'cypress',\n renderer: jsxRenderer,\n operation(node, ctx) {\n if (!ast.isHttpOperationNode(node)) return null\n const { config, resolver, driver, root } = ctx\n const { output, baseURL, group } = ctx.options\n\n const pluginTs = driver.getPlugin(pluginTsName)\n\n if (!pluginTs) {\n return null\n }\n\n const tsResolver = driver.getResolver(pluginTsName)\n\n const importedTypeNames = [tsResolver.resolveRequestConfigName(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })]\n\n const meta = {\n name: resolver.resolveName(node.operationId),\n file: resolver.resolveFile(\n { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },\n { root, output, group: group ?? undefined },\n ),\n fileTs: tsResolver.resolveFile(\n { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },\n {\n root,\n output: pluginTs.options?.output ?? output,\n group: pluginTs.options?.group ?? undefined,\n },\n ),\n } as const\n\n return (\n <File\n baseName={meta.file.baseName}\n path={meta.file.path}\n meta={meta.file.meta}\n banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n >\n {meta.fileTs && importedTypeNames.length > 0 && <File.Import name={importedTypeNames} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />}\n <Request name={meta.name} node={node} resolver={tsResolver} baseURL={baseURL} />\n </File>\n )\n },\n})\n","import { camelCase, toFilePath } from '@internals/utils'\nimport { defineResolver } from 'kubb/kit'\nimport type { PluginCypress } from '../types.ts'\n\n/**\n * Default resolver used by `@kubb/plugin-cypress`. Decides the names and file\n * paths for every generated `cy.request()` wrapper. Functions and files use\n * camelCase, matching the convention from `@kubb/plugin-axios` and `@kubb/plugin-fetch`.\n *\n * @example Resolve a helper name\n * ```ts\n * import { resolverCypress } from '@kubb/plugin-cypress'\n *\n * resolverCypress.default('list pets', 'function') // 'listPets'\n * ```\n */\nexport const resolverCypress = defineResolver<PluginCypress>(() => ({\n name: 'default',\n pluginName: 'plugin-cypress',\n default(name, type) {\n return type === 'file' ? toFilePath(name) : camelCase(name)\n },\n resolveName(name) {\n return this.default(name, 'function')\n },\n resolvePathName(name, type) {\n return this.default(name, type)\n },\n}))\n","import { createGroupConfig } from '@internals/shared'\nimport { definePlugin } from 'kubb/kit'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { cypressGenerator } from './generators/cypressGenerator.tsx'\nimport { resolverCypress } from './resolvers/resolverCypress.ts'\nimport type { PluginCypress } from './types.ts'\n\n/**\n * Canonical plugin name for `@kubb/plugin-cypress`. Used for driver lookups and\n * cross-plugin dependency references.\n */\nexport const pluginCypressName = 'plugin-cypress' satisfies PluginCypress['name']\n\n/**\n * Generates one typed `cy.request()` wrapper per OpenAPI operation. Each helper\n * has typed path params, body, query, and a typed response, so failing API\n * calls in Cypress show up at compile time instead of inside the test runner.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb/config'\n * import { pluginTs } from '@kubb/plugin-ts'\n * import { pluginCypress } from '@kubb/plugin-cypress'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * plugins: [\n * pluginTs(),\n * pluginCypress({\n * output: { path: './cypress' },\n * }),\n * ],\n * })\n * ```\n */\nexport const pluginCypress = definePlugin<PluginCypress>((options) => {\n const {\n output = { path: 'cypress', barrel: { type: 'named' } },\n group,\n exclude = [],\n include,\n override = [],\n baseURL,\n resolver: userResolver,\n macros: userMacros,\n } = options\n\n const groupConfig = createGroupConfig(group)\n\n return {\n name: pluginCypressName,\n options,\n dependencies: [pluginTsName],\n hooks: {\n 'kubb:plugin:setup'(ctx) {\n const resolver = userResolver ? { ...resolverCypress, ...userResolver } : resolverCypress\n\n ctx.setOptions({\n output,\n exclude,\n include,\n override,\n group: groupConfig,\n baseURL,\n resolver,\n })\n ctx.setResolver(resolver)\n if (userMacros?.length) {\n ctx.setMacros(userMacros)\n }\n ctx.addGenerator(cypressGenerator)\n },\n },\n }\n})\n\nexport default pluginCypress\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["ast","File","Function","jsxRenderer","ast","pluginTsName","File","pluginTsName","Resolver"],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/reserved.ts","../../../internals/utils/src/url.ts","../../../internals/shared/src/params.ts","../../../internals/shared/src/operation.ts","../../../internals/shared/src/group.ts","../src/components/Request.tsx","../src/generators/cypressGenerator.tsx","../src/resolvers/resolverCypress.ts","../src/plugin.ts"],"sourcesContent":["type Options = {\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n return text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n .split(/[\\s\\-_./\\\\:]+/)\n .filter(Boolean)\n .map((word, i) => {\n if (word.length > 1 && word === word.toUpperCase()) return word\n const head = i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()\n return head + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Converts `text` to camelCase.\n *\n * @example Word boundaries\n * `camelCase('hello-world') // 'helloWorld'`\n *\n * @example With a prefix\n * `camelCase('tag', { prefix: 'create' }) // 'createTag'`\n */\nexport function camelCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n *\n * @example Word boundaries\n * `pascalCase('hello-world') // 'HelloWorld'`\n *\n * @example With a suffix\n * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`\n */\nexport function pascalCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n\n/**\n * Converts `text` to snake_case.\n *\n * @example From camelCase\n * `snakeCase('helloWorld') // 'hello_world'`\n *\n * @example From mixed separators\n * `snakeCase('Hello-World') // 'hello_world'`\n */\nexport function snakeCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n const processed = `${prefix} ${text} ${suffix}`.trim()\n return processed\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s\\-.]+/g, '_')\n .replace(/[^a-zA-Z0-9_]/g, '')\n .toLowerCase()\n .split('_')\n .filter(Boolean)\n .join('_')\n}\n\n/**\n * Converts `text` to SCREAMING_SNAKE_CASE.\n *\n * @example From camelCase\n * `screamingSnakeCase('helloWorld') // 'HELLO_WORLD'`\n */\nexport function screamingSnakeCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return snakeCase(text, { prefix, suffix }).toUpperCase()\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return isIdentifier(name)\n}\n\n/**\n * Returns `name` when it's a syntactically valid JavaScript variable name,\n * otherwise prefixes it with `_` so the result is a valid identifier.\n *\n * Useful for sanitizing OpenAPI schema names or operation IDs that start with\n * a digit (e.g. `409`, `504AccountCancel`) before using them as exported\n * variable, type, or function names.\n *\n * @example\n * ```ts\n * ensureValidVarName('409') // '_409'\n * ensureValidVarName('504AccountCancel') // '_504AccountCancel'\n * ensureValidVarName('Pet') // 'Pet'\n * ensureValidVarName('class') // '_class'\n * ```\n */\nexport function ensureValidVarName(name: string): string {\n if (!name || isValidVarName(name)) {\n return name\n }\n return `_${name}`\n}\n\n/**\n * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.\n *\n * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys\n * even though they are not valid variable names, so use this (not {@link isValidVarName}) when\n * deciding whether an object key needs quoting.\n *\n * @example\n * ```ts\n * isIdentifier('name') // true\n * isIdentifier('x-total')// false\n * ```\n */\nexport function isIdentifier(name: string): boolean {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n","import { camelCase } from './casing.ts'\nimport { isValidVarName } from './reserved.ts'\n\nexport type URLObject = {\n /**\n * The resolved URL string (Express-style or template literal, depending on context).\n */\n url: string\n /**\n * Extracted path parameters as a key-value map, or `null` when the path has none.\n */\n params: Record<string, string> | null\n}\n\n/**\n * Supported identifier casing strategies for path parameters.\n */\nexport type PathCasing = 'camelcase'\n\ntype TemplateOptions = {\n /**\n * Literal text prepended inside the template literal, e.g. a base URL.\n */\n prefix?: string | null\n /**\n * Transform applied to each extracted parameter name before interpolation.\n */\n replacer?: (pathParam: string) => string\n /**\n * Casing strategy applied to path parameter names.\n */\n casing?: PathCasing\n}\n\ntype ObjectOptions = {\n /**\n * Controls whether the `url` is rendered as an Express path or a template literal.\n * @default 'path'\n */\n type?: 'path' | 'template'\n /**\n * Transform applied to each extracted parameter name.\n */\n replacer?: (pathParam: string) => string\n /**\n * When `true`, the result is serialized to a string expression instead of a plain object.\n */\n stringify?: boolean\n /**\n * Casing strategy applied to path parameter names.\n */\n casing?: PathCasing\n}\n\nfunction transformParam(raw: string, casing?: PathCasing): string {\n const param = isValidVarName(raw) ? raw : camelCase(raw)\n return casing === 'camelcase' ? camelCase(param) : param\n}\n\nfunction toParamsObject(\n path: string,\n { replacer, casing }: { replacer?: (pathParam: string) => string; casing?: PathCasing } = {},\n): Record<string, string> | null {\n const params: Record<string, string> = {}\n\n for (const match of path.matchAll(/\\{([^}]+)\\}/g)) {\n const param = transformParam(match[1]!, casing)\n const key = replacer ? replacer(param) : param\n params[key] = key\n }\n\n return Object.keys(params).length > 0 ? params : null\n}\n\n/**\n * Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.\n */\nexport class Url {\n /**\n * Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.\n *\n * @example\n * Url.canParse('https://petstore.swagger.io/v2') // true\n * Url.canParse('/pet/{petId}') // false\n */\n static canParse(url: string, base?: string | URL): boolean {\n return URL.canParse(url, base)\n }\n\n /**\n * Converts an OpenAPI/Swagger path to Express-style colon syntax.\n *\n * @example\n * Url.toPath('/pet/{petId}') // '/pet/:petId'\n */\n static toPath(path: string): string {\n return path.replace(/\\{([^}]+)\\}/g, ':$1')\n }\n\n /**\n * Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`\n * literal aligns with the grouped `path` request option that the runtime client interpolates by\n * key.\n *\n * @example\n * Url.toCasedTemplate('/projects/{project_id}', { casing: 'camelcase' }) // '/projects/{projectId}'\n */\n static toCasedTemplate(path: string, { casing }: { casing?: PathCasing } = {}): string {\n return path.replace(/\\{([^}]+)\\}/g, (_, name: string) => `{${transformParam(name, casing)}}`)\n }\n\n /**\n * Converts an OpenAPI/Swagger path to a TypeScript template literal string.\n * `prefix` is prepended inside the literal, `replacer` transforms each parameter name,\n * and `casing` controls parameter identifier casing.\n *\n * @example\n * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'\n *\n * @example\n * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'\n */\n static toTemplateString(path: string, { prefix, replacer, casing }: TemplateOptions = {}): string {\n const parts = path.split(/\\{([^}]+)\\}/)\n const result = parts\n .map((part, i) => {\n if (i % 2 === 0) return part\n const param = transformParam(part, casing)\n return `\\${${replacer ? replacer(param) : param}}`\n })\n .join('')\n\n return `\\`${prefix ?? ''}${result}\\``\n }\n\n /**\n * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the\n * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter\n * names are camelCased to match the generated `path` type, and `prefix` is prepended inside the\n * literal. Shared by the client and cypress generators that pass a grouped `path` object.\n *\n * @example\n * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'\n */\n static toGroupedTemplateString(path: string, { prefix }: { prefix?: string | null } = {}): string {\n return Url.toTemplateString(path, { prefix, casing: 'camelcase', replacer: (name) => `path.${name}` })\n }\n\n /**\n * Returns the path and its extracted params as a structured `URLObject`, or as a stringified\n * expression when `stringify` is set.\n *\n * @example\n * Url.toObject('/pet/{petId}')\n * // { url: '/pet/:petId', params: { petId: 'petId' } }\n */\n static toObject(path: string, { type = 'path', replacer, stringify, casing }: ObjectOptions = {}): URLObject | string {\n const object: URLObject = {\n url: type === 'path' ? Url.toPath(path) : Url.toTemplateString(path, { replacer, casing }),\n params: toParamsObject(path, { replacer, casing }),\n }\n\n if (stringify) {\n if (type === 'template') {\n return JSON.stringify(object).replaceAll(\"'\", '').replaceAll(`\"`, '')\n }\n\n if (object.params) {\n return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll(\"'\", '').replaceAll(`\"`, '')} }`\n }\n\n return `{ url: '${object.url}' }`\n }\n\n return object\n }\n}\n","import { camelCase, isValidVarName } from '@internals/utils'\nimport type { ast } from 'kubb/kit'\n\nconst caseParamsCache = new WeakMap<Array<ast.ParameterNode>, Array<ast.ParameterNode>>()\n\n/**\n * Applies camelCase to parameter names and returns a new array without mutating the input.\n *\n * Run it before handing parameters to schema builders so output property keys get the right casing\n * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the\n * original array is returned unchanged. Results are cached per input array.\n */\nexport function caseParams(params: Array<ast.ParameterNode>, casing: 'camelcase' | undefined): Array<ast.ParameterNode> {\n if (!casing) return params\n\n const cached = caseParamsCache.get(params)\n if (cached) return cached\n\n const result = params.map((param) => ({ ...param, name: camelCase(param.name) }))\n caseParamsCache.set(params, result)\n return result\n}\n\n/**\n * Drops parameters that collapse to the same property identity once camelCased, keeping the first.\n *\n * Some specs declare the same parameter twice under different casings (for example AWS S3 lists both\n * `max-uploads` and `MaxUploads`). Both resolve to one output property, so emitting both would yield\n * an object type with a duplicate member, which TypeScript rejects. De-duplicate by the camelCased\n * identity so the resulting group is collision-free regardless of the names each caller carries.\n */\nexport function dedupeByCasedName(params: Array<ast.ParameterNode>): Array<ast.ParameterNode> {\n const seen = new Set<string>()\n\n return params.filter((param) => {\n const key = camelCase(param.name)\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\nexport function buildParamsMapping<TParam extends { name: string }>(\n originalParams: ReadonlyArray<TParam>,\n mappedParams: ReadonlyArray<TParam>,\n): Record<string, string> | null {\n const mapping: Record<string, string> = {}\n let hasChanged = false\n\n originalParams.forEach((param, i) => {\n const mappedName = mappedParams[i]?.name ?? param.name\n mapping[param.name] = mappedName\n\n if (param.name !== mappedName) {\n hasChanged = true\n }\n })\n\n return hasChanged ? mapping : null\n}\n\nexport function buildTransformedParamsMapping<TParam extends { name: string }>(\n params: ReadonlyArray<TParam>,\n transformName: (name: string) => string,\n): Record<string, string> | null {\n if (!params.length) {\n return null\n }\n\n return buildParamsMapping(\n params,\n params.map((param) => ({ ...param, name: transformName(param.name) })),\n )\n}\n\nfunction toAccess(object: string, name: string): string {\n return isValidVarName(name) ? `${object}.${name}` : `${object}[${JSON.stringify(name)}]`\n}\n\n/**\n * Renders the object-literal expression that renames the camelCased keys of a grouped request\n * option back to the names the OpenAPI document declares, guarded so an omitted optional group\n * stays omitted. Shared by the client and cypress generators, which pass a `buildParamsMapping`\n * result and the source expression to read the keys from.\n *\n * @example\n * ```ts\n * buildParamsRemapExpression({ source: 'config.query', mapping: { include_deleted: 'includeDeleted' } })\n * // 'config.query ? { \"include_deleted\": config.query.includeDeleted } : config.query'\n * ```\n */\nexport function buildParamsRemapExpression({ source, mapping }: { source: string; mapping: Record<string, string> }): string {\n const pairs = Object.entries(mapping)\n .map(([originalName, casedName]) => `${JSON.stringify(originalName)}: ${toAccess(source, casedName)}`)\n .join(', ')\n\n return `${source} ? { ${pairs} } : ${source}`\n}\n","import { Url } from '@internals/utils'\nimport { ast, type ResolverFileParams } from 'kubb/kit'\nimport { caseParams, dedupeByCasedName } from './params.ts'\n\n/**\n * Builds the `ResolverFileParams` every operation generator passes to\n * `resolver.file`: a file named `name`, tagged by the operation's first\n * tag (or `'default'`), at the operation's path. Centralizes the entry object\n * that was repeated at dozens of call sites across the client and query plugins.\n *\n * @example\n * ```ts\n * resolver.file(operationFileEntry(node, node.operationId), { root, output, group })\n * ```\n */\nexport function operationFileEntry(node: ast.OperationNode, name: string, extname: ResolverFileParams['extname'] = '.ts'): ResolverFileParams {\n return {\n name,\n extname,\n tag: node.tags[0] ?? 'default',\n path: node.path,\n }\n}\n\nexport type ContentTypeInfo = {\n contentTypes: string[]\n isMultipleContentTypes: boolean\n contentTypeUnion: string\n defaultContentType: string\n hasFormData: boolean\n}\n\nexport type RequestConfigResolver = {\n response: {\n body(node: ast.OperationNode): string\n }\n}\n\nexport type ResponseStatusNameResolver = {\n response: {\n status(node: ast.OperationNode, statusCode: ast.StatusCode): string\n }\n}\n\nexport type ResponseNameResolver = ResponseStatusNameResolver & {\n response: {\n response(node: ast.OperationNode): string\n }\n}\n\nexport type OperationTypeNameResolver = RequestConfigResolver &\n ResponseNameResolver & {\n param: {\n path(node: ast.OperationNode, param: ast.ParameterNode): string\n query(node: ast.OperationNode, param: ast.ParameterNode): string\n headers(node: ast.OperationNode, param: ast.ParameterNode): string\n }\n }\n\n/**\n * Resolver interface for building operation parameters.\n *\n * `ResolverTs` from `@kubb/plugin-ts` satisfies this interface and can be passed directly.\n */\nexport type OperationParamsResolver = {\n /**\n * Naming for an operation's parameters, grouped by location.\n */\n param: {\n /**\n * Resolves the type name for an individual parameter.\n *\n * @example Individual path parameter name\n * `resolver.param.name(node, param) // → 'DeletePetPathPetId'`\n */\n name(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the grouped path parameters type name.\n * When the return value equals `resolver.param.name`, no indexed access is emitted.\n *\n * @example Grouped path params type name\n * `resolver.param.path(node, param) // → 'DeletePetPath'`\n */\n path(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the grouped query parameters type name.\n * When the return value equals `resolver.param.name`, an inline struct type is emitted instead.\n *\n * @example Grouped query params type name\n * `resolver.param.query(node, param) // → 'FindPetsByStatusQuery'`\n */\n query(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the grouped header parameters type name.\n * When the return value equals `resolver.param.name`, an inline struct type is emitted instead.\n *\n * @example Grouped header params type name\n * `resolver.param.headers(node, param) // → 'DeletePetHeaders'`\n */\n headers(node: ast.OperationNode, param: ast.ParameterNode): string\n }\n /**\n * Naming for an operation's request and response types.\n */\n response: {\n /**\n * Resolves the request body type name.\n *\n * @example Request body type name\n * `resolver.response.body(node) // → 'CreatePetBody'`\n */\n body(node: ast.OperationNode): string\n }\n}\n\nexport type OperationCommentLink = 'pathTemplate' | 'urlPath' | false | ((node: ast.OperationNode) => string | undefined)\n\nexport type BuildOperationCommentsOptions = {\n link?: OperationCommentLink\n linkPosition?: 'beforeDeprecated' | 'afterDeprecated'\n splitLines?: boolean\n}\n\ntype ResponseLike = {\n statusCode: ast.StatusCode | number | string\n}\n\nexport type OperationParameterGroups = Record<ast.ParameterNode['in'], Array<ast.ParameterNode>>\n\nexport type ResolveOperationTypeNameOptions = {\n paramsCasing?: 'camelcase' | 'original'\n responseStatusNames?: boolean | 'error'\n exclude?: ReadonlyArray<string | undefined>\n order?: 'params-first' | 'body-response-first'\n /**\n * Include the individual `Path`/`Query`/`Headers` group type names. Set to `false` for clients\n * that reference the grouped `Options` type instead of the per-group types.\n */\n includeParams?: boolean\n}\n\nfunction getOperationLink(node: ast.OperationNode, link: OperationCommentLink): string | null {\n if (!link) {\n return null\n }\n\n if (typeof link === 'function') {\n return link(node) ?? null\n }\n\n if (link === 'urlPath') {\n return node.path ? `{@link ${Url.toPath(node.path)}}` : null\n }\n\n return node.path ? `{@link ${node.path.replaceAll('{', ':').replaceAll('}', '')}}` : null\n}\n\n/**\n * Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several\n * are present and the union, default, and form-data flags the client uses to pick one.\n */\nfunction buildContentTypeInfo(contentTypes: string[]): ContentTypeInfo {\n const isMultipleContentTypes = contentTypes.length > 1\n\n return {\n contentTypes,\n isMultipleContentTypes,\n contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(' | ') : '',\n defaultContentType: contentTypes[0] ?? 'application/json',\n hasFormData: contentTypes.some((ct) => ct === 'multipart/form-data'),\n }\n}\n\nexport function getContentTypeInfo(node: ast.OperationNode): ContentTypeInfo {\n return buildContentTypeInfo(node.requestBody?.content?.map((e) => e.contentType) ?? [])\n}\n\n/**\n * The request-body counterpart for the primary success response: the content types it documents and\n * whether several are present, so the client can let a caller pick which one to accept.\n */\nexport function getResponseContentTypeInfo(node: ast.OperationNode): ContentTypeInfo {\n return buildContentTypeInfo(getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? [])\n}\n\nexport type ResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n\n/**\n * Reads the single base content type of an operation's primary success response, lowercased and\n * stripped of any `; charset=...` suffix. Returns `undefined` when the response declares zero or\n * more than one content type, since neither case has a single type to act on.\n */\nfunction getPrimarySuccessContentType(node: ast.OperationNode): string | undefined {\n const contentTypes = getPrimarySuccessResponse(node)?.content?.map((entry) => entry.contentType) ?? []\n if (contentTypes.length !== 1) return undefined\n return contentTypes[0]!.split(';')[0]!.trim().toLowerCase()\n}\n\n/**\n * Whether an operation streams its primary success response as Server-Sent Events\n * (`text/event-stream`). The client generator uses this to return a typed event stream instead of a\n * one-shot `RequestResult`.\n */\nexport function isEventStream(node: ast.OperationNode): boolean {\n return getPrimarySuccessContentType(node) === 'text/event-stream'\n}\n\n/**\n * Derives the default `responseType` for an operation from its primary success response.\n *\n * Returns a value only when that response declares a single non-JSON content type. `text/event-stream`\n * and other binary types (`application/octet-stream`, `application/pdf`, `image/*`, `audio/*`,\n * `video/*`) map to a stream or `'blob'`, and other `text/*` maps to `'text'`. Otherwise `undefined`,\n * leaving the runtime client's `Content-Type` auto-detection in charge.\n */\nexport function getResponseType(node: ast.OperationNode): ResponseType | undefined {\n const baseType = getPrimarySuccessContentType(node)\n if (!baseType) return undefined\n\n if (baseType === 'application/json' || baseType.endsWith('+json') || baseType === 'text/json') return undefined\n if (baseType === 'text/event-stream') return 'stream'\n if (baseType.startsWith('text/')) return 'text'\n if (baseType === 'application/octet-stream' || baseType === 'application/pdf' || /^(image|audio|video)\\//.test(baseType)) return 'blob'\n return undefined\n}\n\n/**\n * Maps a content type to the PascalCase suffix used to name per-content-type variants\n * (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).\n */\nfunction getContentTypeSuffix(contentType: string): string {\n const baseType = contentType.split(';')[0]!.trim()\n if (baseType === 'application/json') return 'Json'\n if (baseType === 'multipart/form-data') return 'FormData'\n if (baseType === 'application/x-www-form-urlencoded') return 'FormUrlEncoded'\n const subtype = baseType.split('/').pop() ?? baseType\n const parts = subtype.split(/[^a-zA-Z0-9]+/).filter(Boolean)\n if (parts.length === 0) return 'Unknown'\n return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('')\n}\n\n/**\n * Appends a content-type suffix to a base name, keeping a trailing `Data` segment last\n * (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).\n */\nexport function getPerContentTypeName(baseName: string, suffix: string): string {\n if (baseName.endsWith('Data')) {\n return suffix.endsWith('Data') ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`\n }\n return baseName + suffix\n}\n\nexport type ContentVariantInput = { contentType: string; schema?: ast.SchemaNode | null; keysToOmit?: Array<string> | null }\nexport type ContentVariant = { name: string; suffix: string; schema: ast.SchemaNode; keysToOmit?: Array<string> | null; contentType: string }\n\n/**\n * Resolves per-content-type variant names for a set of content entries, deduplicating suffix\n * collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is\n * the final (possibly counter-augmented) value, so callers can derive parallel names in another\n * namespace (e.g. plugin-faker deriving the matching plugin-ts type name).\n */\nexport function resolveContentTypeVariants(entries: Array<ContentVariantInput>, baseName: string): Array<ContentVariant> {\n const usedNames = new Set<string>()\n return entries\n .filter((entry) => entry.schema)\n .map((entry) => {\n const baseSuffix = getContentTypeSuffix(entry.contentType)\n let suffix = baseSuffix\n let name = getPerContentTypeName(baseName, suffix)\n let counter = 2\n while (usedNames.has(name)) {\n suffix = `${baseSuffix}${counter++}`\n name = getPerContentTypeName(baseName, suffix)\n }\n usedNames.add(name)\n return { name, suffix, schema: entry.schema!, keysToOmit: entry.keysToOmit, contentType: entry.contentType }\n })\n}\n\nexport function buildRequestConfigType(node: ast.OperationNode): string {\n const request = getContentTypeInfo(node)\n const response = getResponseContentTypeInfo(node)\n // The request groups come from the grouped params, so `config` drops the data-shape keys to stay\n // assignable to `Options`, which omits them from `RequestConfig`.\n const configType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n\n // Only the ambiguous side is offered: a single-type side has nothing to pick, so it stays baked in\n // the generated call.\n const members = [\n request.isMultipleContentTypes ? `request?: ${request.contentTypeUnion}` : null,\n response.isMultipleContentTypes ? `response?: ${response.contentTypeUnion}` : null,\n ].filter(Boolean)\n\n return members.length ? `${configType} & { contentType?: { ${members.join('; ')} } }` : configType\n}\n\n/**\n * Builds the `client?:` option type shared by the generated query hooks (`useQuery`,\n * `useInfiniteQuery`, `useSWR`, ...). Unlike {@link buildRequestConfigType}, it never adds a\n * `contentType?:` member: query hooks wrap GET operations, which carry no request body to select a\n * content type for.\n */\nexport function buildClientOptionType(): string {\n return `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n}\n\nexport type RequestGroups = {\n path: boolean\n query: boolean\n body: boolean\n headers: boolean\n}\n\n/**\n * Which of the grouped request options an operation carries.\n */\nexport function getRequestGroups(node: ast.OperationNode): RequestGroups {\n const { path, query, header } = getOperationParameters(node)\n return {\n path: path.length > 0,\n query: query.length > 0,\n body: Boolean(node.requestBody?.content?.[0]?.schema),\n headers: header.length > 0,\n }\n}\n\nexport type RequestGroupOptionality = {\n groups: RequestGroups\n hasRequiredPath: boolean\n hasRequiredQuery: boolean\n hasRequiredHeader: boolean\n /**\n * Whether the grouped request parameter can default to `{}`. True only when no group carries a\n * required member, so every member is safe to omit.\n */\n isOptional: boolean\n}\n\n/**\n * Resolves which grouped request options an operation carries together with whether each group\n * holds a required member. The grouped parameter stays optional only when nothing inside it is\n * required, matching the generated `RequestConfig` type.\n */\nexport function getRequestGroupOptionality(node: ast.OperationNode): RequestGroupOptionality {\n const groups = getRequestGroups(node)\n const { path, query, header } = getOperationParameters(node)\n const hasRequiredPath = path.some((param) => param.required)\n const hasRequiredQuery = query.some((param) => param.required)\n const hasRequiredHeader = header.some((param) => param.required)\n\n return {\n groups,\n hasRequiredPath,\n hasRequiredQuery,\n hasRequiredHeader,\n isOptional: !hasRequiredPath && !hasRequiredQuery && !hasRequiredHeader && !groups.body,\n }\n}\n\nexport type RequestOptionsNameResolver = RequestConfigResolver & {\n response: {\n options(node: ast.OperationNode): string\n }\n}\n\n/**\n * Builds the grouped `{ path, query, body, headers }` parameter for a generated client\n * function, typed from the operation's `Options` (minus `url`). Only the groups the\n * operation actually has are destructured. The trailing `config` parameter carries the\n * runtime `RequestConfig` overrides plus `client`.\n */\nexport function buildRequestParamsSignature(\n node: ast.OperationNode,\n resolver: RequestOptionsNameResolver,\n options: { isConfigurable?: boolean } = {},\n): { signature: string; groups: RequestGroups } {\n const { isConfigurable = true } = options\n const { groups, isOptional } = getRequestGroupOptionality(node)\n\n const names = (['path', 'query', 'body', 'headers'] as const).filter((key) => groups[key])\n\n const firstParam = names.length > 0 ? `{ ${names.join(', ')} }: ${resolver.response.options(node)}${isOptional ? ' = {}' : ''}` : null\n const configParam = isConfigurable ? `config: ${buildRequestConfigType(node)} = {}` : null\n\n return {\n signature: [firstParam, configParam].filter(Boolean).join(', '),\n groups,\n }\n}\n\nexport function buildOperationComments(node: ast.OperationNode, options: BuildOperationCommentsOptions = {}): Array<string> {\n const { link = 'pathTemplate', linkPosition = 'afterDeprecated', splitLines = false } = options\n const linkComment = getOperationLink(node, link)\n const comments =\n linkPosition === 'beforeDeprecated'\n ? [node.description && `@description ${node.description}`, node.summary && `@summary ${node.summary}`, linkComment, node.deprecated && '@deprecated']\n : [node.description && `@description ${node.description}`, node.summary && `@summary ${node.summary}`, node.deprecated && '@deprecated', linkComment]\n\n const filteredComments = comments.filter((comment): comment is string => Boolean(comment))\n\n if (!splitLines) {\n return filteredComments\n }\n\n return filteredComments.flatMap((text) => text.split(/\\r?\\n/).map((line) => line.trim())).filter((comment): comment is string => Boolean(comment))\n}\n\nexport function getOperationParameters(node: ast.OperationNode, options: { paramsCasing?: 'camelcase' | 'original' } = {}): OperationParameterGroups {\n const params = caseParams(node.parameters, options.paramsCasing === 'original' ? undefined : 'camelcase')\n\n return {\n path: dedupeByCasedName(params.filter((param) => param.in === 'path')),\n query: dedupeByCasedName(params.filter((param) => param.in === 'query')),\n header: dedupeByCasedName(params.filter((param) => param.in === 'header')),\n cookie: dedupeByCasedName(params.filter((param) => param.in === 'cookie')),\n }\n}\n\nexport function getStatusCodeNumber(statusCode: ast.StatusCode | number | string): number | null {\n const code = Number(statusCode)\n\n return Number.isNaN(code) ? null : code\n}\n\nexport function isSuccessStatusCode(statusCode: ast.StatusCode | number | string): boolean {\n const code = getStatusCodeNumber(statusCode)\n\n return code !== null && code >= 200 && code < 300\n}\n\nexport function isErrorStatusCode(statusCode: ast.StatusCode | number | string): boolean {\n const code = getStatusCodeNumber(statusCode)\n\n return code !== null && code >= 400\n}\n\nexport function getSuccessResponses<TResponse extends ResponseLike>(responses: ReadonlyArray<TResponse>): Array<TResponse> {\n return responses.filter((response) => isSuccessStatusCode(response.statusCode))\n}\n\nexport function getOperationSuccessResponses(node: ast.OperationNode): Array<ast.ResponseNode> {\n return getSuccessResponses(node.responses)\n}\n\nexport function getPrimarySuccessResponse(node: ast.OperationNode): ast.ResponseNode | null {\n return getOperationSuccessResponses(node)[0] ?? null\n}\n\nexport function resolveErrorNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.response.status(node, response.statusCode))\n}\n\nexport function resolveSuccessNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses.filter((response) => isSuccessStatusCode(response.statusCode)).map((response) => resolver.response.status(node, response.statusCode))\n}\n\nexport function resolveStatusCodeNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses.map((response) => resolver.response.status(node, response.statusCode))\n}\n\nconst typeNamesByResolver = new WeakMap<OperationTypeNameResolver, Map<string, string[]>>()\n\nexport function resolveOperationTypeNames(\n node: ast.OperationNode,\n resolver: OperationTypeNameResolver,\n options: ResolveOperationTypeNameOptions = {},\n): string[] {\n const cacheKey = `${node.operationId}\\0${options.paramsCasing ?? ''}\\0${options.order ?? ''}\\0${options.responseStatusNames ?? ''}\\0${options.includeParams === false ? 'noparams' : ''}\\0${(options.exclude ?? []).join(',')}`\n let byResolver = typeNamesByResolver.get(resolver)\n if (byResolver) {\n const cached = byResolver.get(cacheKey)\n if (cached) return cached\n } else {\n byResolver = new Map()\n typeNamesByResolver.set(resolver, byResolver)\n }\n\n const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing })\n const responseStatusNames =\n options.responseStatusNames === 'error'\n ? resolveErrorNames(node, resolver)\n : options.responseStatusNames === false\n ? []\n : resolveStatusCodeNames(node, resolver)\n const exclude = new Set(options.exclude ?? [])\n const paramNames =\n options.includeParams === false\n ? []\n : [\n ...path.map((param) => resolver.param.path(node, param)),\n ...query.map((param) => resolver.param.query(node, param)),\n ...header.map((param) => resolver.param.headers(node, param)),\n ]\n const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.response.body(node) : null, resolver.response.response(node)]\n const names =\n options.order === 'body-response-first'\n ? [...bodyAndResponseNames, ...paramNames, ...responseStatusNames]\n : [...paramNames, ...bodyAndResponseNames, ...responseStatusNames]\n\n const result = names.filter((name): name is string => Boolean(name) && !exclude.has(name as string))\n byResolver.set(cacheKey, result)\n return result\n}\n\nexport function resolveResponseTypes(node: ast.OperationNode, resolver: ResponseNameResolver): Array<[statusCode: number | 'default', typeName: string]> {\n const types: Array<[number | 'default', string]> = []\n\n for (const response of node.responses) {\n if (response.statusCode === 'default') {\n types.push(['default', resolver.response.response(node)])\n continue\n }\n\n const code = getStatusCodeNumber(response.statusCode)\n if (code === null) {\n continue\n }\n\n types.push([code, isSuccessStatusCode(code) ? resolver.response.response(node) : resolver.response.status(node, response.statusCode)])\n }\n\n return types\n}\n\nexport function findSuccessStatusCode(responses: Array<{ statusCode: ast.StatusCode | number | string }>): ast.StatusCode | null {\n for (const response of responses) {\n if (isSuccessStatusCode(response.statusCode)) {\n return response.statusCode as ast.StatusCode\n }\n }\n\n return null\n}\n","import { camelCase } from '@internals/utils'\nimport type { Group } from 'kubb/kit'\n\n/**\n * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the\n * shared default naming so every plugin groups output consistently:\n *\n * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).\n * - other groups use the camelCased group (`pet store` → `petStore`).\n *\n * A user-provided `group.name` always wins over the default namer, so callers stay in\n * control of their output folders. Returns `null` when grouping is disabled, matching the\n * per-plugin convention.\n *\n * @param group - The user-supplied group option, or `undefined` to disable grouping.\n *\n * @example\n * ```ts\n * createGroupConfig(group) // shared across every plugin\n * ```\n */\nexport function createGroupConfig(group: Group | undefined): Group | null {\n if (!group) {\n return null\n }\n\n const defaultName = (ctx: { group: string }): string => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n\n return camelCase(ctx.group)\n }\n\n return {\n ...group,\n name: group.name ? group.name : defaultName,\n } satisfies Group\n}\n","import { buildParamsMapping, buildParamsRemapExpression, buildRequestParamsSignature, getOperationParameters } from '@internals/shared'\nimport { Url } from '@internals/utils'\nimport { ast } from 'kubb/kit'\nimport type { ResolverTs } from '@kubb/plugin-ts'\nimport { File, Function } from 'kubb/jsx'\nimport type { KubbReactNode } from 'kubb/jsx'\n\ntype Props = {\n /**\n * Name of the function\n */\n name: string\n /**\n * AST operation node\n */\n node: ast.OperationNode\n /**\n * TypeScript resolver for resolving param/data/response type names\n */\n resolver: ResolverTs\n baseURL: string | null | undefined\n}\n\nexport function Request({ baseURL = '', name, resolver, node }: Props): KubbReactNode {\n if (!ast.isHttpOperationNode(node)) return null\n\n const { query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node, { paramsCasing: 'original' })\n const { query: casedQueryParams, header: casedHeaderParams } = getOperationParameters(node)\n\n const queryParamsMapping = buildParamsMapping(originalQueryParams, casedQueryParams)\n const headerParamsMapping = buildParamsMapping(originalHeaderParams, casedHeaderParams)\n\n const { signature, groups } = buildRequestParamsSignature(node, resolver, { isConfigurable: false })\n const paramsSignature = [signature, 'options: Partial<Cypress.RequestOptions> = {}'].filter(Boolean).join(', ')\n\n const responseType = resolver.response.response(node)\n const returnType = `Cypress.Chainable<${responseType}>`\n\n // Reference the path object straight in the URL with camelCase placeholders.\n const urlTemplate = Url.toGroupedTemplateString(node.path, { prefix: baseURL })\n\n const requestOptions: Array<string> = [`method: '${node.method}'`, `url: ${urlTemplate}`]\n\n if (groups.query) {\n requestOptions.push(queryParamsMapping ? `qs: ${buildParamsRemapExpression({ source: 'query', mapping: queryParamsMapping })}` : 'qs: query')\n }\n\n if (groups.headers) {\n requestOptions.push(headerParamsMapping ? `headers: ${buildParamsRemapExpression({ source: 'headers', mapping: headerParamsMapping })}` : 'headers')\n }\n\n if (groups.body) {\n requestOptions.push('body')\n }\n\n requestOptions.push('...options')\n\n const requestCall = `return cy.request<${responseType}>({\n ${requestOptions.join(',\\n ')}\n}).then((res) => res.body)`\n\n return (\n <File.Source name={name} isIndexable isExportable>\n <Function name={name} export params={paramsSignature} returnType={returnType}>\n {requestCall}\n </Function>\n </File.Source>\n )\n}\n","import { resolveOperationTypeNames } from '@internals/shared'\nimport { ast, defineGenerator } from 'kubb/kit'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { File, jsxRenderer } from 'kubb/jsx'\nimport { Request } from '../components/Request.tsx'\nimport type { PluginCypress } from '../types.ts'\n\n/**\n * Built-in generator for `@kubb/plugin-cypress`. Emits one typed\n * `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress\n * test specs and custom commands.\n */\nexport const cypressGenerator = defineGenerator<PluginCypress>({\n name: 'cypress',\n renderer: jsxRenderer,\n operation(node, ctx) {\n if (!ast.isHttpOperationNode(node)) return null\n const { config, resolver, driver, root } = ctx\n const { output, baseURL, group } = ctx.options\n\n const pluginTs = driver.getPlugin(pluginTsName)\n\n if (!pluginTs) {\n return null\n }\n\n const tsResolver = driver.getResolver(pluginTsName)\n\n const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })]\n\n const meta = {\n name: resolver.name(node.operationId),\n file: resolver.file({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path, root, output, group: group ?? undefined }),\n fileTs: tsResolver.file({\n name: node.operationId,\n extname: '.ts',\n tag: node.tags[0] ?? 'default',\n path: node.path,\n root,\n output: pluginTs.options?.output ?? output,\n group: pluginTs.options?.group ?? undefined,\n }),\n } as const\n\n return (\n <File\n baseName={meta.file.baseName}\n path={meta.file.path}\n meta={meta.file.meta}\n banner={resolver.default.banner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n footer={resolver.default.footer(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n >\n {importedTypeNames.length > 0 && <File.Import name={importedTypeNames} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />}\n <Request name={meta.name} node={node} resolver={tsResolver} baseURL={baseURL} />\n </File>\n )\n },\n})\n","import { createResolver } from 'kubb/kit'\nimport type { PluginCypress } from '../types.ts'\n\n/**\n * Default resolver used by `@kubb/plugin-cypress`. Decides the names and file\n * paths for every generated `cy.request()` wrapper. Functions and files use\n * camelCase, matching the convention from `@kubb/plugin-axios` and `@kubb/plugin-fetch`.\n *\n * @example Resolve a helper name\n * ```ts\n * import { resolverCypress } from '@kubb/plugin-cypress'\n *\n * resolverCypress.name('list pets') // 'listPets'\n * ```\n */\nexport const resolverCypress = createResolver<PluginCypress>({\n pluginName: 'plugin-cypress',\n})\n","import { createGroupConfig } from '@internals/shared'\nimport { definePlugin, Resolver } from 'kubb/kit'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { cypressGenerator } from './generators/cypressGenerator.tsx'\nimport { resolverCypress } from './resolvers/resolverCypress.ts'\nimport type { PluginCypress, ResolverCypress } from './types.ts'\n\n/**\n * Canonical plugin name for `@kubb/plugin-cypress`. Used for driver lookups and\n * cross-plugin dependency references.\n */\nexport const pluginCypressName = 'plugin-cypress' satisfies PluginCypress['name']\n\n/**\n * Generates one typed `cy.request()` wrapper per OpenAPI operation. Each helper\n * has typed path params, body, query, and a typed response, so failing API\n * calls in Cypress show up at compile time instead of inside the test runner.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb/config'\n * import { pluginTs } from '@kubb/plugin-ts'\n * import { pluginCypress } from '@kubb/plugin-cypress'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * plugins: [\n * pluginTs(),\n * pluginCypress({\n * output: { path: './cypress' },\n * }),\n * ],\n * })\n * ```\n */\nexport const pluginCypress = definePlugin<PluginCypress>((options) => {\n const {\n output = { path: 'cypress', barrel: { type: 'named' } },\n group,\n exclude = [],\n include,\n override = [],\n baseURL,\n resolver: userResolver,\n macros: userMacros,\n } = options\n\n const groupConfig = createGroupConfig(group)\n\n return {\n name: pluginCypressName,\n options,\n dependencies: [pluginTsName],\n hooks: {\n 'kubb:plugin:setup'(ctx) {\n const resolver = userResolver ? Resolver.merge<ResolverCypress>(resolverCypress, userResolver) : resolverCypress\n\n ctx.setOptions({\n output,\n exclude,\n include,\n override,\n group: groupConfig,\n baseURL,\n resolver,\n })\n ctx.setResolver(resolver)\n if (userMacros?.length) {\n ctx.setMacros(userMacros)\n }\n ctx.addGenerator(cypressGenerator)\n },\n },\n }\n})\n\nexport default pluginCypress\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
2
- import { Exclude, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ast } from "kubb/kit";
2
+ import { Exclude, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ResolverPatch, ast } from "kubb/kit";
3
3
  import { KubbReactNode } from "kubb/jsx";
4
4
  import { ResolverTs } from "@kubb/plugin-ts";
5
5
 
@@ -30,19 +30,7 @@ declare function Request({
30
30
  /**
31
31
  * Resolver for Cypress that provides naming methods for test functions.
32
32
  */
33
- type ResolverCypress = Resolver & {
34
- /**
35
- * Resolves the function name for an operation.
36
- *
37
- * @example Resolving function names
38
- * `resolver.resolveName('show pet by id') // -> 'showPetById'`
39
- */
40
- resolveName(this: ResolverCypress, name: string): string;
41
- /**
42
- * Resolves the output file name for a Cypress request module.
43
- */
44
- resolvePathName(this: ResolverCypress, name: string, type?: 'file' | 'function' | 'type' | 'const'): string;
45
- };
33
+ type ResolverCypress = Resolver;
46
34
  /**
47
35
  * Where the generated Cypress helpers are written and how they are exported, plus the optional
48
36
  * `group` strategy. The `group` option organizes `output.mode: 'directory'` output into per-tag or per-path subdirectories.
@@ -70,7 +58,7 @@ type Options = OutputOptions & {
70
58
  /**
71
59
  * Override how helper names and file paths are built.
72
60
  */
73
- resolver?: Partial<ResolverCypress> & ThisType<ResolverCypress>;
61
+ resolver?: ResolverPatch<ResolverCypress>;
74
62
  /**
75
63
  * Macros applied to each operation node before printing.
76
64
  */
@@ -143,10 +131,10 @@ declare const pluginCypress: (options?: Options | undefined) => import("kubb/kit
143
131
  * ```ts
144
132
  * import { resolverCypress } from '@kubb/plugin-cypress'
145
133
  *
146
- * resolverCypress.default('list pets', 'function') // 'listPets'
134
+ * resolverCypress.name('list pets') // 'listPets'
147
135
  * ```
148
136
  */
149
- declare const resolverCypress: ResolverCypress;
137
+ declare const resolverCypress: import("kubb/kit").Resolver;
150
138
  //#endregion
151
139
  export { type PluginCypress, Request, type ResolverCypress, cypressGenerator, pluginCypress as default, pluginCypress, pluginCypressName, resolverCypress };
152
140
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./rolldown-runtime-C0LytTxp.js";
2
- import { ast, defineGenerator, definePlugin, defineResolver } from "kubb/kit";
2
+ import { Resolver, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
3
3
  import { File, Function, jsxRenderer } from "kubb/jsx";
4
4
  import { jsx, jsxs } from "kubb/jsx/jsx-runtime";
5
5
  import { pluginTsName } from "@kubb/plugin-ts";
@@ -30,31 +30,6 @@ function camelCase(text, { prefix = "", suffix = "" } = {}) {
30
30
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
31
31
  }
32
32
  //#endregion
33
- //#region ../../internals/utils/src/fs.ts
34
- /**
35
- * Builds a nested file path from a dotted name. Splits on dots that precede a letter
36
- * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
37
- * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
38
- *
39
- * Empty segments are dropped before joining. They arise when the name starts with a dot
40
- * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
41
- * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
42
- * absolute path, letting generated files escape the configured output directory.
43
- *
44
- * @example Nested path from a dotted name
45
- * `toFilePath('pet.petId') // 'pet/petId'`
46
- *
47
- * @example PascalCase the final segment
48
- * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
49
- *
50
- * @example Suffix applied to the final segment only
51
- * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
52
- */
53
- function toFilePath(name, caseLast = camelCase) {
54
- const parts = name.split(/\.(?=[a-zA-Z])/);
55
- return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
56
- }
57
- //#endregion
58
33
  //#region ../../internals/utils/src/reserved.ts
59
34
  /**
60
35
  * JavaScript and Java reserved words.
@@ -155,6 +130,22 @@ const reservedWords = /* @__PURE__ */ new Set([
155
130
  */
156
131
  function isValidVarName(name) {
157
132
  if (!name || reservedWords.has(name)) return false;
133
+ return isIdentifier(name);
134
+ }
135
+ /**
136
+ * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
137
+ *
138
+ * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
139
+ * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
140
+ * deciding whether an object key needs quoting.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * isIdentifier('name') // true
145
+ * isIdentifier('x-total')// false
146
+ * ```
147
+ */
148
+ function isIdentifier(name) {
158
149
  return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
159
150
  }
160
151
  //#endregion
@@ -336,8 +327,11 @@ function buildParamsRemapExpression({ source, mapping }) {
336
327
  }
337
328
  //#endregion
338
329
  //#region ../../internals/shared/src/operation.ts
339
- function getContentTypeInfo(node) {
340
- const contentTypes = node.requestBody?.content?.map((e) => e.contentType) ?? [];
330
+ /**
331
+ * Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
332
+ * are present and the union, default, and form-data flags the client uses to pick one.
333
+ */
334
+ function buildContentTypeInfo(contentTypes) {
341
335
  const isMultipleContentTypes = contentTypes.length > 1;
342
336
  return {
343
337
  contentTypes,
@@ -347,20 +341,15 @@ function getContentTypeInfo(node) {
347
341
  hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
348
342
  };
349
343
  }
344
+ function getContentTypeInfo(node) {
345
+ return buildContentTypeInfo(node.requestBody?.content?.map((e) => e.contentType) ?? []);
346
+ }
350
347
  /**
351
348
  * The request-body counterpart for the primary success response: the content types it documents and
352
349
  * whether several are present, so the client can let a caller pick which one to accept.
353
350
  */
354
351
  function getResponseContentTypeInfo(node) {
355
- const contentTypes = getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? [];
356
- const isMultipleContentTypes = contentTypes.length > 1;
357
- return {
358
- contentTypes,
359
- isMultipleContentTypes,
360
- contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
361
- defaultContentType: contentTypes[0] ?? "application/json",
362
- hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
363
- };
352
+ return buildContentTypeInfo(getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? []);
364
353
  }
365
354
  function buildRequestConfigType(node) {
366
355
  const request = getContentTypeInfo(node);
@@ -402,7 +391,7 @@ function getRequestGroupOptionality(node) {
402
391
  }
403
392
  /**
404
393
  * Builds the grouped `{ path, query, body, headers }` parameter for a generated client
405
- * function, typed from the operation's `RequestConfig` (minus `url`). Only the groups the
394
+ * function, typed from the operation's `Options` (minus `url`). Only the groups the
406
395
  * operation actually has are destructured. The trailing `config` parameter carries the
407
396
  * runtime `RequestConfig` overrides plus `client`.
408
397
  */
@@ -416,7 +405,7 @@ function buildRequestParamsSignature(node, resolver, options = {}) {
416
405
  "headers"
417
406
  ].filter((key) => groups[key]);
418
407
  return {
419
- signature: [names.length > 0 ? `{ ${names.join(", ")} }: ${resolver.resolveRequestConfigName(node)}${isOptional ? " = {}" : ""}` : null, isConfigurable ? `config: ${buildRequestConfigType(node)} = {}` : null].filter(Boolean).join(", "),
408
+ signature: [names.length > 0 ? `{ ${names.join(", ")} }: ${resolver.response.options(node)}${isOptional ? " = {}" : ""}` : null, isConfigurable ? `config: ${buildRequestConfigType(node)} = {}` : null].filter(Boolean).join(", "),
420
409
  groups
421
410
  };
422
411
  }
@@ -451,10 +440,10 @@ function getPrimarySuccessResponse(node) {
451
440
  return getOperationSuccessResponses(node)[0] ?? null;
452
441
  }
453
442
  function resolveErrorNames(node, resolver) {
454
- return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
443
+ return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.response.status(node, response.statusCode));
455
444
  }
456
445
  function resolveStatusCodeNames(node, resolver) {
457
- return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
446
+ return node.responses.map((response) => resolver.response.status(node, response.statusCode));
458
447
  }
459
448
  const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
460
449
  function resolveOperationTypeNames(node, resolver, options = {}) {
@@ -471,11 +460,11 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
471
460
  const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
472
461
  const exclude = new Set(options.exclude ?? []);
473
462
  const paramNames = options.includeParams === false ? [] : [
474
- ...path.map((param) => resolver.resolvePathParamsName(node, param)),
475
- ...query.map((param) => resolver.resolveQueryParamsName(node, param)),
476
- ...header.map((param) => resolver.resolveHeaderParamsName(node, param))
463
+ ...path.map((param) => resolver.param.path(node, param)),
464
+ ...query.map((param) => resolver.param.query(node, param)),
465
+ ...header.map((param) => resolver.param.headers(node, param))
477
466
  ];
478
- const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null, resolver.resolveResponseName(node)];
467
+ const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.response.body(node) : null, resolver.response.response(node)];
479
468
  const result = (options.order === "body-response-first" ? [
480
469
  ...bodyAndResponseNames,
481
470
  ...paramNames,
@@ -529,7 +518,7 @@ function Request({ baseURL = "", name, resolver, node }) {
529
518
  const headerParamsMapping = buildParamsMapping(originalHeaderParams, casedHeaderParams);
530
519
  const { signature, groups } = buildRequestParamsSignature(node, resolver, { isConfigurable: false });
531
520
  const paramsSignature = [signature, "options: Partial<Cypress.RequestOptions> = {}"].filter(Boolean).join(", ");
532
- const responseType = resolver.resolveResponseName(node);
521
+ const responseType = resolver.response.response(node);
533
522
  const returnType = `Cypress.Chainable<${responseType}>`;
534
523
  const urlTemplate = Url.toGroupedTemplateString(node.path, { prefix: baseURL });
535
524
  const requestOptions = [`method: '${node.method}'`, `url: ${urlTemplate}`];
@@ -576,25 +565,23 @@ const cypressGenerator = defineGenerator({
576
565
  const pluginTs = driver.getPlugin(pluginTsName);
577
566
  if (!pluginTs) return null;
578
567
  const tsResolver = driver.getResolver(pluginTsName);
579
- const importedTypeNames = [tsResolver.resolveRequestConfigName(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })];
568
+ const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })];
580
569
  const meta = {
581
- name: resolver.resolveName(node.operationId),
582
- file: resolver.resolveFile({
570
+ name: resolver.name(node.operationId),
571
+ file: resolver.file({
583
572
  name: node.operationId,
584
573
  extname: ".ts",
585
574
  tag: node.tags[0] ?? "default",
586
- path: node.path
587
- }, {
575
+ path: node.path,
588
576
  root,
589
577
  output,
590
578
  group: group ?? void 0
591
579
  }),
592
- fileTs: tsResolver.resolveFile({
580
+ fileTs: tsResolver.file({
593
581
  name: node.operationId,
594
582
  extname: ".ts",
595
583
  tag: node.tags[0] ?? "default",
596
- path: node.path
597
- }, {
584
+ path: node.path,
598
585
  root,
599
586
  output: pluginTs.options?.output ?? output,
600
587
  group: pluginTs.options?.group ?? void 0
@@ -604,7 +591,7 @@ const cypressGenerator = defineGenerator({
604
591
  baseName: meta.file.baseName,
605
592
  path: meta.file.path,
606
593
  meta: meta.file.meta,
607
- banner: resolver.resolveBanner(ctx.meta, {
594
+ banner: resolver.default.banner(ctx.meta, {
608
595
  output,
609
596
  config,
610
597
  file: {
@@ -612,7 +599,7 @@ const cypressGenerator = defineGenerator({
612
599
  baseName: meta.file.baseName
613
600
  }
614
601
  }),
615
- footer: resolver.resolveFooter(ctx.meta, {
602
+ footer: resolver.default.footer(ctx.meta, {
616
603
  output,
617
604
  config,
618
605
  file: {
@@ -620,7 +607,7 @@ const cypressGenerator = defineGenerator({
620
607
  baseName: meta.file.baseName
621
608
  }
622
609
  }),
623
- children: [meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
610
+ children: [importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
624
611
  name: importedTypeNames,
625
612
  root: meta.file.path,
626
613
  path: meta.fileTs.path,
@@ -645,22 +632,10 @@ const cypressGenerator = defineGenerator({
645
632
  * ```ts
646
633
  * import { resolverCypress } from '@kubb/plugin-cypress'
647
634
  *
648
- * resolverCypress.default('list pets', 'function') // 'listPets'
635
+ * resolverCypress.name('list pets') // 'listPets'
649
636
  * ```
650
637
  */
651
- const resolverCypress = defineResolver(() => ({
652
- name: "default",
653
- pluginName: "plugin-cypress",
654
- default(name, type) {
655
- return type === "file" ? toFilePath(name) : camelCase(name);
656
- },
657
- resolveName(name) {
658
- return this.default(name, "function");
659
- },
660
- resolvePathName(name, type) {
661
- return this.default(name, type);
662
- }
663
- }));
638
+ const resolverCypress = createResolver({ pluginName: "plugin-cypress" });
664
639
  //#endregion
665
640
  //#region src/plugin.ts
666
641
  /**
@@ -702,10 +677,7 @@ const pluginCypress = definePlugin((options) => {
702
677
  options,
703
678
  dependencies: [pluginTsName],
704
679
  hooks: { "kubb:plugin:setup"(ctx) {
705
- const resolver = userResolver ? {
706
- ...resolverCypress,
707
- ...userResolver
708
- } : resolverCypress;
680
+ const resolver = userResolver ? Resolver.merge(resolverCypress, userResolver) : resolverCypress;
709
681
  ctx.setOptions({
710
682
  output,
711
683
  exclude,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/fs.ts","../../../internals/utils/src/reserved.ts","../../../internals/utils/src/url.ts","../../../internals/shared/src/params.ts","../../../internals/shared/src/operation.ts","../../../internals/shared/src/group.ts","../src/components/Request.tsx","../src/generators/cypressGenerator.tsx","../src/resolvers/resolverCypress.ts","../src/plugin.ts"],"sourcesContent":["type Options = {\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n return text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n .split(/[\\s\\-_./\\\\:]+/)\n .filter(Boolean)\n .map((word, i) => {\n if (word.length > 1 && word === word.toUpperCase()) return word\n const head = i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()\n return head + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Converts `text` to camelCase.\n *\n * @example Word boundaries\n * `camelCase('hello-world') // 'helloWorld'`\n *\n * @example With a prefix\n * `camelCase('tag', { prefix: 'create' }) // 'createTag'`\n */\nexport function camelCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n *\n * @example Word boundaries\n * `pascalCase('hello-world') // 'HelloWorld'`\n *\n * @example With a suffix\n * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`\n */\nexport function pascalCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n\n/**\n * Converts `text` to snake_case.\n *\n * @example From camelCase\n * `snakeCase('helloWorld') // 'hello_world'`\n *\n * @example From mixed separators\n * `snakeCase('Hello-World') // 'hello_world'`\n */\nexport function snakeCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n const processed = `${prefix} ${text} ${suffix}`.trim()\n return processed\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s\\-.]+/g, '_')\n .replace(/[^a-zA-Z0-9_]/g, '')\n .toLowerCase()\n .split('_')\n .filter(Boolean)\n .join('_')\n}\n\n/**\n * Converts `text` to SCREAMING_SNAKE_CASE.\n *\n * @example From camelCase\n * `screamingSnakeCase('helloWorld') // 'HELLO_WORLD'`\n */\nexport function screamingSnakeCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return snakeCase(text, { prefix, suffix }).toUpperCase()\n}\n","import { posix } from 'node:path'\nimport { camelCase } from './casing.ts'\n\nfunction toSlash(p: string): string {\n if (p.startsWith('\\\\\\\\?\\\\')) return p\n return p.replaceAll('\\\\', '/')\n}\n\n/**\n * Returns the relative path from `rootDir` to `filePath`, always using forward slashes\n * and prefixed with `./` when not already traversing upward.\n *\n * @example\n * ```ts\n * getRelativePath('/src/components', '/src/components/Button.tsx') // './Button.tsx'\n * getRelativePath('/src/components', '/src/utils/helpers.ts') // '../utils/helpers.ts'\n * ```\n */\nexport function getRelativePath(rootDir?: string | null, filePath?: string | null): string {\n if (!rootDir || !filePath) {\n throw new Error(`Root and file should be filled in when retrieving the relativePath, ${rootDir || ''} ${filePath || ''}`)\n }\n\n const relativePath = posix.relative(toSlash(rootDir), toSlash(filePath))\n\n return relativePath.startsWith('../') ? relativePath : `./${relativePath}`\n}\n\n/**\n * Builds a nested file path from a dotted name. Splits on dots that precede a letter\n * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases\n * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.\n *\n * Empty segments are dropped before joining. They arise when the name starts with a dot\n * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to\n * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an\n * absolute path, letting generated files escape the configured output directory.\n *\n * @example Nested path from a dotted name\n * `toFilePath('pet.petId') // 'pet/petId'`\n *\n * @example PascalCase the final segment\n * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`\n *\n * @example Suffix applied to the final segment only\n * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`\n */\nexport function toFilePath(name: string, caseLast: (part: string) => string = camelCase): string {\n const parts = name.split(/\\.(?=[a-zA-Z])/)\n return parts\n .map((part, i) => (i === parts.length - 1 ? caseLast(part) : camelCase(part)))\n .filter(Boolean)\n .join('/')\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n\n/**\n * Returns `name` when it's a syntactically valid JavaScript variable name,\n * otherwise prefixes it with `_` so the result is a valid identifier.\n *\n * Useful for sanitizing OpenAPI schema names or operation IDs that start with\n * a digit (e.g. `409`, `504AccountCancel`) before using them as exported\n * variable, type, or function names.\n *\n * @example\n * ```ts\n * ensureValidVarName('409') // '_409'\n * ensureValidVarName('504AccountCancel') // '_504AccountCancel'\n * ensureValidVarName('Pet') // 'Pet'\n * ensureValidVarName('class') // '_class'\n * ```\n */\nexport function ensureValidVarName(name: string): string {\n if (!name || isValidVarName(name)) {\n return name\n }\n return `_${name}`\n}\n","import { camelCase } from './casing.ts'\nimport { isValidVarName } from './reserved.ts'\n\nexport type URLObject = {\n /**\n * The resolved URL string (Express-style or template literal, depending on context).\n */\n url: string\n /**\n * Extracted path parameters as a key-value map, or `null` when the path has none.\n */\n params: Record<string, string> | null\n}\n\n/**\n * Supported identifier casing strategies for path parameters.\n */\nexport type PathCasing = 'camelcase'\n\ntype TemplateOptions = {\n /**\n * Literal text prepended inside the template literal, e.g. a base URL.\n */\n prefix?: string | null\n /**\n * Transform applied to each extracted parameter name before interpolation.\n */\n replacer?: (pathParam: string) => string\n /**\n * Casing strategy applied to path parameter names.\n */\n casing?: PathCasing\n}\n\ntype ObjectOptions = {\n /**\n * Controls whether the `url` is rendered as an Express path or a template literal.\n * @default 'path'\n */\n type?: 'path' | 'template'\n /**\n * Transform applied to each extracted parameter name.\n */\n replacer?: (pathParam: string) => string\n /**\n * When `true`, the result is serialized to a string expression instead of a plain object.\n */\n stringify?: boolean\n /**\n * Casing strategy applied to path parameter names.\n */\n casing?: PathCasing\n}\n\nfunction transformParam(raw: string, casing?: PathCasing): string {\n const param = isValidVarName(raw) ? raw : camelCase(raw)\n return casing === 'camelcase' ? camelCase(param) : param\n}\n\nfunction toParamsObject(\n path: string,\n { replacer, casing }: { replacer?: (pathParam: string) => string; casing?: PathCasing } = {},\n): Record<string, string> | null {\n const params: Record<string, string> = {}\n\n for (const match of path.matchAll(/\\{([^}]+)\\}/g)) {\n const param = transformParam(match[1]!, casing)\n const key = replacer ? replacer(param) : param\n params[key] = key\n }\n\n return Object.keys(params).length > 0 ? params : null\n}\n\n/**\n * Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.\n */\nexport class Url {\n /**\n * Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.\n *\n * @example\n * Url.canParse('https://petstore.swagger.io/v2') // true\n * Url.canParse('/pet/{petId}') // false\n */\n static canParse(url: string, base?: string | URL): boolean {\n return URL.canParse(url, base)\n }\n\n /**\n * Converts an OpenAPI/Swagger path to Express-style colon syntax.\n *\n * @example\n * Url.toPath('/pet/{petId}') // '/pet/:petId'\n */\n static toPath(path: string): string {\n return path.replace(/\\{([^}]+)\\}/g, ':$1')\n }\n\n /**\n * Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`\n * literal aligns with the grouped `path` request option that the runtime client interpolates by\n * key.\n *\n * @example\n * Url.toCasedTemplate('/projects/{project_id}', { casing: 'camelcase' }) // '/projects/{projectId}'\n */\n static toCasedTemplate(path: string, { casing }: { casing?: PathCasing } = {}): string {\n return path.replace(/\\{([^}]+)\\}/g, (_, name: string) => `{${transformParam(name, casing)}}`)\n }\n\n /**\n * Converts an OpenAPI/Swagger path to a TypeScript template literal string.\n * `prefix` is prepended inside the literal, `replacer` transforms each parameter name,\n * and `casing` controls parameter identifier casing.\n *\n * @example\n * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'\n *\n * @example\n * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'\n */\n static toTemplateString(path: string, { prefix, replacer, casing }: TemplateOptions = {}): string {\n const parts = path.split(/\\{([^}]+)\\}/)\n const result = parts\n .map((part, i) => {\n if (i % 2 === 0) return part\n const param = transformParam(part, casing)\n return `\\${${replacer ? replacer(param) : param}}`\n })\n .join('')\n\n return `\\`${prefix ?? ''}${result}\\``\n }\n\n /**\n * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the\n * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter\n * names are camelCased to match the generated `path` type, and `prefix` is prepended inside the\n * literal. Shared by the client and cypress generators that pass a grouped `path` object.\n *\n * @example\n * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'\n */\n static toGroupedTemplateString(path: string, { prefix }: { prefix?: string | null } = {}): string {\n return Url.toTemplateString(path, { prefix, casing: 'camelcase', replacer: (name) => `path.${name}` })\n }\n\n /**\n * Returns the path and its extracted params as a structured `URLObject`, or as a stringified\n * expression when `stringify` is set.\n *\n * @example\n * Url.toObject('/pet/{petId}')\n * // { url: '/pet/:petId', params: { petId: 'petId' } }\n */\n static toObject(path: string, { type = 'path', replacer, stringify, casing }: ObjectOptions = {}): URLObject | string {\n const object: URLObject = {\n url: type === 'path' ? Url.toPath(path) : Url.toTemplateString(path, { replacer, casing }),\n params: toParamsObject(path, { replacer, casing }),\n }\n\n if (stringify) {\n if (type === 'template') {\n return JSON.stringify(object).replaceAll(\"'\", '').replaceAll(`\"`, '')\n }\n\n if (object.params) {\n return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll(\"'\", '').replaceAll(`\"`, '')} }`\n }\n\n return `{ url: '${object.url}' }`\n }\n\n return object\n }\n}\n","import { camelCase, isValidVarName } from '@internals/utils'\nimport type { ast } from 'kubb/kit'\n\nconst caseParamsCache = new WeakMap<Array<ast.ParameterNode>, Array<ast.ParameterNode>>()\n\n/**\n * Applies camelCase to parameter names and returns a new array without mutating the input.\n *\n * Run it before handing parameters to schema builders so output property keys get the right casing\n * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the\n * original array is returned unchanged. Results are cached per input array.\n */\nexport function caseParams(params: Array<ast.ParameterNode>, casing: 'camelcase' | undefined): Array<ast.ParameterNode> {\n if (!casing) return params\n\n const cached = caseParamsCache.get(params)\n if (cached) return cached\n\n const result = params.map((param) => ({ ...param, name: camelCase(param.name) }))\n caseParamsCache.set(params, result)\n return result\n}\n\n/**\n * Drops parameters that collapse to the same property identity once camelCased, keeping the first.\n *\n * Some specs declare the same parameter twice under different casings (for example AWS S3 lists both\n * `max-uploads` and `MaxUploads`). Both resolve to one output property, so emitting both would yield\n * an object type with a duplicate member, which TypeScript rejects. De-duplicate by the camelCased\n * identity so the resulting group is collision-free regardless of the names each caller carries.\n */\nexport function dedupeByCasedName(params: Array<ast.ParameterNode>): Array<ast.ParameterNode> {\n const seen = new Set<string>()\n\n return params.filter((param) => {\n const key = camelCase(param.name)\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\nexport function buildParamsMapping<TParam extends { name: string }>(\n originalParams: ReadonlyArray<TParam>,\n mappedParams: ReadonlyArray<TParam>,\n): Record<string, string> | null {\n const mapping: Record<string, string> = {}\n let hasChanged = false\n\n originalParams.forEach((param, i) => {\n const mappedName = mappedParams[i]?.name ?? param.name\n mapping[param.name] = mappedName\n\n if (param.name !== mappedName) {\n hasChanged = true\n }\n })\n\n return hasChanged ? mapping : null\n}\n\nexport function buildTransformedParamsMapping<TParam extends { name: string }>(\n params: ReadonlyArray<TParam>,\n transformName: (name: string) => string,\n): Record<string, string> | null {\n if (!params.length) {\n return null\n }\n\n return buildParamsMapping(\n params,\n params.map((param) => ({ ...param, name: transformName(param.name) })),\n )\n}\n\nfunction toAccess(object: string, name: string): string {\n return isValidVarName(name) ? `${object}.${name}` : `${object}[${JSON.stringify(name)}]`\n}\n\n/**\n * Renders the object-literal expression that renames the camelCased keys of a grouped request\n * option back to the names the OpenAPI document declares, guarded so an omitted optional group\n * stays omitted. Shared by the client and cypress generators, which pass a `buildParamsMapping`\n * result and the source expression to read the keys from.\n *\n * @example\n * ```ts\n * buildParamsRemapExpression({ source: 'config.query', mapping: { include_deleted: 'includeDeleted' } })\n * // 'config.query ? { \"include_deleted\": config.query.includeDeleted } : config.query'\n * ```\n */\nexport function buildParamsRemapExpression({ source, mapping }: { source: string; mapping: Record<string, string> }): string {\n const pairs = Object.entries(mapping)\n .map(([originalName, casedName]) => `${JSON.stringify(originalName)}: ${toAccess(source, casedName)}`)\n .join(', ')\n\n return `${source} ? { ${pairs} } : ${source}`\n}\n","import { Url } from '@internals/utils'\nimport { ast, type ResolverFileParams } from 'kubb/kit'\nimport { caseParams, dedupeByCasedName } from './params.ts'\n\n/**\n * Builds the `ResolverFileParams` every operation generator passes to\n * `resolver.resolveFile`: a file named `name`, tagged by the operation's first\n * tag (or `'default'`), at the operation's path. Centralizes the entry object\n * that was repeated at dozens of call sites across the client and query plugins.\n *\n * @example\n * ```ts\n * resolver.resolveFile(operationFileEntry(node, node.operationId), { root, output, group })\n * ```\n */\nexport function operationFileEntry(node: ast.OperationNode, name: string, extname: ResolverFileParams['extname'] = '.ts'): ResolverFileParams {\n return {\n name,\n extname,\n tag: node.tags[0] ?? 'default',\n path: node.path,\n }\n}\n\nexport type ContentTypeInfo = {\n contentTypes: string[]\n isMultipleContentTypes: boolean\n contentTypeUnion: string\n defaultContentType: string\n hasFormData: boolean\n}\n\nexport type RequestConfigResolver = {\n resolveDataName(node: ast.OperationNode): string\n}\n\nexport type ResponseStatusNameResolver = {\n resolveResponseStatusName(node: ast.OperationNode, statusCode: ast.StatusCode): string\n}\n\nexport type ResponseNameResolver = ResponseStatusNameResolver & {\n resolveResponseName(node: ast.OperationNode): string\n}\n\nexport type OperationTypeNameResolver = RequestConfigResolver &\n ResponseNameResolver & {\n resolvePathParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n resolveQueryParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n resolveHeaderParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n }\n\n/**\n * Resolver interface for building operation parameters.\n *\n * `ResolverTs` from `@kubb/plugin-ts` satisfies this interface and can be passed directly.\n */\nexport type OperationParamsResolver = {\n /**\n * Resolves the type name for an individual parameter.\n *\n * @example Individual path parameter name\n * `resolver.resolveParamName(node, param) // → 'DeletePetPathPetId'`\n */\n resolveParamName(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the request body type name.\n *\n * @example Request body type name\n * `resolver.resolveDataName(node) // → 'CreatePetData'`\n */\n resolveDataName(node: ast.OperationNode): string\n /**\n * Resolves the grouped path parameters type name.\n * When the return value equals `resolveParamName`, no indexed access is emitted.\n *\n * @example Grouped path params type name\n * `resolver.resolvePathParamsName(node, param) // → 'DeletePetPathParams'`\n */\n resolvePathParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the grouped query parameters type name.\n * When the return value equals `resolveParamName`, an inline struct type is emitted instead.\n *\n * @example Grouped query params type name\n * `resolver.resolveQueryParamsName(node, param) // → 'FindPetsByStatusQueryParams'`\n */\n resolveQueryParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the grouped header parameters type name.\n * When the return value equals `resolveParamName`, an inline struct type is emitted instead.\n *\n * @example Grouped header params type name\n * `resolver.resolveHeaderParamsName(node, param) // → 'DeletePetHeaderParams'`\n */\n resolveHeaderParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n}\n\nexport type OperationCommentLink = 'pathTemplate' | 'urlPath' | false | ((node: ast.OperationNode) => string | undefined)\n\nexport type BuildOperationCommentsOptions = {\n link?: OperationCommentLink\n linkPosition?: 'beforeDeprecated' | 'afterDeprecated'\n splitLines?: boolean\n}\n\ntype ResponseLike = {\n statusCode: ast.StatusCode | number | string\n}\n\nexport type OperationParameterGroups = Record<ast.ParameterNode['in'], Array<ast.ParameterNode>>\n\nexport type ResolveOperationTypeNameOptions = {\n paramsCasing?: 'camelcase' | 'original'\n responseStatusNames?: boolean | 'error'\n exclude?: ReadonlyArray<string | undefined>\n order?: 'params-first' | 'body-response-first'\n /**\n * Include the individual `PathParams`/`QueryParams`/`HeaderParams` type names. Set to `false`\n * for clients that reference the grouped `RequestConfig` type instead of the per-group types.\n */\n includeParams?: boolean\n}\n\nfunction getOperationLink(node: ast.OperationNode, link: OperationCommentLink): string | null {\n if (!link) {\n return null\n }\n\n if (typeof link === 'function') {\n return link(node) ?? null\n }\n\n if (link === 'urlPath') {\n return node.path ? `{@link ${Url.toPath(node.path)}}` : null\n }\n\n return node.path ? `{@link ${node.path.replaceAll('{', ':').replaceAll('}', '')}}` : null\n}\n\nexport function getContentTypeInfo(node: ast.OperationNode): ContentTypeInfo {\n const contentTypes = node.requestBody?.content?.map((e) => e.contentType) ?? []\n const isMultipleContentTypes = contentTypes.length > 1\n\n return {\n contentTypes,\n isMultipleContentTypes,\n contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(' | ') : '',\n defaultContentType: contentTypes[0] ?? 'application/json',\n hasFormData: contentTypes.some((ct) => ct === 'multipart/form-data'),\n }\n}\n\n/**\n * The request-body counterpart for the primary success response: the content types it documents and\n * whether several are present, so the client can let a caller pick which one to accept.\n */\nexport function getResponseContentTypeInfo(node: ast.OperationNode): ContentTypeInfo {\n const contentTypes = getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? []\n const isMultipleContentTypes = contentTypes.length > 1\n\n return {\n contentTypes,\n isMultipleContentTypes,\n contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(' | ') : '',\n defaultContentType: contentTypes[0] ?? 'application/json',\n hasFormData: contentTypes.some((ct) => ct === 'multipart/form-data'),\n }\n}\n\nexport type ResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n\n/**\n * Reads the single base content type of an operation's primary success response, lowercased and\n * stripped of any `; charset=...` suffix. Returns `undefined` when the response declares zero or\n * more than one content type, since neither case has a single type to act on.\n */\nfunction getPrimarySuccessContentType(node: ast.OperationNode): string | undefined {\n const contentTypes = getPrimarySuccessResponse(node)?.content?.map((entry) => entry.contentType) ?? []\n if (contentTypes.length !== 1) return undefined\n return contentTypes[0]!.split(';')[0]!.trim().toLowerCase()\n}\n\n/**\n * Whether an operation streams its primary success response as Server-Sent Events\n * (`text/event-stream`). The client generator uses this to return a typed event stream instead of a\n * one-shot `RequestResult`.\n */\nexport function isEventStream(node: ast.OperationNode): boolean {\n return getPrimarySuccessContentType(node) === 'text/event-stream'\n}\n\n/**\n * Derives the default `responseType` for an operation from its primary success response.\n *\n * Returns a value only when that response declares a single non-JSON content type. `text/event-stream`\n * and other binary types (`application/octet-stream`, `application/pdf`, `image/*`, `audio/*`,\n * `video/*`) map to a stream or `'blob'`, and other `text/*` maps to `'text'`. Otherwise `undefined`,\n * leaving the runtime client's `Content-Type` auto-detection in charge.\n */\nexport function getResponseType(node: ast.OperationNode): ResponseType | undefined {\n const baseType = getPrimarySuccessContentType(node)\n if (!baseType) return undefined\n\n if (baseType === 'application/json' || baseType.endsWith('+json') || baseType === 'text/json') return undefined\n if (baseType === 'text/event-stream') return 'stream'\n if (baseType.startsWith('text/')) return 'text'\n if (baseType === 'application/octet-stream' || baseType === 'application/pdf' || /^(image|audio|video)\\//.test(baseType)) return 'blob'\n return undefined\n}\n\n/**\n * Maps a content type to the PascalCase suffix used to name per-content-type variants\n * (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).\n */\nfunction getContentTypeSuffix(contentType: string): string {\n const baseType = contentType.split(';')[0]!.trim()\n if (baseType === 'application/json') return 'Json'\n if (baseType === 'multipart/form-data') return 'FormData'\n if (baseType === 'application/x-www-form-urlencoded') return 'FormUrlEncoded'\n const subtype = baseType.split('/').pop() ?? baseType\n const parts = subtype.split(/[^a-zA-Z0-9]+/).filter(Boolean)\n if (parts.length === 0) return 'Unknown'\n return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('')\n}\n\n/**\n * Appends a content-type suffix to a base name, keeping a trailing `Data` segment last\n * (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).\n */\nexport function getPerContentTypeName(baseName: string, suffix: string): string {\n if (baseName.endsWith('Data')) {\n return suffix.endsWith('Data') ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`\n }\n return baseName + suffix\n}\n\nexport type ContentVariantInput = { contentType: string; schema?: ast.SchemaNode | null; keysToOmit?: Array<string> | null }\nexport type ContentVariant = { name: string; suffix: string; schema: ast.SchemaNode; keysToOmit?: Array<string> | null; contentType: string }\n\n/**\n * Resolves per-content-type variant names for a set of content entries, deduplicating suffix\n * collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is\n * the final (possibly counter-augmented) value, so callers can derive parallel names in another\n * namespace (e.g. plugin-faker deriving the matching plugin-ts type name).\n */\nexport function resolveContentTypeVariants(entries: Array<ContentVariantInput>, baseName: string): Array<ContentVariant> {\n const usedNames = new Set<string>()\n return entries\n .filter((entry) => entry.schema)\n .map((entry) => {\n const baseSuffix = getContentTypeSuffix(entry.contentType)\n let suffix = baseSuffix\n let name = getPerContentTypeName(baseName, suffix)\n let counter = 2\n while (usedNames.has(name)) {\n suffix = `${baseSuffix}${counter++}`\n name = getPerContentTypeName(baseName, suffix)\n }\n usedNames.add(name)\n return { name, suffix, schema: entry.schema!, keysToOmit: entry.keysToOmit, contentType: entry.contentType }\n })\n}\n\nexport function buildRequestConfigType(node: ast.OperationNode): string {\n const request = getContentTypeInfo(node)\n const response = getResponseContentTypeInfo(node)\n // The request groups come from the grouped params, so `config` drops the data-shape keys to stay\n // assignable to `Options`, which omits them from `RequestConfig`.\n const configType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n\n // Only the ambiguous side is offered: a single-type side has nothing to pick, so it stays baked in\n // the generated call.\n const members = [\n request.isMultipleContentTypes ? `request?: ${request.contentTypeUnion}` : null,\n response.isMultipleContentTypes ? `response?: ${response.contentTypeUnion}` : null,\n ].filter(Boolean)\n\n return members.length ? `${configType} & { contentType?: { ${members.join('; ')} } }` : configType\n}\n\n/**\n * Builds the `client?:` option type shared by the generated query hooks (`useQuery`,\n * `useInfiniteQuery`, `useSWR`, ...). Unlike {@link buildRequestConfigType}, it never adds a\n * `contentType?:` member: query hooks wrap GET operations, which carry no request body to select a\n * content type for.\n */\nexport function buildClientOptionType(): string {\n return `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n}\n\nexport type RequestGroups = {\n path: boolean\n query: boolean\n body: boolean\n headers: boolean\n}\n\n/**\n * Which of the grouped request options an operation carries.\n */\nexport function getRequestGroups(node: ast.OperationNode): RequestGroups {\n const { path, query, header } = getOperationParameters(node)\n return {\n path: path.length > 0,\n query: query.length > 0,\n body: Boolean(node.requestBody?.content?.[0]?.schema),\n headers: header.length > 0,\n }\n}\n\nexport type RequestGroupOptionality = {\n groups: RequestGroups\n hasRequiredPath: boolean\n hasRequiredQuery: boolean\n hasRequiredHeader: boolean\n /**\n * Whether the grouped request parameter can default to `{}`. True only when no group carries a\n * required member, so every member is safe to omit.\n */\n isOptional: boolean\n}\n\n/**\n * Resolves which grouped request options an operation carries together with whether each group\n * holds a required member. The grouped parameter stays optional only when nothing inside it is\n * required, matching the generated `RequestConfig` type.\n */\nexport function getRequestGroupOptionality(node: ast.OperationNode): RequestGroupOptionality {\n const groups = getRequestGroups(node)\n const { path, query, header } = getOperationParameters(node)\n const hasRequiredPath = path.some((param) => param.required)\n const hasRequiredQuery = query.some((param) => param.required)\n const hasRequiredHeader = header.some((param) => param.required)\n\n return {\n groups,\n hasRequiredPath,\n hasRequiredQuery,\n hasRequiredHeader,\n isOptional: !hasRequiredPath && !hasRequiredQuery && !hasRequiredHeader && !groups.body,\n }\n}\n\nexport type RequestConfigNameResolver = RequestConfigResolver & {\n resolveRequestConfigName(node: ast.OperationNode): string\n}\n\n/**\n * Builds the grouped `{ path, query, body, headers }` parameter for a generated client\n * function, typed from the operation's `RequestConfig` (minus `url`). Only the groups the\n * operation actually has are destructured. The trailing `config` parameter carries the\n * runtime `RequestConfig` overrides plus `client`.\n */\nexport function buildRequestParamsSignature(\n node: ast.OperationNode,\n resolver: RequestConfigNameResolver,\n options: { isConfigurable?: boolean } = {},\n): { signature: string; groups: RequestGroups } {\n const { isConfigurable = true } = options\n const { groups, isOptional } = getRequestGroupOptionality(node)\n\n const names = (['path', 'query', 'body', 'headers'] as const).filter((key) => groups[key])\n\n const firstParam = names.length > 0 ? `{ ${names.join(', ')} }: ${resolver.resolveRequestConfigName(node)}${isOptional ? ' = {}' : ''}` : null\n const configParam = isConfigurable ? `config: ${buildRequestConfigType(node)} = {}` : null\n\n return {\n signature: [firstParam, configParam].filter(Boolean).join(', '),\n groups,\n }\n}\n\nexport function buildOperationComments(node: ast.OperationNode, options: BuildOperationCommentsOptions = {}): Array<string> {\n const { link = 'pathTemplate', linkPosition = 'afterDeprecated', splitLines = false } = options\n const linkComment = getOperationLink(node, link)\n const comments =\n linkPosition === 'beforeDeprecated'\n ? [node.description && `@description ${node.description}`, node.summary && `@summary ${node.summary}`, linkComment, node.deprecated && '@deprecated']\n : [node.description && `@description ${node.description}`, node.summary && `@summary ${node.summary}`, node.deprecated && '@deprecated', linkComment]\n\n const filteredComments = comments.filter((comment): comment is string => Boolean(comment))\n\n if (!splitLines) {\n return filteredComments\n }\n\n return filteredComments.flatMap((text) => text.split(/\\r?\\n/).map((line) => line.trim())).filter((comment): comment is string => Boolean(comment))\n}\n\nexport function getOperationParameters(node: ast.OperationNode, options: { paramsCasing?: 'camelcase' | 'original' } = {}): OperationParameterGroups {\n const params = caseParams(node.parameters, options.paramsCasing === 'original' ? undefined : 'camelcase')\n\n return {\n path: dedupeByCasedName(params.filter((param) => param.in === 'path')),\n query: dedupeByCasedName(params.filter((param) => param.in === 'query')),\n header: dedupeByCasedName(params.filter((param) => param.in === 'header')),\n cookie: dedupeByCasedName(params.filter((param) => param.in === 'cookie')),\n }\n}\n\nexport function getStatusCodeNumber(statusCode: ast.StatusCode | number | string): number | null {\n const code = Number(statusCode)\n\n return Number.isNaN(code) ? null : code\n}\n\nexport function isSuccessStatusCode(statusCode: ast.StatusCode | number | string): boolean {\n const code = getStatusCodeNumber(statusCode)\n\n return code !== null && code >= 200 && code < 300\n}\n\nexport function isErrorStatusCode(statusCode: ast.StatusCode | number | string): boolean {\n const code = getStatusCodeNumber(statusCode)\n\n return code !== null && code >= 400\n}\n\nexport function getSuccessResponses<TResponse extends ResponseLike>(responses: ReadonlyArray<TResponse>): Array<TResponse> {\n return responses.filter((response) => isSuccessStatusCode(response.statusCode))\n}\n\nexport function getOperationSuccessResponses(node: ast.OperationNode): Array<ast.ResponseNode> {\n return getSuccessResponses(node.responses)\n}\n\nexport function getPrimarySuccessResponse(node: ast.OperationNode): ast.ResponseNode | null {\n return getOperationSuccessResponses(node)[0] ?? null\n}\n\nexport function resolveErrorNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses\n .filter((response) => isErrorStatusCode(response.statusCode))\n .map((response) => resolver.resolveResponseStatusName(node, response.statusCode))\n}\n\nexport function resolveSuccessNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses\n .filter((response) => isSuccessStatusCode(response.statusCode))\n .map((response) => resolver.resolveResponseStatusName(node, response.statusCode))\n}\n\nexport function resolveStatusCodeNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode))\n}\n\nconst typeNamesByResolver = new WeakMap<OperationTypeNameResolver, Map<string, string[]>>()\n\nexport function resolveOperationTypeNames(\n node: ast.OperationNode,\n resolver: OperationTypeNameResolver,\n options: ResolveOperationTypeNameOptions = {},\n): string[] {\n const cacheKey = `${node.operationId}\\0${options.paramsCasing ?? ''}\\0${options.order ?? ''}\\0${options.responseStatusNames ?? ''}\\0${options.includeParams === false ? 'noparams' : ''}\\0${(options.exclude ?? []).join(',')}`\n let byResolver = typeNamesByResolver.get(resolver)\n if (byResolver) {\n const cached = byResolver.get(cacheKey)\n if (cached) return cached\n } else {\n byResolver = new Map()\n typeNamesByResolver.set(resolver, byResolver)\n }\n\n const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing })\n const responseStatusNames =\n options.responseStatusNames === 'error'\n ? resolveErrorNames(node, resolver)\n : options.responseStatusNames === false\n ? []\n : resolveStatusCodeNames(node, resolver)\n const exclude = new Set(options.exclude ?? [])\n const paramNames =\n options.includeParams === false\n ? []\n : [\n ...path.map((param) => resolver.resolvePathParamsName(node, param)),\n ...query.map((param) => resolver.resolveQueryParamsName(node, param)),\n ...header.map((param) => resolver.resolveHeaderParamsName(node, param)),\n ]\n const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null, resolver.resolveResponseName(node)]\n const names =\n options.order === 'body-response-first'\n ? [...bodyAndResponseNames, ...paramNames, ...responseStatusNames]\n : [...paramNames, ...bodyAndResponseNames, ...responseStatusNames]\n\n const result = names.filter((name): name is string => Boolean(name) && !exclude.has(name as string))\n byResolver.set(cacheKey, result)\n return result\n}\n\nexport function resolveResponseTypes(node: ast.OperationNode, resolver: ResponseNameResolver): Array<[statusCode: number | 'default', typeName: string]> {\n const types: Array<[number | 'default', string]> = []\n\n for (const response of node.responses) {\n if (response.statusCode === 'default') {\n types.push(['default', resolver.resolveResponseName(node)])\n continue\n }\n\n const code = getStatusCodeNumber(response.statusCode)\n if (code === null) {\n continue\n }\n\n types.push([code, isSuccessStatusCode(code) ? resolver.resolveResponseName(node) : resolver.resolveResponseStatusName(node, response.statusCode)])\n }\n\n return types\n}\n\nexport function findSuccessStatusCode(responses: Array<{ statusCode: ast.StatusCode | number | string }>): ast.StatusCode | null {\n for (const response of responses) {\n if (isSuccessStatusCode(response.statusCode)) {\n return response.statusCode as ast.StatusCode\n }\n }\n\n return null\n}\n","import { camelCase } from '@internals/utils'\nimport type { Group } from 'kubb/kit'\n\n/**\n * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the\n * shared default naming so every plugin groups output consistently:\n *\n * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).\n * - other groups use the camelCased group (`pet store` → `petStore`).\n *\n * A user-provided `group.name` always wins over the default namer, so callers stay in\n * control of their output folders. Returns `null` when grouping is disabled, matching the\n * per-plugin convention.\n *\n * @param group - The user-supplied group option, or `undefined` to disable grouping.\n *\n * @example\n * ```ts\n * createGroupConfig(group) // shared across every plugin\n * ```\n */\nexport function createGroupConfig(group: Group | undefined): Group | null {\n if (!group) {\n return null\n }\n\n const defaultName = (ctx: { group: string }): string => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n\n return camelCase(ctx.group)\n }\n\n return {\n ...group,\n name: group.name ? group.name : defaultName,\n } satisfies Group\n}\n","import { buildParamsMapping, buildParamsRemapExpression, buildRequestParamsSignature, getOperationParameters } from '@internals/shared'\nimport { Url } from '@internals/utils'\nimport { ast } from 'kubb/kit'\nimport type { ResolverTs } from '@kubb/plugin-ts'\nimport { File, Function } from 'kubb/jsx'\nimport type { KubbReactNode } from 'kubb/jsx'\n\ntype Props = {\n /**\n * Name of the function\n */\n name: string\n /**\n * AST operation node\n */\n node: ast.OperationNode\n /**\n * TypeScript resolver for resolving param/data/response type names\n */\n resolver: ResolverTs\n baseURL: string | null | undefined\n}\n\nexport function Request({ baseURL = '', name, resolver, node }: Props): KubbReactNode {\n if (!ast.isHttpOperationNode(node)) return null\n\n const { query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node, { paramsCasing: 'original' })\n const { query: casedQueryParams, header: casedHeaderParams } = getOperationParameters(node)\n\n const queryParamsMapping = buildParamsMapping(originalQueryParams, casedQueryParams)\n const headerParamsMapping = buildParamsMapping(originalHeaderParams, casedHeaderParams)\n\n const { signature, groups } = buildRequestParamsSignature(node, resolver, { isConfigurable: false })\n const paramsSignature = [signature, 'options: Partial<Cypress.RequestOptions> = {}'].filter(Boolean).join(', ')\n\n const responseType = resolver.resolveResponseName(node)\n const returnType = `Cypress.Chainable<${responseType}>`\n\n // Reference the path object straight in the URL with camelCase placeholders.\n const urlTemplate = Url.toGroupedTemplateString(node.path, { prefix: baseURL })\n\n const requestOptions: Array<string> = [`method: '${node.method}'`, `url: ${urlTemplate}`]\n\n if (groups.query) {\n requestOptions.push(queryParamsMapping ? `qs: ${buildParamsRemapExpression({ source: 'query', mapping: queryParamsMapping })}` : 'qs: query')\n }\n\n if (groups.headers) {\n requestOptions.push(headerParamsMapping ? `headers: ${buildParamsRemapExpression({ source: 'headers', mapping: headerParamsMapping })}` : 'headers')\n }\n\n if (groups.body) {\n requestOptions.push('body')\n }\n\n requestOptions.push('...options')\n\n const requestCall = `return cy.request<${responseType}>({\n ${requestOptions.join(',\\n ')}\n}).then((res) => res.body)`\n\n return (\n <File.Source name={name} isIndexable isExportable>\n <Function name={name} export params={paramsSignature} returnType={returnType}>\n {requestCall}\n </Function>\n </File.Source>\n )\n}\n","import { resolveOperationTypeNames } from '@internals/shared'\nimport { ast, defineGenerator } from 'kubb/kit'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { File, jsxRenderer } from 'kubb/jsx'\nimport { Request } from '../components/Request.tsx'\nimport type { PluginCypress } from '../types.ts'\n\n/**\n * Built-in generator for `@kubb/plugin-cypress`. Emits one typed\n * `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress\n * test specs and custom commands.\n */\nexport const cypressGenerator = defineGenerator<PluginCypress>({\n name: 'cypress',\n renderer: jsxRenderer,\n operation(node, ctx) {\n if (!ast.isHttpOperationNode(node)) return null\n const { config, resolver, driver, root } = ctx\n const { output, baseURL, group } = ctx.options\n\n const pluginTs = driver.getPlugin(pluginTsName)\n\n if (!pluginTs) {\n return null\n }\n\n const tsResolver = driver.getResolver(pluginTsName)\n\n const importedTypeNames = [tsResolver.resolveRequestConfigName(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })]\n\n const meta = {\n name: resolver.resolveName(node.operationId),\n file: resolver.resolveFile(\n { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },\n { root, output, group: group ?? undefined },\n ),\n fileTs: tsResolver.resolveFile(\n { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },\n {\n root,\n output: pluginTs.options?.output ?? output,\n group: pluginTs.options?.group ?? undefined,\n },\n ),\n } as const\n\n return (\n <File\n baseName={meta.file.baseName}\n path={meta.file.path}\n meta={meta.file.meta}\n banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n >\n {meta.fileTs && importedTypeNames.length > 0 && <File.Import name={importedTypeNames} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />}\n <Request name={meta.name} node={node} resolver={tsResolver} baseURL={baseURL} />\n </File>\n )\n },\n})\n","import { camelCase, toFilePath } from '@internals/utils'\nimport { defineResolver } from 'kubb/kit'\nimport type { PluginCypress } from '../types.ts'\n\n/**\n * Default resolver used by `@kubb/plugin-cypress`. Decides the names and file\n * paths for every generated `cy.request()` wrapper. Functions and files use\n * camelCase, matching the convention from `@kubb/plugin-axios` and `@kubb/plugin-fetch`.\n *\n * @example Resolve a helper name\n * ```ts\n * import { resolverCypress } from '@kubb/plugin-cypress'\n *\n * resolverCypress.default('list pets', 'function') // 'listPets'\n * ```\n */\nexport const resolverCypress = defineResolver<PluginCypress>(() => ({\n name: 'default',\n pluginName: 'plugin-cypress',\n default(name, type) {\n return type === 'file' ? toFilePath(name) : camelCase(name)\n },\n resolveName(name) {\n return this.default(name, 'function')\n },\n resolvePathName(name, type) {\n return this.default(name, type)\n },\n}))\n","import { createGroupConfig } from '@internals/shared'\nimport { definePlugin } from 'kubb/kit'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { cypressGenerator } from './generators/cypressGenerator.tsx'\nimport { resolverCypress } from './resolvers/resolverCypress.ts'\nimport type { PluginCypress } from './types.ts'\n\n/**\n * Canonical plugin name for `@kubb/plugin-cypress`. Used for driver lookups and\n * cross-plugin dependency references.\n */\nexport const pluginCypressName = 'plugin-cypress' satisfies PluginCypress['name']\n\n/**\n * Generates one typed `cy.request()` wrapper per OpenAPI operation. Each helper\n * has typed path params, body, query, and a typed response, so failing API\n * calls in Cypress show up at compile time instead of inside the test runner.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb/config'\n * import { pluginTs } from '@kubb/plugin-ts'\n * import { pluginCypress } from '@kubb/plugin-cypress'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * plugins: [\n * pluginTs(),\n * pluginCypress({\n * output: { path: './cypress' },\n * }),\n * ],\n * })\n * ```\n */\nexport const pluginCypress = definePlugin<PluginCypress>((options) => {\n const {\n output = { path: 'cypress', barrel: { type: 'named' } },\n group,\n exclude = [],\n include,\n override = [],\n baseURL,\n resolver: userResolver,\n macros: userMacros,\n } = options\n\n const groupConfig = createGroupConfig(group)\n\n return {\n name: pluginCypressName,\n options,\n dependencies: [pluginTsName],\n hooks: {\n 'kubb:plugin:setup'(ctx) {\n const resolver = userResolver ? { ...resolverCypress, ...userResolver } : resolverCypress\n\n ctx.setOptions({\n output,\n exclude,\n include,\n override,\n group: groupConfig,\n baseURL,\n resolver,\n })\n ctx.setResolver(resolver)\n if (userMacros?.length) {\n ctx.setMacros(userMacros)\n }\n ctx.addGenerator(cypressGenerator)\n },\n },\n }\n})\n\nexport default pluginCypress\n"],"mappings":";;;;;;;;;;;;;AAkBA,SAAS,gBAAgB,MAAc,QAAyB;CAC9D,OAAO,KACJ,KAAK,CAAC,CACN,QAAQ,qBAAqB,OAAO,CAAC,CACrC,QAAQ,yBAAyB,OAAO,CAAC,CACzC,QAAQ,gBAAgB,OAAO,CAAC,CAChC,MAAM,eAAe,CAAC,CACtB,OAAO,OAAO,CAAC,CACf,KAAK,MAAM,MAAM;EAChB,IAAI,KAAK,SAAS,KAAK,SAAS,KAAK,YAAY,GAAG,OAAO;EAE3D,QADa,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,KAC9E,KAAK,MAAM,CAAC;CAC5B,CAAC,CAAC,CACD,KAAK,EAAE,CAAC,CACR,QAAQ,iBAAiB,EAAE;AAChC;;;;;;;;;;AAWA,SAAgB,UAAU,MAAc,EAAE,SAAS,IAAI,SAAS,OAAgB,CAAC,GAAW;CAC1F,OAAO,gBAAgB,GAAG,OAAO,GAAG,KAAK,GAAG,UAAU,KAAK;AAC7D;;;;;;;;;;;;;;;;;;;;;;ACCA,SAAgB,WAAW,MAAc,WAAqC,WAAmB;CAC/F,MAAM,QAAQ,KAAK,MAAM,gBAAgB;CACzC,OAAO,MACJ,KAAK,MAAM,MAAO,MAAM,MAAM,SAAS,IAAI,SAAS,IAAI,IAAI,UAAU,IAAI,CAAE,CAAC,CAC7E,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;AACb;;;;;;;ACjDA,MAAM,gCAAgB,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAU;;;;;;;;;;;AAYV,SAAgB,eAAe,MAAuB;CACpD,IAAI,CAAC,QAAQ,cAAc,IAAI,IAAiB,GAC9C,OAAO;CAET,OAAO,6BAA6B,KAAK,IAAI;AAC/C;;;ACjDA,SAAS,eAAe,KAAa,QAA6B;CAChE,MAAM,QAAQ,eAAe,GAAG,IAAI,MAAM,UAAU,GAAG;CACvD,OAAO,WAAW,cAAc,UAAU,KAAK,IAAI;AACrD;AAEA,SAAS,eACP,MACA,EAAE,UAAU,WAA8E,CAAC,GAC5D;CAC/B,MAAM,SAAiC,CAAC;CAExC,KAAK,MAAM,SAAS,KAAK,SAAS,cAAc,GAAG;EACjD,MAAM,QAAQ,eAAe,MAAM,IAAK,MAAM;EAC9C,MAAM,MAAM,WAAW,SAAS,KAAK,IAAI;EACzC,OAAO,OAAO;CAChB;CAEA,OAAO,OAAO,KAAK,MAAM,CAAC,CAAC,SAAS,IAAI,SAAS;AACnD;;;;AAKA,IAAa,MAAb,MAAa,IAAI;;;;;;;;CAQf,OAAO,SAAS,KAAa,MAA8B;EACzD,OAAO,IAAI,SAAS,KAAK,IAAI;CAC/B;;;;;;;CAQA,OAAO,OAAO,MAAsB;EAClC,OAAO,KAAK,QAAQ,gBAAgB,KAAK;CAC3C;;;;;;;;;CAUA,OAAO,gBAAgB,MAAc,EAAE,WAAoC,CAAC,GAAW;EACrF,OAAO,KAAK,QAAQ,iBAAiB,GAAG,SAAiB,IAAI,eAAe,MAAM,MAAM,EAAE,EAAE;CAC9F;;;;;;;;;;;;CAaA,OAAO,iBAAiB,MAAc,EAAE,QAAQ,UAAU,WAA4B,CAAC,GAAW;EAEhG,MAAM,SADQ,KAAK,MAAM,aACN,CAAC,CACjB,KAAK,MAAM,MAAM;GAChB,IAAI,IAAI,MAAM,GAAG,OAAO;GACxB,MAAM,QAAQ,eAAe,MAAM,MAAM;GACzC,OAAO,MAAM,WAAW,SAAS,KAAK,IAAI,MAAM;EAClD,CAAC,CAAC,CACD,KAAK,EAAE;EAEV,OAAO,KAAK,UAAU,KAAK,OAAO;CACpC;;;;;;;;;;CAWA,OAAO,wBAAwB,MAAc,EAAE,WAAuC,CAAC,GAAW;EAChG,OAAO,IAAI,iBAAiB,MAAM;GAAE;GAAQ,QAAQ;GAAa,WAAW,SAAS,QAAQ;EAAO,CAAC;CACvG;;;;;;;;;CAUA,OAAO,SAAS,MAAc,EAAE,OAAO,QAAQ,UAAU,WAAW,WAA0B,CAAC,GAAuB;EACpH,MAAM,SAAoB;GACxB,KAAK,SAAS,SAAS,IAAI,OAAO,IAAI,IAAI,IAAI,iBAAiB,MAAM;IAAE;IAAU;GAAO,CAAC;GACzF,QAAQ,eAAe,MAAM;IAAE;IAAU;GAAO,CAAC;EACnD;EAEA,IAAI,WAAW;GACb,IAAI,SAAS,YACX,OAAO,KAAK,UAAU,MAAM,CAAC,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,WAAW,KAAK,EAAE;GAGtE,IAAI,OAAO,QACT,OAAO,WAAW,OAAO,IAAI,aAAa,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,WAAW,KAAK,EAAE,EAAE;GAGlH,OAAO,WAAW,OAAO,IAAI;EAC/B;EAEA,OAAO;CACT;AACF;;;AC7KA,MAAM,kCAAkB,IAAI,QAA4D;;;;;;;;AASxF,SAAgB,WAAW,QAAkC,QAA2D;CACtH,IAAI,CAAC,QAAQ,OAAO;CAEpB,MAAM,SAAS,gBAAgB,IAAI,MAAM;CACzC,IAAI,QAAQ,OAAO;CAEnB,MAAM,SAAS,OAAO,KAAK,WAAW;EAAE,GAAG;EAAO,MAAM,UAAU,MAAM,IAAI;CAAE,EAAE;CAChF,gBAAgB,IAAI,QAAQ,MAAM;CAClC,OAAO;AACT;;;;;;;;;AAUA,SAAgB,kBAAkB,QAA4D;CAC5F,MAAM,uBAAO,IAAI,IAAY;CAE7B,OAAO,OAAO,QAAQ,UAAU;EAC9B,MAAM,MAAM,UAAU,MAAM,IAAI;EAChC,IAAI,KAAK,IAAI,GAAG,GAAG,OAAO;EAC1B,KAAK,IAAI,GAAG;EACZ,OAAO;CACT,CAAC;AACH;AAEA,SAAgB,mBACd,gBACA,cAC+B;CAC/B,MAAM,UAAkC,CAAC;CACzC,IAAI,aAAa;CAEjB,eAAe,SAAS,OAAO,MAAM;EACnC,MAAM,aAAa,aAAa,EAAE,EAAE,QAAQ,MAAM;EAClD,QAAQ,MAAM,QAAQ;EAEtB,IAAI,MAAM,SAAS,YACjB,aAAa;CAEjB,CAAC;CAED,OAAO,aAAa,UAAU;AAChC;AAgBA,SAAS,SAAS,QAAgB,MAAsB;CACtD,OAAO,eAAe,IAAI,IAAI,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,KAAK,UAAU,IAAI,EAAE;AACxF;;;;;;;;;;;;;AAcA,SAAgB,2BAA2B,EAAE,QAAQ,WAAwE;CAK3H,OAAO,GAAG,OAAO,OAJH,OAAO,QAAQ,OAAO,CAAC,CAClC,KAAK,CAAC,cAAc,eAAe,GAAG,KAAK,UAAU,YAAY,EAAE,IAAI,SAAS,QAAQ,SAAS,GAAG,CAAC,CACrG,KAAK,IAEoB,EAAE,OAAO;AACvC;;;AC0CA,SAAgB,mBAAmB,MAA0C;CAC3E,MAAM,eAAe,KAAK,aAAa,SAAS,KAAK,MAAM,EAAE,WAAW,KAAK,CAAC;CAC9E,MAAM,yBAAyB,aAAa,SAAS;CAErD,OAAO;EACL;EACA;EACA,kBAAkB,yBAAyB,aAAa,KAAK,OAAO,KAAK,UAAU,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI;EACtG,oBAAoB,aAAa,MAAM;EACvC,aAAa,aAAa,MAAM,OAAO,OAAO,qBAAqB;CACrE;AACF;;;;;AAMA,SAAgB,2BAA2B,MAA0C;CACnF,MAAM,eAAe,0BAA0B,IAAI,CAAC,EAAE,SAAS,KAAK,MAAM,EAAE,WAAW,KAAK,CAAC;CAC7F,MAAM,yBAAyB,aAAa,SAAS;CAErD,OAAO;EACL;EACA;EACA,kBAAkB,yBAAyB,aAAa,KAAK,OAAO,KAAK,UAAU,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI;EACtG,oBAAoB,aAAa,MAAM;EACvC,aAAa,aAAa,MAAM,OAAO,OAAO,qBAAqB;CACrE;AACF;AAgGA,SAAgB,uBAAuB,MAAiC;CACtE,MAAM,UAAU,mBAAmB,IAAI;CACvC,MAAM,WAAW,2BAA2B,IAAI;CAGhD,MAAM,aAAa;CAInB,MAAM,UAAU,CACd,QAAQ,yBAAyB,aAAa,QAAQ,qBAAqB,MAC3E,SAAS,yBAAyB,cAAc,SAAS,qBAAqB,IAChF,CAAC,CAAC,OAAO,OAAO;CAEhB,OAAO,QAAQ,SAAS,GAAG,WAAW,uBAAuB,QAAQ,KAAK,IAAI,EAAE,QAAQ;AAC1F;;;;AAsBA,SAAgB,iBAAiB,MAAwC;CACvE,MAAM,EAAE,MAAM,OAAO,WAAW,uBAAuB,IAAI;CAC3D,OAAO;EACL,MAAM,KAAK,SAAS;EACpB,OAAO,MAAM,SAAS;EACtB,MAAM,QAAQ,KAAK,aAAa,UAAU,EAAE,EAAE,MAAM;EACpD,SAAS,OAAO,SAAS;CAC3B;AACF;;;;;;AAmBA,SAAgB,2BAA2B,MAAkD;CAC3F,MAAM,SAAS,iBAAiB,IAAI;CACpC,MAAM,EAAE,MAAM,OAAO,WAAW,uBAAuB,IAAI;CAC3D,MAAM,kBAAkB,KAAK,MAAM,UAAU,MAAM,QAAQ;CAC3D,MAAM,mBAAmB,MAAM,MAAM,UAAU,MAAM,QAAQ;CAC7D,MAAM,oBAAoB,OAAO,MAAM,UAAU,MAAM,QAAQ;CAE/D,OAAO;EACL;EACA;EACA;EACA;EACA,YAAY,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,qBAAqB,CAAC,OAAO;CACrF;AACF;;;;;;;AAYA,SAAgB,4BACd,MACA,UACA,UAAwC,CAAC,GACK;CAC9C,MAAM,EAAE,iBAAiB,SAAS;CAClC,MAAM,EAAE,QAAQ,eAAe,2BAA2B,IAAI;CAE9D,MAAM,QAAS;EAAC;EAAQ;EAAS;EAAQ;CAAS,CAAC,CAAW,QAAQ,QAAQ,OAAO,IAAI;CAKzF,OAAO;EACL,WAAW,CAJM,MAAM,SAAS,IAAI,KAAK,MAAM,KAAK,IAAI,EAAE,MAAM,SAAS,yBAAyB,IAAI,IAAI,aAAa,UAAU,OAAO,MACtH,iBAAiB,WAAW,uBAAuB,IAAI,EAAE,SAAS,IAGjD,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,IAAI;EAC9D;CACF;AACF;AAmBA,SAAgB,uBAAuB,MAAyB,UAAuD,CAAC,GAA6B;CACnJ,MAAM,SAAS,WAAW,KAAK,YAAY,QAAQ,iBAAiB,aAAa,KAAA,IAAY,WAAW;CAExG,OAAO;EACL,MAAM,kBAAkB,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC;EACrE,OAAO,kBAAkB,OAAO,QAAQ,UAAU,MAAM,OAAO,OAAO,CAAC;EACvE,QAAQ,kBAAkB,OAAO,QAAQ,UAAU,MAAM,OAAO,QAAQ,CAAC;EACzE,QAAQ,kBAAkB,OAAO,QAAQ,UAAU,MAAM,OAAO,QAAQ,CAAC;CAC3E;AACF;AAEA,SAAgB,oBAAoB,YAA6D;CAC/F,MAAM,OAAO,OAAO,UAAU;CAE9B,OAAO,OAAO,MAAM,IAAI,IAAI,OAAO;AACrC;AAEA,SAAgB,oBAAoB,YAAuD;CACzF,MAAM,OAAO,oBAAoB,UAAU;CAE3C,OAAO,SAAS,QAAQ,QAAQ,OAAO,OAAO;AAChD;AAEA,SAAgB,kBAAkB,YAAuD;CACvF,MAAM,OAAO,oBAAoB,UAAU;CAE3C,OAAO,SAAS,QAAQ,QAAQ;AAClC;AAEA,SAAgB,oBAAoD,WAAuD;CACzH,OAAO,UAAU,QAAQ,aAAa,oBAAoB,SAAS,UAAU,CAAC;AAChF;AAEA,SAAgB,6BAA6B,MAAkD;CAC7F,OAAO,oBAAoB,KAAK,SAAS;AAC3C;AAEA,SAAgB,0BAA0B,MAAkD;CAC1F,OAAO,6BAA6B,IAAI,CAAC,CAAC,MAAM;AAClD;AAEA,SAAgB,kBAAkB,MAAyB,UAAgD;CACzG,OAAO,KAAK,UACT,QAAQ,aAAa,kBAAkB,SAAS,UAAU,CAAC,CAAC,CAC5D,KAAK,aAAa,SAAS,0BAA0B,MAAM,SAAS,UAAU,CAAC;AACpF;AAQA,SAAgB,uBAAuB,MAAyB,UAAgD;CAC9G,OAAO,KAAK,UAAU,KAAK,aAAa,SAAS,0BAA0B,MAAM,SAAS,UAAU,CAAC;AACvG;AAEA,MAAM,sCAAsB,IAAI,QAA0D;AAE1F,SAAgB,0BACd,MACA,UACA,UAA2C,CAAC,GAClC;CACV,MAAM,WAAW,GAAG,KAAK,YAAY,IAAI,QAAQ,gBAAgB,GAAG,IAAI,QAAQ,SAAS,GAAG,IAAI,QAAQ,uBAAuB,GAAG,IAAI,QAAQ,kBAAkB,QAAQ,aAAa,GAAG,KAAK,QAAQ,WAAW,CAAC,EAAA,CAAG,KAAK,GAAG;CAC5N,IAAI,aAAa,oBAAoB,IAAI,QAAQ;CACjD,IAAI,YAAY;EACd,MAAM,SAAS,WAAW,IAAI,QAAQ;EACtC,IAAI,QAAQ,OAAO;CACrB,OAAO;EACL,6BAAa,IAAI,IAAI;EACrB,oBAAoB,IAAI,UAAU,UAAU;CAC9C;CAEA,MAAM,EAAE,MAAM,OAAO,WAAW,uBAAuB,MAAM,EAAE,cAAc,QAAQ,aAAa,CAAC;CACnG,MAAM,sBACJ,QAAQ,wBAAwB,UAC5B,kBAAkB,MAAM,QAAQ,IAChC,QAAQ,wBAAwB,QAC9B,CAAC,IACD,uBAAuB,MAAM,QAAQ;CAC7C,MAAM,UAAU,IAAI,IAAI,QAAQ,WAAW,CAAC,CAAC;CAC7C,MAAM,aACJ,QAAQ,kBAAkB,QACtB,CAAC,IACD;EACE,GAAG,KAAK,KAAK,UAAU,SAAS,sBAAsB,MAAM,KAAK,CAAC;EAClE,GAAG,MAAM,KAAK,UAAU,SAAS,uBAAuB,MAAM,KAAK,CAAC;EACpE,GAAG,OAAO,KAAK,UAAU,SAAS,wBAAwB,MAAM,KAAK,CAAC;CACxE;CACN,MAAM,uBAAuB,CAAC,KAAK,aAAa,UAAU,EAAE,EAAE,SAAS,SAAS,gBAAgB,IAAI,IAAI,MAAM,SAAS,oBAAoB,IAAI,CAAC;CAMhJ,MAAM,UAJJ,QAAQ,UAAU,wBACd;EAAC,GAAG;EAAsB,GAAG;EAAY,GAAG;CAAmB,IAC/D;EAAC,GAAG;EAAY,GAAG;EAAsB,GAAG;CAAmB,EAAA,CAEhD,QAAQ,SAAyB,QAAQ,IAAI,KAAK,CAAC,QAAQ,IAAI,IAAc,CAAC;CACnG,WAAW,IAAI,UAAU,MAAM;CAC/B,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;ACndA,SAAgB,kBAAkB,OAAwC;CACxE,IAAI,CAAC,OACH,OAAO;CAGT,MAAM,eAAe,QAAmC;EACtD,IAAI,MAAM,SAAS,QACjB,OAAO,GAAG,IAAI,MAAM,MAAM,GAAG,CAAC,CAAC;EAGjC,OAAO,UAAU,IAAI,KAAK;CAC5B;CAEA,OAAO;EACL,GAAG;EACH,MAAM,MAAM,OAAO,MAAM,OAAO;CAClC;AACF;;;ACfA,SAAgB,QAAQ,EAAE,UAAU,IAAI,MAAM,UAAU,QAA8B;CACpF,IAAI,CAAC,IAAI,oBAAoB,IAAI,GAAG,OAAO;CAE3C,MAAM,EAAE,OAAO,qBAAqB,QAAQ,yBAAyB,uBAAuB,MAAM,EAAE,cAAc,WAAW,CAAC;CAC9H,MAAM,EAAE,OAAO,kBAAkB,QAAQ,sBAAsB,uBAAuB,IAAI;CAE1F,MAAM,qBAAqB,mBAAmB,qBAAqB,gBAAgB;CACnF,MAAM,sBAAsB,mBAAmB,sBAAsB,iBAAiB;CAEtF,MAAM,EAAE,WAAW,WAAW,4BAA4B,MAAM,UAAU,EAAE,gBAAgB,MAAM,CAAC;CACnG,MAAM,kBAAkB,CAAC,WAAW,+CAA+C,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,IAAI;CAE9G,MAAM,eAAe,SAAS,oBAAoB,IAAI;CACtD,MAAM,aAAa,qBAAqB,aAAa;CAGrD,MAAM,cAAc,IAAI,wBAAwB,KAAK,MAAM,EAAE,QAAQ,QAAQ,CAAC;CAE9E,MAAM,iBAAgC,CAAC,YAAY,KAAK,OAAO,IAAI,QAAQ,aAAa;CAExF,IAAI,OAAO,OACT,eAAe,KAAK,qBAAqB,OAAO,2BAA2B;EAAE,QAAQ;EAAS,SAAS;CAAmB,CAAC,MAAM,WAAW;CAG9I,IAAI,OAAO,SACT,eAAe,KAAK,sBAAsB,YAAY,2BAA2B;EAAE,QAAQ;EAAW,SAAS;CAAoB,CAAC,MAAM,SAAS;CAGrJ,IAAI,OAAO,MACT,eAAe,KAAK,MAAM;CAG5B,eAAe,KAAK,YAAY;CAEhC,MAAM,cAAc,qBAAqB,aAAa;IACpD,eAAe,KAAK,OAAO,EAAE;;CAG/B,OACE,oBAAC,KAAK,QAAN;EAAmB;EAAM,aAAA;EAAY,cAAA;YACnC,oBAAC,UAAD;GAAgB;GAAM,QAAA;GAAO,QAAQ;GAA6B;aAC/D;EACO,CAAA;CACC,CAAA;AAEjB;;;;;;;;ACxDA,MAAa,mBAAmB,gBAA+B;CAC7D,MAAM;CACN,UAAU;CACV,UAAU,MAAM,KAAK;EACnB,IAAI,CAAC,IAAI,oBAAoB,IAAI,GAAG,OAAO;EAC3C,MAAM,EAAE,QAAQ,UAAU,QAAQ,SAAS;EAC3C,MAAM,EAAE,QAAQ,SAAS,UAAU,IAAI;EAEvC,MAAM,WAAW,OAAO,UAAU,YAAY;EAE9C,IAAI,CAAC,UACH,OAAO;EAGT,MAAM,aAAa,OAAO,YAAY,YAAY;EAElD,MAAM,oBAAoB,CAAC,WAAW,yBAAyB,IAAI,GAAG,GAAG,0BAA0B,MAAM,YAAY,EAAE,eAAe,MAAM,CAAC,CAAC;EAE9I,MAAM,OAAO;GACX,MAAM,SAAS,YAAY,KAAK,WAAW;GAC3C,MAAM,SAAS,YACb;IAAE,MAAM,KAAK;IAAa,SAAS;IAAO,KAAK,KAAK,KAAK,MAAM;IAAW,MAAM,KAAK;GAAK,GAC1F;IAAE;IAAM;IAAQ,OAAO,SAAS,KAAA;GAAU,CAC5C;GACA,QAAQ,WAAW,YACjB;IAAE,MAAM,KAAK;IAAa,SAAS;IAAO,KAAK,KAAK,KAAK,MAAM;IAAW,MAAM,KAAK;GAAK,GAC1F;IACE;IACA,QAAQ,SAAS,SAAS,UAAU;IACpC,OAAO,SAAS,SAAS,SAAS,KAAA;GACpC,CACF;EACF;EAEA,OACE,qBAAC,MAAD;GACE,UAAU,KAAK,KAAK;GACpB,MAAM,KAAK,KAAK;GAChB,MAAM,KAAK,KAAK;GAChB,QAAQ,SAAS,cAAc,IAAI,MAAM;IAAE;IAAQ;IAAQ,MAAM;KAAE,MAAM,KAAK,KAAK;KAAM,UAAU,KAAK,KAAK;IAAS;GAAE,CAAC;GACzH,QAAQ,SAAS,cAAc,IAAI,MAAM;IAAE;IAAQ;IAAQ,MAAM;KAAE,MAAM,KAAK,KAAK;KAAM,UAAU,KAAK,KAAK;IAAS;GAAE,CAAC;aAL3H,CAOG,KAAK,UAAU,kBAAkB,SAAS,KAAK,oBAAC,KAAK,QAAN;IAAa,MAAM;IAAmB,MAAM,KAAK,KAAK;IAAM,MAAM,KAAK,OAAO;IAAM,YAAA;GAAY,CAAA,GAChJ,oBAAC,SAAD;IAAS,MAAM,KAAK;IAAY;IAAM,UAAU;IAAqB;GAAU,CAAA,CAC3E;;CAEV;AACF,CAAC;;;;;;;;;;;;;;;AC3CD,MAAa,kBAAkB,sBAAqC;CAClE,MAAM;CACN,YAAY;CACZ,QAAQ,MAAM,MAAM;EAClB,OAAO,SAAS,SAAS,WAAW,IAAI,IAAI,UAAU,IAAI;CAC5D;CACA,YAAY,MAAM;EAChB,OAAO,KAAK,QAAQ,MAAM,UAAU;CACtC;CACA,gBAAgB,MAAM,MAAM;EAC1B,OAAO,KAAK,QAAQ,MAAM,IAAI;CAChC;AACF,EAAE;;;;;;;ACjBF,MAAa,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;AAyBjC,MAAa,gBAAgB,cAA6B,YAAY;CACpE,MAAM,EACJ,SAAS;EAAE,MAAM;EAAW,QAAQ,EAAE,MAAM,QAAQ;CAAE,GACtD,OACA,UAAU,CAAC,GACX,SACA,WAAW,CAAC,GACZ,SACA,UAAU,cACV,QAAQ,eACN;CAEJ,MAAM,cAAc,kBAAkB,KAAK;CAE3C,OAAO;EACL,MAAM;EACN;EACA,cAAc,CAAC,YAAY;EAC3B,OAAO,EACL,oBAAoB,KAAK;GACvB,MAAM,WAAW,eAAe;IAAE,GAAG;IAAiB,GAAG;GAAa,IAAI;GAE1E,IAAI,WAAW;IACb;IACA;IACA;IACA;IACA,OAAO;IACP;IACA;GACF,CAAC;GACD,IAAI,YAAY,QAAQ;GACxB,IAAI,YAAY,QACd,IAAI,UAAU,UAAU;GAE1B,IAAI,aAAa,gBAAgB;EACnC,EACF;CACF;AACF,CAAC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/reserved.ts","../../../internals/utils/src/url.ts","../../../internals/shared/src/params.ts","../../../internals/shared/src/operation.ts","../../../internals/shared/src/group.ts","../src/components/Request.tsx","../src/generators/cypressGenerator.tsx","../src/resolvers/resolverCypress.ts","../src/plugin.ts"],"sourcesContent":["type Options = {\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n return text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n .split(/[\\s\\-_./\\\\:]+/)\n .filter(Boolean)\n .map((word, i) => {\n if (word.length > 1 && word === word.toUpperCase()) return word\n const head = i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()\n return head + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Converts `text` to camelCase.\n *\n * @example Word boundaries\n * `camelCase('hello-world') // 'helloWorld'`\n *\n * @example With a prefix\n * `camelCase('tag', { prefix: 'create' }) // 'createTag'`\n */\nexport function camelCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n *\n * @example Word boundaries\n * `pascalCase('hello-world') // 'HelloWorld'`\n *\n * @example With a suffix\n * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`\n */\nexport function pascalCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n\n/**\n * Converts `text` to snake_case.\n *\n * @example From camelCase\n * `snakeCase('helloWorld') // 'hello_world'`\n *\n * @example From mixed separators\n * `snakeCase('Hello-World') // 'hello_world'`\n */\nexport function snakeCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n const processed = `${prefix} ${text} ${suffix}`.trim()\n return processed\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s\\-.]+/g, '_')\n .replace(/[^a-zA-Z0-9_]/g, '')\n .toLowerCase()\n .split('_')\n .filter(Boolean)\n .join('_')\n}\n\n/**\n * Converts `text` to SCREAMING_SNAKE_CASE.\n *\n * @example From camelCase\n * `screamingSnakeCase('helloWorld') // 'HELLO_WORLD'`\n */\nexport function screamingSnakeCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return snakeCase(text, { prefix, suffix }).toUpperCase()\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return isIdentifier(name)\n}\n\n/**\n * Returns `name` when it's a syntactically valid JavaScript variable name,\n * otherwise prefixes it with `_` so the result is a valid identifier.\n *\n * Useful for sanitizing OpenAPI schema names or operation IDs that start with\n * a digit (e.g. `409`, `504AccountCancel`) before using them as exported\n * variable, type, or function names.\n *\n * @example\n * ```ts\n * ensureValidVarName('409') // '_409'\n * ensureValidVarName('504AccountCancel') // '_504AccountCancel'\n * ensureValidVarName('Pet') // 'Pet'\n * ensureValidVarName('class') // '_class'\n * ```\n */\nexport function ensureValidVarName(name: string): string {\n if (!name || isValidVarName(name)) {\n return name\n }\n return `_${name}`\n}\n\n/**\n * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.\n *\n * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys\n * even though they are not valid variable names, so use this (not {@link isValidVarName}) when\n * deciding whether an object key needs quoting.\n *\n * @example\n * ```ts\n * isIdentifier('name') // true\n * isIdentifier('x-total')// false\n * ```\n */\nexport function isIdentifier(name: string): boolean {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n","import { camelCase } from './casing.ts'\nimport { isValidVarName } from './reserved.ts'\n\nexport type URLObject = {\n /**\n * The resolved URL string (Express-style or template literal, depending on context).\n */\n url: string\n /**\n * Extracted path parameters as a key-value map, or `null` when the path has none.\n */\n params: Record<string, string> | null\n}\n\n/**\n * Supported identifier casing strategies for path parameters.\n */\nexport type PathCasing = 'camelcase'\n\ntype TemplateOptions = {\n /**\n * Literal text prepended inside the template literal, e.g. a base URL.\n */\n prefix?: string | null\n /**\n * Transform applied to each extracted parameter name before interpolation.\n */\n replacer?: (pathParam: string) => string\n /**\n * Casing strategy applied to path parameter names.\n */\n casing?: PathCasing\n}\n\ntype ObjectOptions = {\n /**\n * Controls whether the `url` is rendered as an Express path or a template literal.\n * @default 'path'\n */\n type?: 'path' | 'template'\n /**\n * Transform applied to each extracted parameter name.\n */\n replacer?: (pathParam: string) => string\n /**\n * When `true`, the result is serialized to a string expression instead of a plain object.\n */\n stringify?: boolean\n /**\n * Casing strategy applied to path parameter names.\n */\n casing?: PathCasing\n}\n\nfunction transformParam(raw: string, casing?: PathCasing): string {\n const param = isValidVarName(raw) ? raw : camelCase(raw)\n return casing === 'camelcase' ? camelCase(param) : param\n}\n\nfunction toParamsObject(\n path: string,\n { replacer, casing }: { replacer?: (pathParam: string) => string; casing?: PathCasing } = {},\n): Record<string, string> | null {\n const params: Record<string, string> = {}\n\n for (const match of path.matchAll(/\\{([^}]+)\\}/g)) {\n const param = transformParam(match[1]!, casing)\n const key = replacer ? replacer(param) : param\n params[key] = key\n }\n\n return Object.keys(params).length > 0 ? params : null\n}\n\n/**\n * Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.\n */\nexport class Url {\n /**\n * Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.\n *\n * @example\n * Url.canParse('https://petstore.swagger.io/v2') // true\n * Url.canParse('/pet/{petId}') // false\n */\n static canParse(url: string, base?: string | URL): boolean {\n return URL.canParse(url, base)\n }\n\n /**\n * Converts an OpenAPI/Swagger path to Express-style colon syntax.\n *\n * @example\n * Url.toPath('/pet/{petId}') // '/pet/:petId'\n */\n static toPath(path: string): string {\n return path.replace(/\\{([^}]+)\\}/g, ':$1')\n }\n\n /**\n * Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`\n * literal aligns with the grouped `path` request option that the runtime client interpolates by\n * key.\n *\n * @example\n * Url.toCasedTemplate('/projects/{project_id}', { casing: 'camelcase' }) // '/projects/{projectId}'\n */\n static toCasedTemplate(path: string, { casing }: { casing?: PathCasing } = {}): string {\n return path.replace(/\\{([^}]+)\\}/g, (_, name: string) => `{${transformParam(name, casing)}}`)\n }\n\n /**\n * Converts an OpenAPI/Swagger path to a TypeScript template literal string.\n * `prefix` is prepended inside the literal, `replacer` transforms each parameter name,\n * and `casing` controls parameter identifier casing.\n *\n * @example\n * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'\n *\n * @example\n * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'\n */\n static toTemplateString(path: string, { prefix, replacer, casing }: TemplateOptions = {}): string {\n const parts = path.split(/\\{([^}]+)\\}/)\n const result = parts\n .map((part, i) => {\n if (i % 2 === 0) return part\n const param = transformParam(part, casing)\n return `\\${${replacer ? replacer(param) : param}}`\n })\n .join('')\n\n return `\\`${prefix ?? ''}${result}\\``\n }\n\n /**\n * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the\n * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter\n * names are camelCased to match the generated `path` type, and `prefix` is prepended inside the\n * literal. Shared by the client and cypress generators that pass a grouped `path` object.\n *\n * @example\n * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'\n */\n static toGroupedTemplateString(path: string, { prefix }: { prefix?: string | null } = {}): string {\n return Url.toTemplateString(path, { prefix, casing: 'camelcase', replacer: (name) => `path.${name}` })\n }\n\n /**\n * Returns the path and its extracted params as a structured `URLObject`, or as a stringified\n * expression when `stringify` is set.\n *\n * @example\n * Url.toObject('/pet/{petId}')\n * // { url: '/pet/:petId', params: { petId: 'petId' } }\n */\n static toObject(path: string, { type = 'path', replacer, stringify, casing }: ObjectOptions = {}): URLObject | string {\n const object: URLObject = {\n url: type === 'path' ? Url.toPath(path) : Url.toTemplateString(path, { replacer, casing }),\n params: toParamsObject(path, { replacer, casing }),\n }\n\n if (stringify) {\n if (type === 'template') {\n return JSON.stringify(object).replaceAll(\"'\", '').replaceAll(`\"`, '')\n }\n\n if (object.params) {\n return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll(\"'\", '').replaceAll(`\"`, '')} }`\n }\n\n return `{ url: '${object.url}' }`\n }\n\n return object\n }\n}\n","import { camelCase, isValidVarName } from '@internals/utils'\nimport type { ast } from 'kubb/kit'\n\nconst caseParamsCache = new WeakMap<Array<ast.ParameterNode>, Array<ast.ParameterNode>>()\n\n/**\n * Applies camelCase to parameter names and returns a new array without mutating the input.\n *\n * Run it before handing parameters to schema builders so output property keys get the right casing\n * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the\n * original array is returned unchanged. Results are cached per input array.\n */\nexport function caseParams(params: Array<ast.ParameterNode>, casing: 'camelcase' | undefined): Array<ast.ParameterNode> {\n if (!casing) return params\n\n const cached = caseParamsCache.get(params)\n if (cached) return cached\n\n const result = params.map((param) => ({ ...param, name: camelCase(param.name) }))\n caseParamsCache.set(params, result)\n return result\n}\n\n/**\n * Drops parameters that collapse to the same property identity once camelCased, keeping the first.\n *\n * Some specs declare the same parameter twice under different casings (for example AWS S3 lists both\n * `max-uploads` and `MaxUploads`). Both resolve to one output property, so emitting both would yield\n * an object type with a duplicate member, which TypeScript rejects. De-duplicate by the camelCased\n * identity so the resulting group is collision-free regardless of the names each caller carries.\n */\nexport function dedupeByCasedName(params: Array<ast.ParameterNode>): Array<ast.ParameterNode> {\n const seen = new Set<string>()\n\n return params.filter((param) => {\n const key = camelCase(param.name)\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\nexport function buildParamsMapping<TParam extends { name: string }>(\n originalParams: ReadonlyArray<TParam>,\n mappedParams: ReadonlyArray<TParam>,\n): Record<string, string> | null {\n const mapping: Record<string, string> = {}\n let hasChanged = false\n\n originalParams.forEach((param, i) => {\n const mappedName = mappedParams[i]?.name ?? param.name\n mapping[param.name] = mappedName\n\n if (param.name !== mappedName) {\n hasChanged = true\n }\n })\n\n return hasChanged ? mapping : null\n}\n\nexport function buildTransformedParamsMapping<TParam extends { name: string }>(\n params: ReadonlyArray<TParam>,\n transformName: (name: string) => string,\n): Record<string, string> | null {\n if (!params.length) {\n return null\n }\n\n return buildParamsMapping(\n params,\n params.map((param) => ({ ...param, name: transformName(param.name) })),\n )\n}\n\nfunction toAccess(object: string, name: string): string {\n return isValidVarName(name) ? `${object}.${name}` : `${object}[${JSON.stringify(name)}]`\n}\n\n/**\n * Renders the object-literal expression that renames the camelCased keys of a grouped request\n * option back to the names the OpenAPI document declares, guarded so an omitted optional group\n * stays omitted. Shared by the client and cypress generators, which pass a `buildParamsMapping`\n * result and the source expression to read the keys from.\n *\n * @example\n * ```ts\n * buildParamsRemapExpression({ source: 'config.query', mapping: { include_deleted: 'includeDeleted' } })\n * // 'config.query ? { \"include_deleted\": config.query.includeDeleted } : config.query'\n * ```\n */\nexport function buildParamsRemapExpression({ source, mapping }: { source: string; mapping: Record<string, string> }): string {\n const pairs = Object.entries(mapping)\n .map(([originalName, casedName]) => `${JSON.stringify(originalName)}: ${toAccess(source, casedName)}`)\n .join(', ')\n\n return `${source} ? { ${pairs} } : ${source}`\n}\n","import { Url } from '@internals/utils'\nimport { ast, type ResolverFileParams } from 'kubb/kit'\nimport { caseParams, dedupeByCasedName } from './params.ts'\n\n/**\n * Builds the `ResolverFileParams` every operation generator passes to\n * `resolver.file`: a file named `name`, tagged by the operation's first\n * tag (or `'default'`), at the operation's path. Centralizes the entry object\n * that was repeated at dozens of call sites across the client and query plugins.\n *\n * @example\n * ```ts\n * resolver.file(operationFileEntry(node, node.operationId), { root, output, group })\n * ```\n */\nexport function operationFileEntry(node: ast.OperationNode, name: string, extname: ResolverFileParams['extname'] = '.ts'): ResolverFileParams {\n return {\n name,\n extname,\n tag: node.tags[0] ?? 'default',\n path: node.path,\n }\n}\n\nexport type ContentTypeInfo = {\n contentTypes: string[]\n isMultipleContentTypes: boolean\n contentTypeUnion: string\n defaultContentType: string\n hasFormData: boolean\n}\n\nexport type RequestConfigResolver = {\n response: {\n body(node: ast.OperationNode): string\n }\n}\n\nexport type ResponseStatusNameResolver = {\n response: {\n status(node: ast.OperationNode, statusCode: ast.StatusCode): string\n }\n}\n\nexport type ResponseNameResolver = ResponseStatusNameResolver & {\n response: {\n response(node: ast.OperationNode): string\n }\n}\n\nexport type OperationTypeNameResolver = RequestConfigResolver &\n ResponseNameResolver & {\n param: {\n path(node: ast.OperationNode, param: ast.ParameterNode): string\n query(node: ast.OperationNode, param: ast.ParameterNode): string\n headers(node: ast.OperationNode, param: ast.ParameterNode): string\n }\n }\n\n/**\n * Resolver interface for building operation parameters.\n *\n * `ResolverTs` from `@kubb/plugin-ts` satisfies this interface and can be passed directly.\n */\nexport type OperationParamsResolver = {\n /**\n * Naming for an operation's parameters, grouped by location.\n */\n param: {\n /**\n * Resolves the type name for an individual parameter.\n *\n * @example Individual path parameter name\n * `resolver.param.name(node, param) // → 'DeletePetPathPetId'`\n */\n name(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the grouped path parameters type name.\n * When the return value equals `resolver.param.name`, no indexed access is emitted.\n *\n * @example Grouped path params type name\n * `resolver.param.path(node, param) // → 'DeletePetPath'`\n */\n path(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the grouped query parameters type name.\n * When the return value equals `resolver.param.name`, an inline struct type is emitted instead.\n *\n * @example Grouped query params type name\n * `resolver.param.query(node, param) // → 'FindPetsByStatusQuery'`\n */\n query(node: ast.OperationNode, param: ast.ParameterNode): string\n /**\n * Resolves the grouped header parameters type name.\n * When the return value equals `resolver.param.name`, an inline struct type is emitted instead.\n *\n * @example Grouped header params type name\n * `resolver.param.headers(node, param) // → 'DeletePetHeaders'`\n */\n headers(node: ast.OperationNode, param: ast.ParameterNode): string\n }\n /**\n * Naming for an operation's request and response types.\n */\n response: {\n /**\n * Resolves the request body type name.\n *\n * @example Request body type name\n * `resolver.response.body(node) // → 'CreatePetBody'`\n */\n body(node: ast.OperationNode): string\n }\n}\n\nexport type OperationCommentLink = 'pathTemplate' | 'urlPath' | false | ((node: ast.OperationNode) => string | undefined)\n\nexport type BuildOperationCommentsOptions = {\n link?: OperationCommentLink\n linkPosition?: 'beforeDeprecated' | 'afterDeprecated'\n splitLines?: boolean\n}\n\ntype ResponseLike = {\n statusCode: ast.StatusCode | number | string\n}\n\nexport type OperationParameterGroups = Record<ast.ParameterNode['in'], Array<ast.ParameterNode>>\n\nexport type ResolveOperationTypeNameOptions = {\n paramsCasing?: 'camelcase' | 'original'\n responseStatusNames?: boolean | 'error'\n exclude?: ReadonlyArray<string | undefined>\n order?: 'params-first' | 'body-response-first'\n /**\n * Include the individual `Path`/`Query`/`Headers` group type names. Set to `false` for clients\n * that reference the grouped `Options` type instead of the per-group types.\n */\n includeParams?: boolean\n}\n\nfunction getOperationLink(node: ast.OperationNode, link: OperationCommentLink): string | null {\n if (!link) {\n return null\n }\n\n if (typeof link === 'function') {\n return link(node) ?? null\n }\n\n if (link === 'urlPath') {\n return node.path ? `{@link ${Url.toPath(node.path)}}` : null\n }\n\n return node.path ? `{@link ${node.path.replaceAll('{', ':').replaceAll('}', '')}}` : null\n}\n\n/**\n * Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several\n * are present and the union, default, and form-data flags the client uses to pick one.\n */\nfunction buildContentTypeInfo(contentTypes: string[]): ContentTypeInfo {\n const isMultipleContentTypes = contentTypes.length > 1\n\n return {\n contentTypes,\n isMultipleContentTypes,\n contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(' | ') : '',\n defaultContentType: contentTypes[0] ?? 'application/json',\n hasFormData: contentTypes.some((ct) => ct === 'multipart/form-data'),\n }\n}\n\nexport function getContentTypeInfo(node: ast.OperationNode): ContentTypeInfo {\n return buildContentTypeInfo(node.requestBody?.content?.map((e) => e.contentType) ?? [])\n}\n\n/**\n * The request-body counterpart for the primary success response: the content types it documents and\n * whether several are present, so the client can let a caller pick which one to accept.\n */\nexport function getResponseContentTypeInfo(node: ast.OperationNode): ContentTypeInfo {\n return buildContentTypeInfo(getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? [])\n}\n\nexport type ResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n\n/**\n * Reads the single base content type of an operation's primary success response, lowercased and\n * stripped of any `; charset=...` suffix. Returns `undefined` when the response declares zero or\n * more than one content type, since neither case has a single type to act on.\n */\nfunction getPrimarySuccessContentType(node: ast.OperationNode): string | undefined {\n const contentTypes = getPrimarySuccessResponse(node)?.content?.map((entry) => entry.contentType) ?? []\n if (contentTypes.length !== 1) return undefined\n return contentTypes[0]!.split(';')[0]!.trim().toLowerCase()\n}\n\n/**\n * Whether an operation streams its primary success response as Server-Sent Events\n * (`text/event-stream`). The client generator uses this to return a typed event stream instead of a\n * one-shot `RequestResult`.\n */\nexport function isEventStream(node: ast.OperationNode): boolean {\n return getPrimarySuccessContentType(node) === 'text/event-stream'\n}\n\n/**\n * Derives the default `responseType` for an operation from its primary success response.\n *\n * Returns a value only when that response declares a single non-JSON content type. `text/event-stream`\n * and other binary types (`application/octet-stream`, `application/pdf`, `image/*`, `audio/*`,\n * `video/*`) map to a stream or `'blob'`, and other `text/*` maps to `'text'`. Otherwise `undefined`,\n * leaving the runtime client's `Content-Type` auto-detection in charge.\n */\nexport function getResponseType(node: ast.OperationNode): ResponseType | undefined {\n const baseType = getPrimarySuccessContentType(node)\n if (!baseType) return undefined\n\n if (baseType === 'application/json' || baseType.endsWith('+json') || baseType === 'text/json') return undefined\n if (baseType === 'text/event-stream') return 'stream'\n if (baseType.startsWith('text/')) return 'text'\n if (baseType === 'application/octet-stream' || baseType === 'application/pdf' || /^(image|audio|video)\\//.test(baseType)) return 'blob'\n return undefined\n}\n\n/**\n * Maps a content type to the PascalCase suffix used to name per-content-type variants\n * (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).\n */\nfunction getContentTypeSuffix(contentType: string): string {\n const baseType = contentType.split(';')[0]!.trim()\n if (baseType === 'application/json') return 'Json'\n if (baseType === 'multipart/form-data') return 'FormData'\n if (baseType === 'application/x-www-form-urlencoded') return 'FormUrlEncoded'\n const subtype = baseType.split('/').pop() ?? baseType\n const parts = subtype.split(/[^a-zA-Z0-9]+/).filter(Boolean)\n if (parts.length === 0) return 'Unknown'\n return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('')\n}\n\n/**\n * Appends a content-type suffix to a base name, keeping a trailing `Data` segment last\n * (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).\n */\nexport function getPerContentTypeName(baseName: string, suffix: string): string {\n if (baseName.endsWith('Data')) {\n return suffix.endsWith('Data') ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`\n }\n return baseName + suffix\n}\n\nexport type ContentVariantInput = { contentType: string; schema?: ast.SchemaNode | null; keysToOmit?: Array<string> | null }\nexport type ContentVariant = { name: string; suffix: string; schema: ast.SchemaNode; keysToOmit?: Array<string> | null; contentType: string }\n\n/**\n * Resolves per-content-type variant names for a set of content entries, deduplicating suffix\n * collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is\n * the final (possibly counter-augmented) value, so callers can derive parallel names in another\n * namespace (e.g. plugin-faker deriving the matching plugin-ts type name).\n */\nexport function resolveContentTypeVariants(entries: Array<ContentVariantInput>, baseName: string): Array<ContentVariant> {\n const usedNames = new Set<string>()\n return entries\n .filter((entry) => entry.schema)\n .map((entry) => {\n const baseSuffix = getContentTypeSuffix(entry.contentType)\n let suffix = baseSuffix\n let name = getPerContentTypeName(baseName, suffix)\n let counter = 2\n while (usedNames.has(name)) {\n suffix = `${baseSuffix}${counter++}`\n name = getPerContentTypeName(baseName, suffix)\n }\n usedNames.add(name)\n return { name, suffix, schema: entry.schema!, keysToOmit: entry.keysToOmit, contentType: entry.contentType }\n })\n}\n\nexport function buildRequestConfigType(node: ast.OperationNode): string {\n const request = getContentTypeInfo(node)\n const response = getResponseContentTypeInfo(node)\n // The request groups come from the grouped params, so `config` drops the data-shape keys to stay\n // assignable to `Options`, which omits them from `RequestConfig`.\n const configType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n\n // Only the ambiguous side is offered: a single-type side has nothing to pick, so it stays baked in\n // the generated call.\n const members = [\n request.isMultipleContentTypes ? `request?: ${request.contentTypeUnion}` : null,\n response.isMultipleContentTypes ? `response?: ${response.contentTypeUnion}` : null,\n ].filter(Boolean)\n\n return members.length ? `${configType} & { contentType?: { ${members.join('; ')} } }` : configType\n}\n\n/**\n * Builds the `client?:` option type shared by the generated query hooks (`useQuery`,\n * `useInfiniteQuery`, `useSWR`, ...). Unlike {@link buildRequestConfigType}, it never adds a\n * `contentType?:` member: query hooks wrap GET operations, which carry no request body to select a\n * content type for.\n */\nexport function buildClientOptionType(): string {\n return `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n}\n\nexport type RequestGroups = {\n path: boolean\n query: boolean\n body: boolean\n headers: boolean\n}\n\n/**\n * Which of the grouped request options an operation carries.\n */\nexport function getRequestGroups(node: ast.OperationNode): RequestGroups {\n const { path, query, header } = getOperationParameters(node)\n return {\n path: path.length > 0,\n query: query.length > 0,\n body: Boolean(node.requestBody?.content?.[0]?.schema),\n headers: header.length > 0,\n }\n}\n\nexport type RequestGroupOptionality = {\n groups: RequestGroups\n hasRequiredPath: boolean\n hasRequiredQuery: boolean\n hasRequiredHeader: boolean\n /**\n * Whether the grouped request parameter can default to `{}`. True only when no group carries a\n * required member, so every member is safe to omit.\n */\n isOptional: boolean\n}\n\n/**\n * Resolves which grouped request options an operation carries together with whether each group\n * holds a required member. The grouped parameter stays optional only when nothing inside it is\n * required, matching the generated `RequestConfig` type.\n */\nexport function getRequestGroupOptionality(node: ast.OperationNode): RequestGroupOptionality {\n const groups = getRequestGroups(node)\n const { path, query, header } = getOperationParameters(node)\n const hasRequiredPath = path.some((param) => param.required)\n const hasRequiredQuery = query.some((param) => param.required)\n const hasRequiredHeader = header.some((param) => param.required)\n\n return {\n groups,\n hasRequiredPath,\n hasRequiredQuery,\n hasRequiredHeader,\n isOptional: !hasRequiredPath && !hasRequiredQuery && !hasRequiredHeader && !groups.body,\n }\n}\n\nexport type RequestOptionsNameResolver = RequestConfigResolver & {\n response: {\n options(node: ast.OperationNode): string\n }\n}\n\n/**\n * Builds the grouped `{ path, query, body, headers }` parameter for a generated client\n * function, typed from the operation's `Options` (minus `url`). Only the groups the\n * operation actually has are destructured. The trailing `config` parameter carries the\n * runtime `RequestConfig` overrides plus `client`.\n */\nexport function buildRequestParamsSignature(\n node: ast.OperationNode,\n resolver: RequestOptionsNameResolver,\n options: { isConfigurable?: boolean } = {},\n): { signature: string; groups: RequestGroups } {\n const { isConfigurable = true } = options\n const { groups, isOptional } = getRequestGroupOptionality(node)\n\n const names = (['path', 'query', 'body', 'headers'] as const).filter((key) => groups[key])\n\n const firstParam = names.length > 0 ? `{ ${names.join(', ')} }: ${resolver.response.options(node)}${isOptional ? ' = {}' : ''}` : null\n const configParam = isConfigurable ? `config: ${buildRequestConfigType(node)} = {}` : null\n\n return {\n signature: [firstParam, configParam].filter(Boolean).join(', '),\n groups,\n }\n}\n\nexport function buildOperationComments(node: ast.OperationNode, options: BuildOperationCommentsOptions = {}): Array<string> {\n const { link = 'pathTemplate', linkPosition = 'afterDeprecated', splitLines = false } = options\n const linkComment = getOperationLink(node, link)\n const comments =\n linkPosition === 'beforeDeprecated'\n ? [node.description && `@description ${node.description}`, node.summary && `@summary ${node.summary}`, linkComment, node.deprecated && '@deprecated']\n : [node.description && `@description ${node.description}`, node.summary && `@summary ${node.summary}`, node.deprecated && '@deprecated', linkComment]\n\n const filteredComments = comments.filter((comment): comment is string => Boolean(comment))\n\n if (!splitLines) {\n return filteredComments\n }\n\n return filteredComments.flatMap((text) => text.split(/\\r?\\n/).map((line) => line.trim())).filter((comment): comment is string => Boolean(comment))\n}\n\nexport function getOperationParameters(node: ast.OperationNode, options: { paramsCasing?: 'camelcase' | 'original' } = {}): OperationParameterGroups {\n const params = caseParams(node.parameters, options.paramsCasing === 'original' ? undefined : 'camelcase')\n\n return {\n path: dedupeByCasedName(params.filter((param) => param.in === 'path')),\n query: dedupeByCasedName(params.filter((param) => param.in === 'query')),\n header: dedupeByCasedName(params.filter((param) => param.in === 'header')),\n cookie: dedupeByCasedName(params.filter((param) => param.in === 'cookie')),\n }\n}\n\nexport function getStatusCodeNumber(statusCode: ast.StatusCode | number | string): number | null {\n const code = Number(statusCode)\n\n return Number.isNaN(code) ? null : code\n}\n\nexport function isSuccessStatusCode(statusCode: ast.StatusCode | number | string): boolean {\n const code = getStatusCodeNumber(statusCode)\n\n return code !== null && code >= 200 && code < 300\n}\n\nexport function isErrorStatusCode(statusCode: ast.StatusCode | number | string): boolean {\n const code = getStatusCodeNumber(statusCode)\n\n return code !== null && code >= 400\n}\n\nexport function getSuccessResponses<TResponse extends ResponseLike>(responses: ReadonlyArray<TResponse>): Array<TResponse> {\n return responses.filter((response) => isSuccessStatusCode(response.statusCode))\n}\n\nexport function getOperationSuccessResponses(node: ast.OperationNode): Array<ast.ResponseNode> {\n return getSuccessResponses(node.responses)\n}\n\nexport function getPrimarySuccessResponse(node: ast.OperationNode): ast.ResponseNode | null {\n return getOperationSuccessResponses(node)[0] ?? null\n}\n\nexport function resolveErrorNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.response.status(node, response.statusCode))\n}\n\nexport function resolveSuccessNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses.filter((response) => isSuccessStatusCode(response.statusCode)).map((response) => resolver.response.status(node, response.statusCode))\n}\n\nexport function resolveStatusCodeNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses.map((response) => resolver.response.status(node, response.statusCode))\n}\n\nconst typeNamesByResolver = new WeakMap<OperationTypeNameResolver, Map<string, string[]>>()\n\nexport function resolveOperationTypeNames(\n node: ast.OperationNode,\n resolver: OperationTypeNameResolver,\n options: ResolveOperationTypeNameOptions = {},\n): string[] {\n const cacheKey = `${node.operationId}\\0${options.paramsCasing ?? ''}\\0${options.order ?? ''}\\0${options.responseStatusNames ?? ''}\\0${options.includeParams === false ? 'noparams' : ''}\\0${(options.exclude ?? []).join(',')}`\n let byResolver = typeNamesByResolver.get(resolver)\n if (byResolver) {\n const cached = byResolver.get(cacheKey)\n if (cached) return cached\n } else {\n byResolver = new Map()\n typeNamesByResolver.set(resolver, byResolver)\n }\n\n const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing })\n const responseStatusNames =\n options.responseStatusNames === 'error'\n ? resolveErrorNames(node, resolver)\n : options.responseStatusNames === false\n ? []\n : resolveStatusCodeNames(node, resolver)\n const exclude = new Set(options.exclude ?? [])\n const paramNames =\n options.includeParams === false\n ? []\n : [\n ...path.map((param) => resolver.param.path(node, param)),\n ...query.map((param) => resolver.param.query(node, param)),\n ...header.map((param) => resolver.param.headers(node, param)),\n ]\n const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.response.body(node) : null, resolver.response.response(node)]\n const names =\n options.order === 'body-response-first'\n ? [...bodyAndResponseNames, ...paramNames, ...responseStatusNames]\n : [...paramNames, ...bodyAndResponseNames, ...responseStatusNames]\n\n const result = names.filter((name): name is string => Boolean(name) && !exclude.has(name as string))\n byResolver.set(cacheKey, result)\n return result\n}\n\nexport function resolveResponseTypes(node: ast.OperationNode, resolver: ResponseNameResolver): Array<[statusCode: number | 'default', typeName: string]> {\n const types: Array<[number | 'default', string]> = []\n\n for (const response of node.responses) {\n if (response.statusCode === 'default') {\n types.push(['default', resolver.response.response(node)])\n continue\n }\n\n const code = getStatusCodeNumber(response.statusCode)\n if (code === null) {\n continue\n }\n\n types.push([code, isSuccessStatusCode(code) ? resolver.response.response(node) : resolver.response.status(node, response.statusCode)])\n }\n\n return types\n}\n\nexport function findSuccessStatusCode(responses: Array<{ statusCode: ast.StatusCode | number | string }>): ast.StatusCode | null {\n for (const response of responses) {\n if (isSuccessStatusCode(response.statusCode)) {\n return response.statusCode as ast.StatusCode\n }\n }\n\n return null\n}\n","import { camelCase } from '@internals/utils'\nimport type { Group } from 'kubb/kit'\n\n/**\n * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the\n * shared default naming so every plugin groups output consistently:\n *\n * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).\n * - other groups use the camelCased group (`pet store` → `petStore`).\n *\n * A user-provided `group.name` always wins over the default namer, so callers stay in\n * control of their output folders. Returns `null` when grouping is disabled, matching the\n * per-plugin convention.\n *\n * @param group - The user-supplied group option, or `undefined` to disable grouping.\n *\n * @example\n * ```ts\n * createGroupConfig(group) // shared across every plugin\n * ```\n */\nexport function createGroupConfig(group: Group | undefined): Group | null {\n if (!group) {\n return null\n }\n\n const defaultName = (ctx: { group: string }): string => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n\n return camelCase(ctx.group)\n }\n\n return {\n ...group,\n name: group.name ? group.name : defaultName,\n } satisfies Group\n}\n","import { buildParamsMapping, buildParamsRemapExpression, buildRequestParamsSignature, getOperationParameters } from '@internals/shared'\nimport { Url } from '@internals/utils'\nimport { ast } from 'kubb/kit'\nimport type { ResolverTs } from '@kubb/plugin-ts'\nimport { File, Function } from 'kubb/jsx'\nimport type { KubbReactNode } from 'kubb/jsx'\n\ntype Props = {\n /**\n * Name of the function\n */\n name: string\n /**\n * AST operation node\n */\n node: ast.OperationNode\n /**\n * TypeScript resolver for resolving param/data/response type names\n */\n resolver: ResolverTs\n baseURL: string | null | undefined\n}\n\nexport function Request({ baseURL = '', name, resolver, node }: Props): KubbReactNode {\n if (!ast.isHttpOperationNode(node)) return null\n\n const { query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node, { paramsCasing: 'original' })\n const { query: casedQueryParams, header: casedHeaderParams } = getOperationParameters(node)\n\n const queryParamsMapping = buildParamsMapping(originalQueryParams, casedQueryParams)\n const headerParamsMapping = buildParamsMapping(originalHeaderParams, casedHeaderParams)\n\n const { signature, groups } = buildRequestParamsSignature(node, resolver, { isConfigurable: false })\n const paramsSignature = [signature, 'options: Partial<Cypress.RequestOptions> = {}'].filter(Boolean).join(', ')\n\n const responseType = resolver.response.response(node)\n const returnType = `Cypress.Chainable<${responseType}>`\n\n // Reference the path object straight in the URL with camelCase placeholders.\n const urlTemplate = Url.toGroupedTemplateString(node.path, { prefix: baseURL })\n\n const requestOptions: Array<string> = [`method: '${node.method}'`, `url: ${urlTemplate}`]\n\n if (groups.query) {\n requestOptions.push(queryParamsMapping ? `qs: ${buildParamsRemapExpression({ source: 'query', mapping: queryParamsMapping })}` : 'qs: query')\n }\n\n if (groups.headers) {\n requestOptions.push(headerParamsMapping ? `headers: ${buildParamsRemapExpression({ source: 'headers', mapping: headerParamsMapping })}` : 'headers')\n }\n\n if (groups.body) {\n requestOptions.push('body')\n }\n\n requestOptions.push('...options')\n\n const requestCall = `return cy.request<${responseType}>({\n ${requestOptions.join(',\\n ')}\n}).then((res) => res.body)`\n\n return (\n <File.Source name={name} isIndexable isExportable>\n <Function name={name} export params={paramsSignature} returnType={returnType}>\n {requestCall}\n </Function>\n </File.Source>\n )\n}\n","import { resolveOperationTypeNames } from '@internals/shared'\nimport { ast, defineGenerator } from 'kubb/kit'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { File, jsxRenderer } from 'kubb/jsx'\nimport { Request } from '../components/Request.tsx'\nimport type { PluginCypress } from '../types.ts'\n\n/**\n * Built-in generator for `@kubb/plugin-cypress`. Emits one typed\n * `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress\n * test specs and custom commands.\n */\nexport const cypressGenerator = defineGenerator<PluginCypress>({\n name: 'cypress',\n renderer: jsxRenderer,\n operation(node, ctx) {\n if (!ast.isHttpOperationNode(node)) return null\n const { config, resolver, driver, root } = ctx\n const { output, baseURL, group } = ctx.options\n\n const pluginTs = driver.getPlugin(pluginTsName)\n\n if (!pluginTs) {\n return null\n }\n\n const tsResolver = driver.getResolver(pluginTsName)\n\n const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })]\n\n const meta = {\n name: resolver.name(node.operationId),\n file: resolver.file({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path, root, output, group: group ?? undefined }),\n fileTs: tsResolver.file({\n name: node.operationId,\n extname: '.ts',\n tag: node.tags[0] ?? 'default',\n path: node.path,\n root,\n output: pluginTs.options?.output ?? output,\n group: pluginTs.options?.group ?? undefined,\n }),\n } as const\n\n return (\n <File\n baseName={meta.file.baseName}\n path={meta.file.path}\n meta={meta.file.meta}\n banner={resolver.default.banner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n footer={resolver.default.footer(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}\n >\n {importedTypeNames.length > 0 && <File.Import name={importedTypeNames} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />}\n <Request name={meta.name} node={node} resolver={tsResolver} baseURL={baseURL} />\n </File>\n )\n },\n})\n","import { createResolver } from 'kubb/kit'\nimport type { PluginCypress } from '../types.ts'\n\n/**\n * Default resolver used by `@kubb/plugin-cypress`. Decides the names and file\n * paths for every generated `cy.request()` wrapper. Functions and files use\n * camelCase, matching the convention from `@kubb/plugin-axios` and `@kubb/plugin-fetch`.\n *\n * @example Resolve a helper name\n * ```ts\n * import { resolverCypress } from '@kubb/plugin-cypress'\n *\n * resolverCypress.name('list pets') // 'listPets'\n * ```\n */\nexport const resolverCypress = createResolver<PluginCypress>({\n pluginName: 'plugin-cypress',\n})\n","import { createGroupConfig } from '@internals/shared'\nimport { definePlugin, Resolver } from 'kubb/kit'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { cypressGenerator } from './generators/cypressGenerator.tsx'\nimport { resolverCypress } from './resolvers/resolverCypress.ts'\nimport type { PluginCypress, ResolverCypress } from './types.ts'\n\n/**\n * Canonical plugin name for `@kubb/plugin-cypress`. Used for driver lookups and\n * cross-plugin dependency references.\n */\nexport const pluginCypressName = 'plugin-cypress' satisfies PluginCypress['name']\n\n/**\n * Generates one typed `cy.request()` wrapper per OpenAPI operation. Each helper\n * has typed path params, body, query, and a typed response, so failing API\n * calls in Cypress show up at compile time instead of inside the test runner.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb/config'\n * import { pluginTs } from '@kubb/plugin-ts'\n * import { pluginCypress } from '@kubb/plugin-cypress'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * plugins: [\n * pluginTs(),\n * pluginCypress({\n * output: { path: './cypress' },\n * }),\n * ],\n * })\n * ```\n */\nexport const pluginCypress = definePlugin<PluginCypress>((options) => {\n const {\n output = { path: 'cypress', barrel: { type: 'named' } },\n group,\n exclude = [],\n include,\n override = [],\n baseURL,\n resolver: userResolver,\n macros: userMacros,\n } = options\n\n const groupConfig = createGroupConfig(group)\n\n return {\n name: pluginCypressName,\n options,\n dependencies: [pluginTsName],\n hooks: {\n 'kubb:plugin:setup'(ctx) {\n const resolver = userResolver ? Resolver.merge<ResolverCypress>(resolverCypress, userResolver) : resolverCypress\n\n ctx.setOptions({\n output,\n exclude,\n include,\n override,\n group: groupConfig,\n baseURL,\n resolver,\n })\n ctx.setResolver(resolver)\n if (userMacros?.length) {\n ctx.setMacros(userMacros)\n }\n ctx.addGenerator(cypressGenerator)\n },\n },\n }\n})\n\nexport default pluginCypress\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/plugin-cypress",
3
- "version": "5.0.0-beta.85",
3
+ "version": "5.0.0-beta.87",
4
4
  "description": "Generate Cypress request commands and e2e test fixtures with Kubb for automated API testing.",
5
5
  "keywords": [
6
6
  "code-generation",
@@ -44,15 +44,15 @@
44
44
  "registry": "https://registry.npmjs.org/"
45
45
  },
46
46
  "dependencies": {
47
- "@kubb/plugin-ts": "5.0.0-beta.84"
47
+ "@kubb/plugin-ts": "5.0.0-beta.86"
48
48
  },
49
49
  "devDependencies": {
50
- "kubb": "5.0.0-beta.84",
50
+ "kubb": "5.0.0-beta.89",
51
51
  "@internals/shared": "0.0.0",
52
52
  "@internals/utils": "0.0.0"
53
53
  },
54
54
  "peerDependencies": {
55
- "kubb": "5.0.0-beta.84"
55
+ "kubb": "5.0.0-beta.89"
56
56
  },
57
57
  "engines": {
58
58
  "node": ">=22"