@kubb/plugin-cypress 5.2.0-canary.20261029T124214 → 5.2.0
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 +27 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +10 -10
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -2,9 +2,9 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
let
|
|
6
|
-
let
|
|
7
|
-
let
|
|
5
|
+
let _kubb_kit = require("@kubb/kit");
|
|
6
|
+
let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
|
|
7
|
+
let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
|
|
8
8
|
let _kubb_plugin_ts = require("@kubb/plugin-ts");
|
|
9
9
|
// ../../internals/shared/src/operation.ts
|
|
10
10
|
/**
|
|
@@ -27,19 +27,19 @@ function operationFileEntry(node, name, extname = ".ts") {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
* Resolves a dependency plugin's generated file for `node.operationId`, cached in `
|
|
31
|
-
*
|
|
30
|
+
* Resolves a dependency plugin's generated file for `node.operationId`, cached in `memo` (the
|
|
31
|
+
* build's `ctx.memo`) under the resolver's own plugin name and the operation. Several dependents reading the
|
|
32
32
|
* same dependency for the same operation in one pass (a query plugin's several hook generators, the
|
|
33
33
|
* MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
|
|
34
34
|
*
|
|
35
35
|
* @example Cache `plugin-ts`'s file for the current operation
|
|
36
36
|
* ```ts
|
|
37
|
-
* const fileTs = resolveDependencyOperationFile({
|
|
37
|
+
* const fileTs = resolveDependencyOperationFile({ memo: ctx.memo, node, resolver: tsResolver, root, output })
|
|
38
38
|
* ```
|
|
39
39
|
*/
|
|
40
40
|
function resolveDependencyOperationFile(options) {
|
|
41
|
-
const {
|
|
42
|
-
return
|
|
41
|
+
const { memo, node, resolver, root, output, group } = options;
|
|
42
|
+
return memo(`${resolver.pluginName}:operationFile:${node.operationId}`, () => resolver.file({
|
|
43
43
|
...operationFileEntry(node, node.operationId),
|
|
44
44
|
root,
|
|
45
45
|
output,
|
|
@@ -364,7 +364,7 @@ function isIdentifier(name) {
|
|
|
364
364
|
* The shared top-level `name` of the operation plugins, computed once per operation name and build.
|
|
365
365
|
*/
|
|
366
366
|
function resolveOperationName(name) {
|
|
367
|
-
return this.memo(`operation:${name}`, () => ensureValidVarName((0,
|
|
367
|
+
return this.memo(`operation:${name}`, () => ensureValidVarName((0, _kubb_kit.camelCase)(name)));
|
|
368
368
|
}
|
|
369
369
|
/**
|
|
370
370
|
* Builds the allocation key for a declaration an operation owns. `scope` names which declaration
|
|
@@ -407,7 +407,7 @@ function createGroupConfig(group) {
|
|
|
407
407
|
if (!group) return null;
|
|
408
408
|
const defaultName = (ctx) => {
|
|
409
409
|
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
410
|
-
return (0,
|
|
410
|
+
return (0, _kubb_kit.camelCase)(ctx.group);
|
|
411
411
|
};
|
|
412
412
|
return {
|
|
413
413
|
...group,
|
|
@@ -420,7 +420,7 @@ function Request({ baseURL = "", name, resolver, node }) {
|
|
|
420
420
|
const paramsSignature = [signature, "options: Partial<Cypress.RequestOptions> = {}"].filter(Boolean).join(", ");
|
|
421
421
|
const responseType = resolver.response.response(node);
|
|
422
422
|
const returnType = `Cypress.Chainable<${responseType}>`;
|
|
423
|
-
const urlTemplate =
|
|
423
|
+
const urlTemplate = _kubb_kit.Url.toGroupedTemplateString(node.path, { prefix: baseURL });
|
|
424
424
|
const requestCall = `return cy.request<${responseType}>({
|
|
425
425
|
${[
|
|
426
426
|
`method: '${node.method}'`,
|
|
@@ -431,11 +431,11 @@ function Request({ baseURL = "", name, resolver, node }) {
|
|
|
431
431
|
"...options"
|
|
432
432
|
].filter(Boolean).join(",\n ")}
|
|
433
433
|
}).then((res) => res.body)`;
|
|
434
|
-
return /* @__PURE__ */ (0,
|
|
434
|
+
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
435
435
|
name,
|
|
436
436
|
isIndexable: true,
|
|
437
437
|
isExportable: true,
|
|
438
|
-
children: /* @__PURE__ */ (0,
|
|
438
|
+
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Function, {
|
|
439
439
|
name,
|
|
440
440
|
export: true,
|
|
441
441
|
params: paramsSignature,
|
|
@@ -450,11 +450,11 @@ function Request({ baseURL = "", name, resolver, node }) {
|
|
|
450
450
|
* `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress
|
|
451
451
|
* test specs and custom commands.
|
|
452
452
|
*/
|
|
453
|
-
const cypressGenerator = (0,
|
|
453
|
+
const cypressGenerator = (0, _kubb_kit.defineGenerator)({
|
|
454
454
|
name: "cypress",
|
|
455
|
-
renderer:
|
|
455
|
+
renderer: _kubb_renderer_jsx.jsxRenderer,
|
|
456
456
|
operation(node, ctx) {
|
|
457
|
-
if (!
|
|
457
|
+
if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
|
|
458
458
|
const { config, resolver, driver, root } = ctx;
|
|
459
459
|
const { output, baseURL, group } = ctx.options;
|
|
460
460
|
const pluginTs = ctx.requirePlugin(_kubb_plugin_ts.pluginTsName);
|
|
@@ -476,7 +476,7 @@ const cypressGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
476
476
|
group: group ?? void 0
|
|
477
477
|
}),
|
|
478
478
|
fileTs: resolveDependencyOperationFile({
|
|
479
|
-
|
|
479
|
+
memo: ctx.memo,
|
|
480
480
|
node,
|
|
481
481
|
resolver: tsResolver,
|
|
482
482
|
root,
|
|
@@ -484,7 +484,7 @@ const cypressGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
484
484
|
group: pluginTs.options?.group
|
|
485
485
|
})
|
|
486
486
|
};
|
|
487
|
-
return /* @__PURE__ */ (0,
|
|
487
|
+
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
488
488
|
baseName: meta.file.baseName,
|
|
489
489
|
path: meta.file.path,
|
|
490
490
|
meta: meta.file.meta,
|
|
@@ -504,12 +504,12 @@ const cypressGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
504
504
|
baseName: meta.file.baseName
|
|
505
505
|
}
|
|
506
506
|
}),
|
|
507
|
-
children: [/* @__PURE__ */ (0,
|
|
507
|
+
children: [/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
508
508
|
name: importedTypeNames,
|
|
509
509
|
root: meta.file.path,
|
|
510
510
|
path: meta.fileTs.path,
|
|
511
511
|
isTypeOnly: true
|
|
512
|
-
}), /* @__PURE__ */ (0,
|
|
512
|
+
}), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Request, {
|
|
513
513
|
name: meta.name,
|
|
514
514
|
node,
|
|
515
515
|
resolver: tsResolver,
|
|
@@ -524,7 +524,7 @@ var compatibility = {
|
|
|
524
524
|
"node": ">=22.22"
|
|
525
525
|
};
|
|
526
526
|
// package.json
|
|
527
|
-
var version = "5.2.0
|
|
527
|
+
var version = "5.2.0";
|
|
528
528
|
// src/resolvers/resolverCypress.ts
|
|
529
529
|
/**
|
|
530
530
|
* Default resolver used by `@kubb/plugin-cypress`. Decides the names and file
|
|
@@ -538,7 +538,7 @@ var version = "5.2.0-canary.20261029T124214";
|
|
|
538
538
|
* resolverCypress.name('list pets') // 'listPets'
|
|
539
539
|
* ```
|
|
540
540
|
*/
|
|
541
|
-
const resolverCypress = (0,
|
|
541
|
+
const resolverCypress = (0, _kubb_kit.createResolver)({
|
|
542
542
|
pluginName: "plugin-cypress",
|
|
543
543
|
name: resolveOperationName
|
|
544
544
|
});
|
|
@@ -571,7 +571,7 @@ const pluginCypressName = "plugin-cypress";
|
|
|
571
571
|
* })
|
|
572
572
|
* ```
|
|
573
573
|
*/
|
|
574
|
-
const pluginCypress = (0,
|
|
574
|
+
const pluginCypress = (0, _kubb_kit.defineExtension)({
|
|
575
575
|
kind: "plugin",
|
|
576
576
|
meta: {
|
|
577
577
|
name: pluginCypressName,
|
|
@@ -584,10 +584,10 @@ const pluginCypress = (0, kubb_kit.defineExtension)({
|
|
|
584
584
|
path: "cypress",
|
|
585
585
|
barrel: { type: "named" }
|
|
586
586
|
}, group, exclude = [], include, override = [], baseURL, resolver: userResolver, macros: userMacros } = options;
|
|
587
|
-
const resolver = userResolver ?
|
|
588
|
-
(0,
|
|
589
|
-
if (userMacros?.length) (0,
|
|
590
|
-
(0,
|
|
587
|
+
const resolver = userResolver ? _kubb_kit.Resolver.merge(resolverCypress, userResolver) : resolverCypress;
|
|
588
|
+
(0, _kubb_kit.setResolver)(resolver);
|
|
589
|
+
if (userMacros?.length) (0, _kubb_kit.setMacros)(userMacros);
|
|
590
|
+
(0, _kubb_kit.addGenerator)(cypressGenerator);
|
|
591
591
|
return {
|
|
592
592
|
output,
|
|
593
593
|
exclude,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["camelCase","camelCase","Url","File","Function","defineGenerator","jsxRenderer","ast","pluginTsName","File","createResolver","defineExtension","pluginTsName","Resolver"],"sources":["../../../internals/shared/src/operation.ts","../../../internals/utils/src/reserved.ts","../../../internals/shared/src/resolver.ts","../../../internals/shared/src/group.ts","../src/components/Request.tsx","../src/generators/cypressGenerator.tsx","../kubb-extension.json","../package.json","../src/resolvers/resolverCypress.ts","../src/plugin.ts"],"sourcesContent":["import { ast, type Group, type NodeCache, type Output, type Resolver, type ResolverFileParams, Url } from 'kubb/kit'\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\n/**\n * Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the\n * current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the\n * same dependency for the same operation in one pass (a query plugin's several hook generators, the\n * MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.\n *\n * @example Cache `plugin-ts`'s file for the current operation\n * ```ts\n * const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })\n * ```\n */\nexport function resolveDependencyOperationFile(options: {\n cache: NodeCache\n node: ast.OperationNode\n resolver: Pick<Resolver, 'file' | 'pluginName'>\n root: string\n output: Output\n group?: Group | null\n}): ast.FileNode {\n const { cache, node, resolver, root, output, group } = options\n\n return cache.ensureItem(`${resolver.pluginName}:operationFile`, () =>\n resolver.file({ ...operationFileEntry(node, node.operationId), root, output, group: group ?? undefined }),\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\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 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 return node.path ? `{@link ${Url.toPath(node.path)}}` : 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\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`.\nconst requestConfigBaseType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n\nexport function buildRequestConfigType(node: ast.OperationNode): string {\n const request = getContentTypeInfo(node)\n const response = getResponseContentTypeInfo(node)\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 ? `${requestConfigBaseType} & { contentType?: { ${members.join('; ')} } }` : requestConfigBaseType\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 requestConfigBaseType\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 // These callers never carry the `contentType` that several media types require.\n const optionsType = hasRequestContentTypeChoice(node)\n ? `Pick<${resolver.response.options(node)}, ${names.map((name) => `'${name}'`).join(' | ')}>`\n : resolver.response.options(node)\n const firstParam = names.length > 0 ? `{ ${names.join(', ')} }: ${optionsType}${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\nconst operationParameterGroupsByNode = new WeakMap<ast.OperationNode, OperationParameterGroups>()\n\n/**\n * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each\n * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance\n * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the\n * same parameters once per plugin.\n */\nexport function getOperationParameters(node: ast.OperationNode): OperationParameterGroups {\n const cached = operationParameterGroupsByNode.get(node)\n if (cached) return cached\n\n // A malformed spec can declare the same name twice within one location. Both would resolve to the\n // same output property, so emitting both would yield an object type with a duplicate member,\n // which TypeScript rejects. Keep the first.\n const group = (location: ast.ParameterNode['in']) => {\n const seen = new Set<string>()\n\n return node.parameters.filter((param) => {\n if (param.in !== location || seen.has(param.name)) return false\n seen.add(param.name)\n return true\n })\n }\n\n const groups: OperationParameterGroups = { path: group('path'), query: group('query'), header: group('header'), cookie: group('cookie') }\n\n operationParameterGroupsByNode.set(node, groups)\n return groups\n}\n\n/**\n * Builds the combined `{ body, path, query, headers }` options object schema for an operation,\n * referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s\n * `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same\n * shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod\n * printer to emit `z.object(…)` rather than a record.\n */\nexport function hasRequestContentTypeChoice(node: ast.OperationNode): boolean {\n return (node.requestBody?.content ?? []).filter((entry) => entry.schema).length > 1\n}\n\n/**\n * Casts a call argument to the client's parameter type; a `'plain'` client is non-generic.\n */\nexport function castToClientOptions(callArg: string, clientName: string, returnType: 'full' | 'data' | 'plain' = 'full'): string {\n return `${callArg} as Parameters<typeof ${clientName}${returnType === 'plain' ? '' : '<true>'}>[0]`\n}\n\nexport function buildOptionsSchema(node: ast.OperationNode, resolver: OperationTypeNameResolver, { pairContentTypes = false } = {}): ast.SchemaNode {\n const { path, query, header } = getOperationParameters(node)\n const hasBody = Boolean(node.requestBody?.content?.[0]?.schema)\n const createNever = () => ast.factory.createSchema({ type: 'never', primitive: undefined, optional: true })\n const groups = [\n { name: 'path', params: path, resolve: resolver.param.path },\n { name: 'query', params: query, resolve: resolver.param.query },\n { name: 'headers', params: header, resolve: resolver.param.headers },\n ] as const\n\n const createOptions = (body: ast.SchemaNode, extra: Array<ast.PropertyNode> = []) =>\n // NOTE(v5-stable): the fields were renamed from the legacy beta shape\n // (`data`/`pathParams`/`queryParams`/`headerParams`) to `body`/`path`/`query`/`headers` so the\n // type matches the runtime client. Drop this note once v5 leaves beta.\n ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n deprecated: node.deprecated,\n properties: [\n ast.factory.createProperty({ name: 'body', required: hasBody, schema: body }),\n ...groups.map(({ name, params, resolve }) => {\n const required = params.some((param) => param.required)\n\n return ast.factory.createProperty({\n name,\n required,\n schema:\n params.length > 0\n ? ast.factory.createSchema({ type: 'ref', name: resolve.call(resolver.param, node, params[0]!), optional: !required })\n : createNever(),\n })\n }),\n ...extra,\n ],\n })\n\n const variants =\n pairContentTypes && hasRequestContentTypeChoice(node) ? resolveContentTypeVariants(node.requestBody?.content ?? [], resolver.response.body(node)) : []\n if (variants.length < 2) {\n return createOptions(hasBody ? ast.factory.createSchema({ type: 'ref', name: resolver.response.body(node) }) : createNever())\n }\n\n // The first media type is the runtime default, so only the others must pass `contentType`.\n return ast.factory.createSchema({\n type: 'union',\n members: variants.map((variant, index) =>\n createOptions(ast.factory.createSchema({ type: 'ref', name: variant.name }), [\n ast.factory.createProperty({\n name: 'contentType',\n required: index > 0,\n schema: ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: [\n ast.factory.createProperty({\n name: 'request',\n required: true,\n schema: ast.factory.createSchema({ type: 'enum', enumValues: [variant.contentType] }),\n }),\n ],\n }),\n }),\n ]),\n ),\n })\n}\n\n/**\n * The schema a status occupies in the `<Name>Responses` record. A status that documents several\n * content types becomes a `{ contentType; data }` union so the runtime can surface the negotiated type\n * on `result.parsed`, while the standalone `<Name>StatusNNN` alias stays the plain body union that the\n * query hooks and `result.data` use.\n */\nfunction buildResponseRecordEntry(node: ast.OperationNode, res: ast.ResponseNode, resolver: ResponseStatusNameResolver): ast.SchemaNode {\n const statusName = resolver.response.status(node, res.statusCode)\n const variants = (res.content ?? []).filter((entry) => entry.schema)\n if (variants.length <= 1) {\n return ast.factory.createSchema({ type: 'ref', name: statusName })\n }\n\n return ast.factory.createSchema({\n type: 'union',\n members: resolveContentTypeVariants(variants, statusName).map((variant) =>\n ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: [\n ast.factory.createProperty({\n name: 'contentType',\n required: true,\n schema: ast.factory.createSchema({ type: 'enum', enumValues: [variant.contentType] }),\n }),\n ast.factory.createProperty({\n name: 'data',\n required: true,\n schema: ast.factory.createSchema({ type: 'ref', name: variant.name }),\n }),\n ],\n }),\n ),\n })\n}\n\n/**\n * Builds the per-status `<Name>Responses` record for an operation, referencing the already-resolved\n * `<Name>StatusNNN` names. Shared by `@kubb/plugin-ts`'s `Responses` type and `@kubb/plugin-zod`'s\n * inferred responses schema, so both emit the same shape from the same inputs.\n *\n * Always emits the keyed record, even when an operation declares no responses. An operation with no\n * responses renders as an empty object, which keeps every consumer's import (for example the axios\n * SDK's `RequestResult<XResponses>`) resolvable instead of pointing at a missing export.\n */\nexport function buildResponses(node: ast.OperationNode, resolver: ResponseStatusNameResolver): ast.SchemaNode {\n return ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: node.responses.map((res) =>\n ast.factory.createProperty({\n name: String(res.statusCode),\n required: true,\n schema: buildResponseRecordEntry(node, res, resolver),\n }),\n ),\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\n/**\n * Lists the type names an operation's types file declares, computed once per resolver and `options` so every\n * dependent reads the same list.\n */\nexport function resolveOperationTypeNames(\n node: ast.OperationNode,\n resolver: OperationTypeNameResolver & Pick<Resolver, 'memo'>,\n options: ResolveOperationTypeNameOptions = {},\n): string[] {\n const key = `${node.operationId}\\0${options.order ?? ''}\\0${options.responseStatusNames ?? ''}\\0${options.includeParams === false ? 'noparams' : ''}\\0${(options.exclude ?? []).join(',')}`\n return resolver.memo(`operationTypeNames:${key}`, () => {\n const { path, query, header } = getOperationParameters(node)\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 return names.filter((name): name is string => Boolean(name) && !exclude.has(name as string))\n })\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","/**\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 'await',\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 { ensureValidVarName, toFilePath } from '@internals/utils'\nimport { ast, camelCase } from 'kubb/kit'\nimport type { GeneratorContext, Resolver, ResolverFile } from 'kubb/kit'\n\n/**\n * The shared top-level `name` of the operation plugins, computed once per operation name and build.\n */\nexport function resolveOperationName(this: Resolver, name: string): string {\n return this.memo(`operation:${name}`, () => ensureValidVarName(camelCase(name)))\n}\n\n/**\n * Builds the allocation key for a declaration an operation owns. `scope` names which declaration\n * it is, so two of them never share an allocation even when a custom resolver gives both the same\n * name. Leave `scope` empty for the operation's own declaration.\n *\n * @example\n * ```ts\n * resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })\n * ```\n */\nexport function operationKey(node: ast.OperationNode, ...scope: Array<string | number>): Array<string | undefined> {\n return ['operation', node.method, node.path, ...scope.map(String)]\n}\n\n/**\n * The `param` namespace shared by the schema-producing plugins (ts, zod, faker):\n * per-parameter names plus the grouped `Path`/`Query`/`Headers` names, all routed\n * through the plugin's top-level `name` casing.\n */\nexport type OperationParamResolver = {\n name(this: Resolver, node: ast.OperationNode, param: ast.ParameterNode): string\n path(this: Resolver, node: ast.OperationNode): string\n query(this: Resolver, node: ast.OperationNode): string\n headers(this: Resolver, node: ast.OperationNode): string\n}\n\n/**\n * The `response` namespace shared by the schema-producing plugins: per-status,\n * body, and combined response names, all routed through the plugin's top-level\n * `name` casing.\n */\nexport type OperationResponseResolver = {\n status(this: Resolver, node: ast.OperationNode, statusCode: ast.StatusCode): string\n body(this: Resolver, node: ast.OperationNode): string\n responses(this: Resolver, node: ast.OperationNode): string\n response(this: Resolver, node: ast.OperationNode): string\n}\n\n/**\n * Builds the shared `param` namespace. Spread the result into `createResolver`\n * and override individual methods next to it when a plugin deviates.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ param: createOperationParamResolver(), ... })\n * ```\n */\nexport function createOperationParamResolver(): OperationParamResolver {\n return {\n name(node, param) {\n const name = this.name(`${node.operationId} ${param.in} ${param.name}`)\n return this.resolveName({ key: operationKey(node, 'param', 'name', param.in, param.name), name })\n },\n path(node) {\n const name = this.name(`${node.operationId} Path`)\n return this.resolveName({ key: operationKey(node, 'param', 'path'), name })\n },\n query(node) {\n const name = this.name(`${node.operationId} Query`)\n return this.resolveName({ key: operationKey(node, 'param', 'query'), name })\n },\n headers(node) {\n const name = this.name(`${node.operationId} Headers`)\n return this.resolveName({ key: operationKey(node, 'param', 'headers'), name })\n },\n }\n}\n\n/**\n * Builds the shared `response` namespace. Spread the result into\n * `createResolver` and add plugin-specific methods (`options`, `error`) next\n * to it.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ response: { ...createOperationResponseResolver(), options(node) {...} }, ... })\n * ```\n */\nexport function createOperationResponseResolver(): OperationResponseResolver {\n return {\n status(node, statusCode) {\n const name = this.name(`${node.operationId} Status ${statusCode}`)\n return this.resolveName({ key: operationKey(node, 'response', 'status', statusCode), name })\n },\n body(node) {\n const name = this.name(`${node.operationId} Body`)\n return this.resolveName({ key: operationKey(node, 'response', 'body'), name })\n },\n responses(node) {\n const name = this.name(`${node.operationId} Responses`)\n return this.resolveName({ key: operationKey(node, 'response', 'responses'), name })\n },\n response(node) {\n const name = this.name(`${node.operationId} Response`)\n return this.resolveName({ key: operationKey(node, 'response', 'response'), name })\n },\n }\n}\n\n/**\n * Builds a resolver `file` override whose base name runs every path segment\n * through `toFilePath`, casing the final segment with `caseLast`.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ file: createCasedFile(pascalCase), ... })\n * ```\n */\nexport function createCasedFile(caseLast: (part: string) => string): ResolverFile {\n return {\n baseName({ name, extname }) {\n return this.memo(`file:${name}\\0${extname}`, (): ast.FileNode['baseName'] => `${toFilePath(name, caseLast)}${extname}`)\n },\n }\n}\n\ntype SchemaIndexContext = Pick<GeneratorContext, 'memo' | 'driver'>\n\n/**\n * Names of the schemas in a circular reference chain, computed once per build.\n */\nexport function getCircularNames(ctx: SchemaIndexContext): ReadonlySet<string> {\n return ctx.memo('circularNames:set', () => ast.findCircularSchemas(ctx.driver.inputNode?.schemas ?? []))\n}\n\n/**\n * Names of the schemas whose type is `enum`, computed once per build.\n */\nexport function getEnumNames(ctx: SchemaIndexContext): ReadonlySet<string> {\n return ctx.memo(\n 'enumNames:set',\n () => new Set((ctx.driver.inputNode?.schemas ?? []).flatMap((schema) => (schema.type === 'enum' && schema.name ? [schema.name] : []))),\n )\n}\n\ndeclare global {\n namespace Kubb {\n interface MemoRegistry {\n operation: string\n file: ast.FileNode['baseName']\n operationTypeNames: Array<string>\n }\n }\n}\n","import { camelCase, 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 { buildRequestParamsSignature } from '@internals/shared'\nimport { Url } from 'kubb/kit'\nimport type { 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.HttpOperationNode\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 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 // Bracket-access the path object with the raw OpenAPI param names, matching the generated `path` type's keys.\n const urlTemplate = Url.toGroupedTemplateString(node.path, { prefix: baseURL })\n\n const requestOptions = [\n `method: '${node.method}'`,\n `url: ${urlTemplate}`,\n groups.query && 'qs: query',\n groups.headers && 'headers',\n groups.body && 'body',\n '...options',\n ].filter(Boolean)\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 { operationKey, resolveDependencyOperationFile, 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 = ctx.requirePlugin(pluginTsName)\n\n const tsResolver = driver.getResolver(pluginTsName)\n\n const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })]\n const name = resolver.name(node.operationId)\n\n const meta = {\n name: resolver.resolveName({ key: operationKey(node), name }),\n file: resolver.file({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path, root, output, group: group ?? undefined }),\n fileTs: resolveDependencyOperationFile({\n cache: ctx.cache,\n node,\n resolver: tsResolver,\n root,\n output: pluginTs.options?.output ?? output,\n group: pluginTs.options?.group,\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 <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 { resolveOperationName } from '@internals/shared'\nimport { 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 name: resolveOperationName,\n})\n","import { createGroupConfig } from '@internals/shared'\nimport { addGenerator, defineExtension, Resolver, setMacros, setResolver } from 'kubb/kit'\nimport { compatibility } from '../kubb-extension.json'\nimport { version } from '../package.json'\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: './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 = defineExtension<PluginCypress>({\n kind: 'plugin',\n meta: { name: pluginCypressName, version, compatibility },\n dependencies: { [pluginTsName]: {} },\n setup(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 resolver = userResolver ? Resolver.merge<ResolverCypress>(resolverCypress, userResolver) : resolverCypress\n\n setResolver(resolver)\n if (userMacros?.length) {\n setMacros(userMacros)\n }\n addGenerator(cypressGenerator)\n\n return {\n output,\n exclude,\n include,\n override,\n group: createGroupConfig(group),\n baseURL,\n }\n },\n})\n\nexport default pluginCypress\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["camelCase","camelCase","Url","File","Function","defineGenerator","jsxRenderer","ast","pluginTsName","File","createResolver","defineExtension","pluginTsName","Resolver"],"sources":["../../../internals/shared/src/operation.ts","../../../internals/utils/src/reserved.ts","../../../internals/shared/src/resolver.ts","../../../internals/shared/src/group.ts","../src/components/Request.tsx","../src/generators/cypressGenerator.tsx","../kubb-extension.json","../package.json","../src/resolvers/resolverCypress.ts","../src/plugin.ts"],"sourcesContent":["import { ast, type Group, type Memo, type Output, type Resolver, type ResolverFileParams, Url } from '@kubb/kit'\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\n/**\n * Resolves a dependency plugin's generated file for `node.operationId`, cached in `memo` (the\n * build's `ctx.memo`) under the resolver's own plugin name and the operation. Several dependents reading the\n * same dependency for the same operation in one pass (a query plugin's several hook generators, the\n * MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.\n *\n * @example Cache `plugin-ts`'s file for the current operation\n * ```ts\n * const fileTs = resolveDependencyOperationFile({ memo: ctx.memo, node, resolver: tsResolver, root, output })\n * ```\n */\nexport function resolveDependencyOperationFile(options: {\n memo: Memo\n node: ast.OperationNode\n resolver: Pick<Resolver, 'file' | 'pluginName'>\n root: string\n output: Output\n group?: Group | null\n}): ast.FileNode {\n const { memo, node, resolver, root, output, group } = options\n\n return memo(`${resolver.pluginName}:operationFile:${node.operationId}`, () =>\n resolver.file({ ...operationFileEntry(node, node.operationId), root, output, group: group ?? undefined }),\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\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 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 return node.path ? `{@link ${Url.toPath(node.path)}}` : 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\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`.\nconst requestConfigBaseType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n\nexport function buildRequestConfigType(node: ast.OperationNode): string {\n const request = getContentTypeInfo(node)\n const response = getResponseContentTypeInfo(node)\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 ? `${requestConfigBaseType} & { contentType?: { ${members.join('; ')} } }` : requestConfigBaseType\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 requestConfigBaseType\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 // These callers never carry the `contentType` that several media types require.\n const optionsType = hasRequestContentTypeChoice(node)\n ? `Pick<${resolver.response.options(node)}, ${names.map((name) => `'${name}'`).join(' | ')}>`\n : resolver.response.options(node)\n const firstParam = names.length > 0 ? `{ ${names.join(', ')} }: ${optionsType}${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\nconst operationParameterGroupsByNode = new WeakMap<ast.OperationNode, OperationParameterGroups>()\n\n/**\n * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each\n * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance\n * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the\n * same parameters once per plugin.\n */\nexport function getOperationParameters(node: ast.OperationNode): OperationParameterGroups {\n const cached = operationParameterGroupsByNode.get(node)\n if (cached) return cached\n\n // A malformed spec can declare the same name twice within one location. Both would resolve to the\n // same output property, so emitting both would yield an object type with a duplicate member,\n // which TypeScript rejects. Keep the first.\n const group = (location: ast.ParameterNode['in']) => {\n const seen = new Set<string>()\n\n return node.parameters.filter((param) => {\n if (param.in !== location || seen.has(param.name)) return false\n seen.add(param.name)\n return true\n })\n }\n\n const groups: OperationParameterGroups = { path: group('path'), query: group('query'), header: group('header'), cookie: group('cookie') }\n\n operationParameterGroupsByNode.set(node, groups)\n return groups\n}\n\n/**\n * Builds the combined `{ body, path, query, headers }` options object schema for an operation,\n * referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s\n * `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same\n * shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod\n * printer to emit `z.object(…)` rather than a record.\n */\nexport function hasRequestContentTypeChoice(node: ast.OperationNode): boolean {\n return (node.requestBody?.content ?? []).filter((entry) => entry.schema).length > 1\n}\n\n/**\n * Casts a call argument to the client's parameter type; a `'plain'` client is non-generic.\n */\nexport function castToClientOptions(callArg: string, clientName: string, returnType: 'full' | 'data' | 'plain' = 'full'): string {\n return `${callArg} as Parameters<typeof ${clientName}${returnType === 'plain' ? '' : '<true>'}>[0]`\n}\n\nexport function buildOptionsSchema(node: ast.OperationNode, resolver: OperationTypeNameResolver, { pairContentTypes = false } = {}): ast.SchemaNode {\n const { path, query, header } = getOperationParameters(node)\n const hasBody = Boolean(node.requestBody?.content?.[0]?.schema)\n const createNever = () => ast.factory.createSchema({ type: 'never', primitive: undefined, optional: true })\n const groups = [\n { name: 'path', params: path, resolve: resolver.param.path },\n { name: 'query', params: query, resolve: resolver.param.query },\n { name: 'headers', params: header, resolve: resolver.param.headers },\n ] as const\n\n const createOptions = (body: ast.SchemaNode, extra: Array<ast.PropertyNode> = []) =>\n // NOTE(v5-stable): the fields were renamed from the legacy beta shape\n // (`data`/`pathParams`/`queryParams`/`headerParams`) to `body`/`path`/`query`/`headers` so the\n // type matches the runtime client. Drop this note once v5 leaves beta.\n ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n deprecated: node.deprecated,\n properties: [\n ast.factory.createProperty({ name: 'body', required: hasBody, schema: body }),\n ...groups.map(({ name, params, resolve }) => {\n const required = params.some((param) => param.required)\n\n return ast.factory.createProperty({\n name,\n required,\n schema:\n params.length > 0\n ? ast.factory.createSchema({ type: 'ref', name: resolve.call(resolver.param, node, params[0]!), optional: !required })\n : createNever(),\n })\n }),\n ...extra,\n ],\n })\n\n const variants =\n pairContentTypes && hasRequestContentTypeChoice(node) ? resolveContentTypeVariants(node.requestBody?.content ?? [], resolver.response.body(node)) : []\n if (variants.length < 2) {\n return createOptions(hasBody ? ast.factory.createSchema({ type: 'ref', name: resolver.response.body(node) }) : createNever())\n }\n\n // The first media type is the runtime default, so only the others must pass `contentType`.\n return ast.factory.createSchema({\n type: 'union',\n members: variants.map((variant, index) =>\n createOptions(ast.factory.createSchema({ type: 'ref', name: variant.name }), [\n ast.factory.createProperty({\n name: 'contentType',\n required: index > 0,\n schema: ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: [\n ast.factory.createProperty({\n name: 'request',\n required: true,\n schema: ast.factory.createSchema({ type: 'enum', enumValues: [variant.contentType] }),\n }),\n ],\n }),\n }),\n ]),\n ),\n })\n}\n\n/**\n * The schema a status occupies in the `<Name>Responses` record. A status that documents several\n * content types becomes a `{ contentType; data }` union so the runtime can surface the negotiated type\n * on `result.parsed`, while the standalone `<Name>StatusNNN` alias stays the plain body union that the\n * query hooks and `result.data` use.\n */\nfunction buildResponseRecordEntry(node: ast.OperationNode, res: ast.ResponseNode, resolver: ResponseStatusNameResolver): ast.SchemaNode {\n const statusName = resolver.response.status(node, res.statusCode)\n const variants = (res.content ?? []).filter((entry) => entry.schema)\n if (variants.length <= 1) {\n return ast.factory.createSchema({ type: 'ref', name: statusName })\n }\n\n return ast.factory.createSchema({\n type: 'union',\n members: resolveContentTypeVariants(variants, statusName).map((variant) =>\n ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: [\n ast.factory.createProperty({\n name: 'contentType',\n required: true,\n schema: ast.factory.createSchema({ type: 'enum', enumValues: [variant.contentType] }),\n }),\n ast.factory.createProperty({\n name: 'data',\n required: true,\n schema: ast.factory.createSchema({ type: 'ref', name: variant.name }),\n }),\n ],\n }),\n ),\n })\n}\n\n/**\n * Builds the per-status `<Name>Responses` record for an operation, referencing the already-resolved\n * `<Name>StatusNNN` names. Shared by `@kubb/plugin-ts`'s `Responses` type and `@kubb/plugin-zod`'s\n * inferred responses schema, so both emit the same shape from the same inputs.\n *\n * Always emits the keyed record, even when an operation declares no responses. An operation with no\n * responses renders as an empty object, which keeps every consumer's import (for example the axios\n * SDK's `RequestResult<XResponses>`) resolvable instead of pointing at a missing export.\n */\nexport function buildResponses(node: ast.OperationNode, resolver: ResponseStatusNameResolver): ast.SchemaNode {\n return ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: node.responses.map((res) =>\n ast.factory.createProperty({\n name: String(res.statusCode),\n required: true,\n schema: buildResponseRecordEntry(node, res, resolver),\n }),\n ),\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\n/**\n * Lists the type names an operation's types file declares, computed once per resolver and `options` so every\n * dependent reads the same list.\n */\nexport function resolveOperationTypeNames(\n node: ast.OperationNode,\n resolver: OperationTypeNameResolver & Pick<Resolver, 'memo'>,\n options: ResolveOperationTypeNameOptions = {},\n): string[] {\n const key = `${node.operationId}\\0${options.order ?? ''}\\0${options.responseStatusNames ?? ''}\\0${options.includeParams === false ? 'noparams' : ''}\\0${(options.exclude ?? []).join(',')}`\n return resolver.memo(`operationTypeNames:${key}`, () => {\n const { path, query, header } = getOperationParameters(node)\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 return names.filter((name): name is string => Boolean(name) && !exclude.has(name as string))\n })\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","/**\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 'await',\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 { ensureValidVarName, toFilePath } from '@internals/utils'\nimport { ast, camelCase } from '@kubb/kit'\nimport type { GeneratorContext, Resolver, ResolverFile } from '@kubb/kit'\n\n/**\n * The shared top-level `name` of the operation plugins, computed once per operation name and build.\n */\nexport function resolveOperationName(this: Resolver, name: string): string {\n return this.memo(`operation:${name}`, () => ensureValidVarName(camelCase(name)))\n}\n\n/**\n * Builds the allocation key for a declaration an operation owns. `scope` names which declaration\n * it is, so two of them never share an allocation even when a custom resolver gives both the same\n * name. Leave `scope` empty for the operation's own declaration.\n *\n * @example\n * ```ts\n * resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })\n * ```\n */\nexport function operationKey(node: ast.OperationNode, ...scope: Array<string | number>): Array<string | undefined> {\n return ['operation', node.method, node.path, ...scope.map(String)]\n}\n\n/**\n * The `param` namespace shared by the schema-producing plugins (ts, zod, faker):\n * per-parameter names plus the grouped `Path`/`Query`/`Headers` names, all routed\n * through the plugin's top-level `name` casing.\n */\nexport type OperationParamResolver = {\n name(this: Resolver, node: ast.OperationNode, param: ast.ParameterNode): string\n path(this: Resolver, node: ast.OperationNode): string\n query(this: Resolver, node: ast.OperationNode): string\n headers(this: Resolver, node: ast.OperationNode): string\n}\n\n/**\n * The `response` namespace shared by the schema-producing plugins: per-status,\n * body, and combined response names, all routed through the plugin's top-level\n * `name` casing.\n */\nexport type OperationResponseResolver = {\n status(this: Resolver, node: ast.OperationNode, statusCode: ast.StatusCode): string\n body(this: Resolver, node: ast.OperationNode): string\n responses(this: Resolver, node: ast.OperationNode): string\n response(this: Resolver, node: ast.OperationNode): string\n}\n\n/**\n * Builds the shared `param` namespace. Spread the result into `createResolver`\n * and override individual methods next to it when a plugin deviates.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ param: createOperationParamResolver(), ... })\n * ```\n */\nexport function createOperationParamResolver(): OperationParamResolver {\n return {\n name(node, param) {\n const name = this.name(`${node.operationId} ${param.in} ${param.name}`)\n return this.resolveName({ key: operationKey(node, 'param', 'name', param.in, param.name), name })\n },\n path(node) {\n const name = this.name(`${node.operationId} Path`)\n return this.resolveName({ key: operationKey(node, 'param', 'path'), name })\n },\n query(node) {\n const name = this.name(`${node.operationId} Query`)\n return this.resolveName({ key: operationKey(node, 'param', 'query'), name })\n },\n headers(node) {\n const name = this.name(`${node.operationId} Headers`)\n return this.resolveName({ key: operationKey(node, 'param', 'headers'), name })\n },\n }\n}\n\n/**\n * Builds the shared `response` namespace. Spread the result into\n * `createResolver` and add plugin-specific methods (`options`, `error`) next\n * to it.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ response: { ...createOperationResponseResolver(), options(node) {...} }, ... })\n * ```\n */\nexport function createOperationResponseResolver(): OperationResponseResolver {\n return {\n status(node, statusCode) {\n const name = this.name(`${node.operationId} Status ${statusCode}`)\n return this.resolveName({ key: operationKey(node, 'response', 'status', statusCode), name })\n },\n body(node) {\n const name = this.name(`${node.operationId} Body`)\n return this.resolveName({ key: operationKey(node, 'response', 'body'), name })\n },\n responses(node) {\n const name = this.name(`${node.operationId} Responses`)\n return this.resolveName({ key: operationKey(node, 'response', 'responses'), name })\n },\n response(node) {\n const name = this.name(`${node.operationId} Response`)\n return this.resolveName({ key: operationKey(node, 'response', 'response'), name })\n },\n }\n}\n\n/**\n * Builds a resolver `file` override whose base name runs every path segment\n * through `toFilePath`, casing the final segment with `caseLast`.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ file: createCasedFile(pascalCase), ... })\n * ```\n */\nexport function createCasedFile(caseLast: (part: string) => string): ResolverFile {\n return {\n baseName({ name, extname }) {\n return this.memo(`file:${name}\\0${extname}`, (): ast.FileNode['baseName'] => `${toFilePath(name, caseLast)}${extname}`)\n },\n }\n}\n\ntype SchemaIndexContext = Pick<GeneratorContext, 'memo' | 'driver'>\n\n/**\n * Names of the schemas in a circular reference chain, computed once per build.\n */\nexport function getCircularNames(ctx: SchemaIndexContext): ReadonlySet<string> {\n return ctx.memo('circularNames:set', () => ast.findCircularSchemas(ctx.driver.inputNode?.schemas ?? []))\n}\n\n/**\n * Names of the schemas whose type is `enum`, computed once per build.\n */\nexport function getEnumNames(ctx: SchemaIndexContext): ReadonlySet<string> {\n return ctx.memo(\n 'enumNames:set',\n () => new Set((ctx.driver.inputNode?.schemas ?? []).flatMap((schema) => (schema.type === 'enum' && schema.name ? [schema.name] : []))),\n )\n}\n\ndeclare global {\n namespace Kubb {\n interface MemoRegistry {\n operation: string\n file: ast.FileNode['baseName']\n operationTypeNames: Array<string>\n }\n }\n}\n","import { camelCase, 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 { buildRequestParamsSignature } from '@internals/shared'\nimport { Url } from '@kubb/kit'\nimport type { ast } from '@kubb/kit'\nimport type { ResolverTs } from '@kubb/plugin-ts'\nimport { File, Function } from '@kubb/renderer-jsx'\nimport type { KubbReactNode } from '@kubb/renderer-jsx'\n\ntype Props = {\n /**\n * Name of the function\n */\n name: string\n /**\n * AST operation node\n */\n node: ast.HttpOperationNode\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 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 // Bracket-access the path object with the raw OpenAPI param names, matching the generated `path` type's keys.\n const urlTemplate = Url.toGroupedTemplateString(node.path, { prefix: baseURL })\n\n const requestOptions = [\n `method: '${node.method}'`,\n `url: ${urlTemplate}`,\n groups.query && 'qs: query',\n groups.headers && 'headers',\n groups.body && 'body',\n '...options',\n ].filter(Boolean)\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 { operationKey, resolveDependencyOperationFile, resolveOperationTypeNames } from '@internals/shared'\nimport { ast, defineGenerator } from '@kubb/kit'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { File, jsxRenderer } from '@kubb/renderer-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 = ctx.requirePlugin(pluginTsName)\n\n const tsResolver = driver.getResolver(pluginTsName)\n\n const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })]\n const name = resolver.name(node.operationId)\n\n const meta = {\n name: resolver.resolveName({ key: operationKey(node), name }),\n file: resolver.file({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path, root, output, group: group ?? undefined }),\n fileTs: resolveDependencyOperationFile({\n memo: ctx.memo,\n node,\n resolver: tsResolver,\n root,\n output: pluginTs.options?.output ?? output,\n group: pluginTs.options?.group,\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 <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 { resolveOperationName } from '@internals/shared'\nimport { 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 name: resolveOperationName,\n})\n","import { createGroupConfig } from '@internals/shared'\nimport { addGenerator, defineExtension, Resolver, setMacros, setResolver } from '@kubb/kit'\nimport { compatibility } from '../kubb-extension.json'\nimport { version } from '../package.json'\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: './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 = defineExtension<PluginCypress>({\n kind: 'plugin',\n meta: { name: pluginCypressName, version, compatibility },\n dependencies: { [pluginTsName]: {} },\n setup(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 resolver = userResolver ? Resolver.merge<ResolverCypress>(resolverCypress, userResolver) : resolverCypress\n\n setResolver(resolver)\n if (userMacros?.length) {\n setMacros(userMacros)\n }\n addGenerator(cypressGenerator)\n\n return {\n output,\n exclude,\n include,\n override,\n group: createGroupConfig(group),\n baseURL,\n }\n },\n})\n\nexport default pluginCypress\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Exclude, Group, Include, Output, OutputOptions, Override, PluginType, Resolver, ResolverPatch, ast } from "kubb/kit";
|
|
1
|
+
import { Exclude, Group, Include, Output, OutputOptions, Override, PluginType, Resolver, ResolverPatch, ast } from "@kubb/kit";
|
|
2
2
|
import { ResolverTs } from "@kubb/plugin-ts";
|
|
3
|
-
import { KubbReactNode } from "kubb/jsx";
|
|
3
|
+
import { KubbReactNode } from "@kubb/renderer-jsx";
|
|
4
4
|
type Props = {
|
|
5
5
|
/**
|
|
6
6
|
* Name of the function
|
|
@@ -75,7 +75,7 @@ declare global {
|
|
|
75
75
|
* `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress
|
|
76
76
|
* test specs and custom commands.
|
|
77
77
|
*/
|
|
78
|
-
export declare const cypressGenerator: import("kubb/kit").Generator<PluginCypress, unknown>;
|
|
78
|
+
export declare const cypressGenerator: import("@kubb/kit").Generator<PluginCypress, unknown>;
|
|
79
79
|
/**
|
|
80
80
|
* Canonical plugin name for `@kubb/plugin-cypress`. Used for driver lookups and
|
|
81
81
|
* cross-plugin dependency references.
|
|
@@ -104,7 +104,7 @@ export declare const pluginCypressName = "plugin-cypress";
|
|
|
104
104
|
* })
|
|
105
105
|
* ```
|
|
106
106
|
*/
|
|
107
|
-
export declare const pluginCypress: import("kubb/kit").PluginFactory<PluginCypress>;
|
|
107
|
+
export declare const pluginCypress: import("@kubb/kit").PluginFactory<PluginCypress>;
|
|
108
108
|
/**
|
|
109
109
|
* Default resolver used by `@kubb/plugin-cypress`. Decides the names and file
|
|
110
110
|
* paths for every generated `cy.request()` wrapper. Functions and files use
|
|
@@ -117,6 +117,6 @@ export declare const pluginCypress: import("kubb/kit").PluginFactory<PluginCypre
|
|
|
117
117
|
* resolverCypress.name('list pets') // 'listPets'
|
|
118
118
|
* ```
|
|
119
119
|
*/
|
|
120
|
-
export declare const resolverCypress: import("kubb/kit").Resolver;
|
|
120
|
+
export declare const resolverCypress: import("@kubb/kit").Resolver;
|
|
121
121
|
export { type PluginCypress, type ResolverCypress, pluginCypress as default };
|
|
122
122
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Exclude, Group, Include, Output, OutputOptions, Override, PluginType, Resolver, ResolverPatch, ast } from "kubb/kit";
|
|
1
|
+
import { Exclude, Group, Include, Output, OutputOptions, Override, PluginType, Resolver, ResolverPatch, ast } from "@kubb/kit";
|
|
2
2
|
import { ResolverTs } from "@kubb/plugin-ts";
|
|
3
|
-
import { KubbReactNode } from "kubb/jsx";
|
|
3
|
+
import { KubbReactNode } from "@kubb/renderer-jsx";
|
|
4
4
|
type Props = {
|
|
5
5
|
/**
|
|
6
6
|
* Name of the function
|
|
@@ -75,7 +75,7 @@ declare global {
|
|
|
75
75
|
* `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress
|
|
76
76
|
* test specs and custom commands.
|
|
77
77
|
*/
|
|
78
|
-
export declare const cypressGenerator: import("kubb/kit").Generator<PluginCypress, unknown>;
|
|
78
|
+
export declare const cypressGenerator: import("@kubb/kit").Generator<PluginCypress, unknown>;
|
|
79
79
|
/**
|
|
80
80
|
* Canonical plugin name for `@kubb/plugin-cypress`. Used for driver lookups and
|
|
81
81
|
* cross-plugin dependency references.
|
|
@@ -104,7 +104,7 @@ export declare const pluginCypressName = "plugin-cypress";
|
|
|
104
104
|
* })
|
|
105
105
|
* ```
|
|
106
106
|
*/
|
|
107
|
-
export declare const pluginCypress: import("kubb/kit").PluginFactory<PluginCypress>;
|
|
107
|
+
export declare const pluginCypress: import("@kubb/kit").PluginFactory<PluginCypress>;
|
|
108
108
|
/**
|
|
109
109
|
* Default resolver used by `@kubb/plugin-cypress`. Decides the names and file
|
|
110
110
|
* paths for every generated `cy.request()` wrapper. Functions and files use
|
|
@@ -117,6 +117,6 @@ export declare const pluginCypress: import("kubb/kit").PluginFactory<PluginCypre
|
|
|
117
117
|
* resolverCypress.name('list pets') // 'listPets'
|
|
118
118
|
* ```
|
|
119
119
|
*/
|
|
120
|
-
export declare const resolverCypress: import("kubb/kit").Resolver;
|
|
120
|
+
export declare const resolverCypress: import("@kubb/kit").Resolver;
|
|
121
121
|
export { type PluginCypress, type ResolverCypress, pluginCypress as default };
|
|
122
122
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Resolver, Url, addGenerator, ast, camelCase, createResolver, defineExtension, defineGenerator, setMacros, setResolver } from "kubb/kit";
|
|
2
|
-
import { File, Function, jsxRenderer } from "kubb/jsx";
|
|
3
|
-
import { jsx, jsxs } from "kubb/jsx/jsx-runtime";
|
|
1
|
+
import { Resolver, Url, addGenerator, ast, camelCase, createResolver, defineExtension, defineGenerator, setMacros, setResolver } from "@kubb/kit";
|
|
2
|
+
import { File, Function, jsxRenderer } from "@kubb/renderer-jsx";
|
|
3
|
+
import { jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
|
|
4
4
|
import { pluginTsName } from "@kubb/plugin-ts";
|
|
5
5
|
// ../../internals/shared/src/operation.ts
|
|
6
6
|
/**
|
|
@@ -23,19 +23,19 @@ function operationFileEntry(node, name, extname = ".ts") {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
|
-
* Resolves a dependency plugin's generated file for `node.operationId`, cached in `
|
|
27
|
-
*
|
|
26
|
+
* Resolves a dependency plugin's generated file for `node.operationId`, cached in `memo` (the
|
|
27
|
+
* build's `ctx.memo`) under the resolver's own plugin name and the operation. Several dependents reading the
|
|
28
28
|
* same dependency for the same operation in one pass (a query plugin's several hook generators, the
|
|
29
29
|
* MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
|
|
30
30
|
*
|
|
31
31
|
* @example Cache `plugin-ts`'s file for the current operation
|
|
32
32
|
* ```ts
|
|
33
|
-
* const fileTs = resolveDependencyOperationFile({
|
|
33
|
+
* const fileTs = resolveDependencyOperationFile({ memo: ctx.memo, node, resolver: tsResolver, root, output })
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
36
36
|
function resolveDependencyOperationFile(options) {
|
|
37
|
-
const {
|
|
38
|
-
return
|
|
37
|
+
const { memo, node, resolver, root, output, group } = options;
|
|
38
|
+
return memo(`${resolver.pluginName}:operationFile:${node.operationId}`, () => resolver.file({
|
|
39
39
|
...operationFileEntry(node, node.operationId),
|
|
40
40
|
root,
|
|
41
41
|
output,
|
|
@@ -472,7 +472,7 @@ const cypressGenerator = defineGenerator({
|
|
|
472
472
|
group: group ?? void 0
|
|
473
473
|
}),
|
|
474
474
|
fileTs: resolveDependencyOperationFile({
|
|
475
|
-
|
|
475
|
+
memo: ctx.memo,
|
|
476
476
|
node,
|
|
477
477
|
resolver: tsResolver,
|
|
478
478
|
root,
|
|
@@ -520,7 +520,7 @@ var compatibility = {
|
|
|
520
520
|
"node": ">=22.22"
|
|
521
521
|
};
|
|
522
522
|
// package.json
|
|
523
|
-
var version = "5.2.0
|
|
523
|
+
var version = "5.2.0";
|
|
524
524
|
// src/resolvers/resolverCypress.ts
|
|
525
525
|
/**
|
|
526
526
|
* Default resolver used by `@kubb/plugin-cypress`. Decides the names and file
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../internals/shared/src/operation.ts","../../../internals/utils/src/reserved.ts","../../../internals/shared/src/resolver.ts","../../../internals/shared/src/group.ts","../src/components/Request.tsx","../src/generators/cypressGenerator.tsx","../kubb-extension.json","../package.json","../src/resolvers/resolverCypress.ts","../src/plugin.ts"],"sourcesContent":["import { ast, type Group, type NodeCache, type Output, type Resolver, type ResolverFileParams, Url } from 'kubb/kit'\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\n/**\n * Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the\n * current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the\n * same dependency for the same operation in one pass (a query plugin's several hook generators, the\n * MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.\n *\n * @example Cache `plugin-ts`'s file for the current operation\n * ```ts\n * const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })\n * ```\n */\nexport function resolveDependencyOperationFile(options: {\n cache: NodeCache\n node: ast.OperationNode\n resolver: Pick<Resolver, 'file' | 'pluginName'>\n root: string\n output: Output\n group?: Group | null\n}): ast.FileNode {\n const { cache, node, resolver, root, output, group } = options\n\n return cache.ensureItem(`${resolver.pluginName}:operationFile`, () =>\n resolver.file({ ...operationFileEntry(node, node.operationId), root, output, group: group ?? undefined }),\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\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 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 return node.path ? `{@link ${Url.toPath(node.path)}}` : 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\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`.\nconst requestConfigBaseType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n\nexport function buildRequestConfigType(node: ast.OperationNode): string {\n const request = getContentTypeInfo(node)\n const response = getResponseContentTypeInfo(node)\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 ? `${requestConfigBaseType} & { contentType?: { ${members.join('; ')} } }` : requestConfigBaseType\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 requestConfigBaseType\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 // These callers never carry the `contentType` that several media types require.\n const optionsType = hasRequestContentTypeChoice(node)\n ? `Pick<${resolver.response.options(node)}, ${names.map((name) => `'${name}'`).join(' | ')}>`\n : resolver.response.options(node)\n const firstParam = names.length > 0 ? `{ ${names.join(', ')} }: ${optionsType}${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\nconst operationParameterGroupsByNode = new WeakMap<ast.OperationNode, OperationParameterGroups>()\n\n/**\n * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each\n * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance\n * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the\n * same parameters once per plugin.\n */\nexport function getOperationParameters(node: ast.OperationNode): OperationParameterGroups {\n const cached = operationParameterGroupsByNode.get(node)\n if (cached) return cached\n\n // A malformed spec can declare the same name twice within one location. Both would resolve to the\n // same output property, so emitting both would yield an object type with a duplicate member,\n // which TypeScript rejects. Keep the first.\n const group = (location: ast.ParameterNode['in']) => {\n const seen = new Set<string>()\n\n return node.parameters.filter((param) => {\n if (param.in !== location || seen.has(param.name)) return false\n seen.add(param.name)\n return true\n })\n }\n\n const groups: OperationParameterGroups = { path: group('path'), query: group('query'), header: group('header'), cookie: group('cookie') }\n\n operationParameterGroupsByNode.set(node, groups)\n return groups\n}\n\n/**\n * Builds the combined `{ body, path, query, headers }` options object schema for an operation,\n * referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s\n * `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same\n * shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod\n * printer to emit `z.object(…)` rather than a record.\n */\nexport function hasRequestContentTypeChoice(node: ast.OperationNode): boolean {\n return (node.requestBody?.content ?? []).filter((entry) => entry.schema).length > 1\n}\n\n/**\n * Casts a call argument to the client's parameter type; a `'plain'` client is non-generic.\n */\nexport function castToClientOptions(callArg: string, clientName: string, returnType: 'full' | 'data' | 'plain' = 'full'): string {\n return `${callArg} as Parameters<typeof ${clientName}${returnType === 'plain' ? '' : '<true>'}>[0]`\n}\n\nexport function buildOptionsSchema(node: ast.OperationNode, resolver: OperationTypeNameResolver, { pairContentTypes = false } = {}): ast.SchemaNode {\n const { path, query, header } = getOperationParameters(node)\n const hasBody = Boolean(node.requestBody?.content?.[0]?.schema)\n const createNever = () => ast.factory.createSchema({ type: 'never', primitive: undefined, optional: true })\n const groups = [\n { name: 'path', params: path, resolve: resolver.param.path },\n { name: 'query', params: query, resolve: resolver.param.query },\n { name: 'headers', params: header, resolve: resolver.param.headers },\n ] as const\n\n const createOptions = (body: ast.SchemaNode, extra: Array<ast.PropertyNode> = []) =>\n // NOTE(v5-stable): the fields were renamed from the legacy beta shape\n // (`data`/`pathParams`/`queryParams`/`headerParams`) to `body`/`path`/`query`/`headers` so the\n // type matches the runtime client. Drop this note once v5 leaves beta.\n ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n deprecated: node.deprecated,\n properties: [\n ast.factory.createProperty({ name: 'body', required: hasBody, schema: body }),\n ...groups.map(({ name, params, resolve }) => {\n const required = params.some((param) => param.required)\n\n return ast.factory.createProperty({\n name,\n required,\n schema:\n params.length > 0\n ? ast.factory.createSchema({ type: 'ref', name: resolve.call(resolver.param, node, params[0]!), optional: !required })\n : createNever(),\n })\n }),\n ...extra,\n ],\n })\n\n const variants =\n pairContentTypes && hasRequestContentTypeChoice(node) ? resolveContentTypeVariants(node.requestBody?.content ?? [], resolver.response.body(node)) : []\n if (variants.length < 2) {\n return createOptions(hasBody ? ast.factory.createSchema({ type: 'ref', name: resolver.response.body(node) }) : createNever())\n }\n\n // The first media type is the runtime default, so only the others must pass `contentType`.\n return ast.factory.createSchema({\n type: 'union',\n members: variants.map((variant, index) =>\n createOptions(ast.factory.createSchema({ type: 'ref', name: variant.name }), [\n ast.factory.createProperty({\n name: 'contentType',\n required: index > 0,\n schema: ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: [\n ast.factory.createProperty({\n name: 'request',\n required: true,\n schema: ast.factory.createSchema({ type: 'enum', enumValues: [variant.contentType] }),\n }),\n ],\n }),\n }),\n ]),\n ),\n })\n}\n\n/**\n * The schema a status occupies in the `<Name>Responses` record. A status that documents several\n * content types becomes a `{ contentType; data }` union so the runtime can surface the negotiated type\n * on `result.parsed`, while the standalone `<Name>StatusNNN` alias stays the plain body union that the\n * query hooks and `result.data` use.\n */\nfunction buildResponseRecordEntry(node: ast.OperationNode, res: ast.ResponseNode, resolver: ResponseStatusNameResolver): ast.SchemaNode {\n const statusName = resolver.response.status(node, res.statusCode)\n const variants = (res.content ?? []).filter((entry) => entry.schema)\n if (variants.length <= 1) {\n return ast.factory.createSchema({ type: 'ref', name: statusName })\n }\n\n return ast.factory.createSchema({\n type: 'union',\n members: resolveContentTypeVariants(variants, statusName).map((variant) =>\n ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: [\n ast.factory.createProperty({\n name: 'contentType',\n required: true,\n schema: ast.factory.createSchema({ type: 'enum', enumValues: [variant.contentType] }),\n }),\n ast.factory.createProperty({\n name: 'data',\n required: true,\n schema: ast.factory.createSchema({ type: 'ref', name: variant.name }),\n }),\n ],\n }),\n ),\n })\n}\n\n/**\n * Builds the per-status `<Name>Responses` record for an operation, referencing the already-resolved\n * `<Name>StatusNNN` names. Shared by `@kubb/plugin-ts`'s `Responses` type and `@kubb/plugin-zod`'s\n * inferred responses schema, so both emit the same shape from the same inputs.\n *\n * Always emits the keyed record, even when an operation declares no responses. An operation with no\n * responses renders as an empty object, which keeps every consumer's import (for example the axios\n * SDK's `RequestResult<XResponses>`) resolvable instead of pointing at a missing export.\n */\nexport function buildResponses(node: ast.OperationNode, resolver: ResponseStatusNameResolver): ast.SchemaNode {\n return ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: node.responses.map((res) =>\n ast.factory.createProperty({\n name: String(res.statusCode),\n required: true,\n schema: buildResponseRecordEntry(node, res, resolver),\n }),\n ),\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\n/**\n * Lists the type names an operation's types file declares, computed once per resolver and `options` so every\n * dependent reads the same list.\n */\nexport function resolveOperationTypeNames(\n node: ast.OperationNode,\n resolver: OperationTypeNameResolver & Pick<Resolver, 'memo'>,\n options: ResolveOperationTypeNameOptions = {},\n): string[] {\n const key = `${node.operationId}\\0${options.order ?? ''}\\0${options.responseStatusNames ?? ''}\\0${options.includeParams === false ? 'noparams' : ''}\\0${(options.exclude ?? []).join(',')}`\n return resolver.memo(`operationTypeNames:${key}`, () => {\n const { path, query, header } = getOperationParameters(node)\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 return names.filter((name): name is string => Boolean(name) && !exclude.has(name as string))\n })\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","/**\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 'await',\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 { ensureValidVarName, toFilePath } from '@internals/utils'\nimport { ast, camelCase } from 'kubb/kit'\nimport type { GeneratorContext, Resolver, ResolverFile } from 'kubb/kit'\n\n/**\n * The shared top-level `name` of the operation plugins, computed once per operation name and build.\n */\nexport function resolveOperationName(this: Resolver, name: string): string {\n return this.memo(`operation:${name}`, () => ensureValidVarName(camelCase(name)))\n}\n\n/**\n * Builds the allocation key for a declaration an operation owns. `scope` names which declaration\n * it is, so two of them never share an allocation even when a custom resolver gives both the same\n * name. Leave `scope` empty for the operation's own declaration.\n *\n * @example\n * ```ts\n * resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })\n * ```\n */\nexport function operationKey(node: ast.OperationNode, ...scope: Array<string | number>): Array<string | undefined> {\n return ['operation', node.method, node.path, ...scope.map(String)]\n}\n\n/**\n * The `param` namespace shared by the schema-producing plugins (ts, zod, faker):\n * per-parameter names plus the grouped `Path`/`Query`/`Headers` names, all routed\n * through the plugin's top-level `name` casing.\n */\nexport type OperationParamResolver = {\n name(this: Resolver, node: ast.OperationNode, param: ast.ParameterNode): string\n path(this: Resolver, node: ast.OperationNode): string\n query(this: Resolver, node: ast.OperationNode): string\n headers(this: Resolver, node: ast.OperationNode): string\n}\n\n/**\n * The `response` namespace shared by the schema-producing plugins: per-status,\n * body, and combined response names, all routed through the plugin's top-level\n * `name` casing.\n */\nexport type OperationResponseResolver = {\n status(this: Resolver, node: ast.OperationNode, statusCode: ast.StatusCode): string\n body(this: Resolver, node: ast.OperationNode): string\n responses(this: Resolver, node: ast.OperationNode): string\n response(this: Resolver, node: ast.OperationNode): string\n}\n\n/**\n * Builds the shared `param` namespace. Spread the result into `createResolver`\n * and override individual methods next to it when a plugin deviates.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ param: createOperationParamResolver(), ... })\n * ```\n */\nexport function createOperationParamResolver(): OperationParamResolver {\n return {\n name(node, param) {\n const name = this.name(`${node.operationId} ${param.in} ${param.name}`)\n return this.resolveName({ key: operationKey(node, 'param', 'name', param.in, param.name), name })\n },\n path(node) {\n const name = this.name(`${node.operationId} Path`)\n return this.resolveName({ key: operationKey(node, 'param', 'path'), name })\n },\n query(node) {\n const name = this.name(`${node.operationId} Query`)\n return this.resolveName({ key: operationKey(node, 'param', 'query'), name })\n },\n headers(node) {\n const name = this.name(`${node.operationId} Headers`)\n return this.resolveName({ key: operationKey(node, 'param', 'headers'), name })\n },\n }\n}\n\n/**\n * Builds the shared `response` namespace. Spread the result into\n * `createResolver` and add plugin-specific methods (`options`, `error`) next\n * to it.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ response: { ...createOperationResponseResolver(), options(node) {...} }, ... })\n * ```\n */\nexport function createOperationResponseResolver(): OperationResponseResolver {\n return {\n status(node, statusCode) {\n const name = this.name(`${node.operationId} Status ${statusCode}`)\n return this.resolveName({ key: operationKey(node, 'response', 'status', statusCode), name })\n },\n body(node) {\n const name = this.name(`${node.operationId} Body`)\n return this.resolveName({ key: operationKey(node, 'response', 'body'), name })\n },\n responses(node) {\n const name = this.name(`${node.operationId} Responses`)\n return this.resolveName({ key: operationKey(node, 'response', 'responses'), name })\n },\n response(node) {\n const name = this.name(`${node.operationId} Response`)\n return this.resolveName({ key: operationKey(node, 'response', 'response'), name })\n },\n }\n}\n\n/**\n * Builds a resolver `file` override whose base name runs every path segment\n * through `toFilePath`, casing the final segment with `caseLast`.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ file: createCasedFile(pascalCase), ... })\n * ```\n */\nexport function createCasedFile(caseLast: (part: string) => string): ResolverFile {\n return {\n baseName({ name, extname }) {\n return this.memo(`file:${name}\\0${extname}`, (): ast.FileNode['baseName'] => `${toFilePath(name, caseLast)}${extname}`)\n },\n }\n}\n\ntype SchemaIndexContext = Pick<GeneratorContext, 'memo' | 'driver'>\n\n/**\n * Names of the schemas in a circular reference chain, computed once per build.\n */\nexport function getCircularNames(ctx: SchemaIndexContext): ReadonlySet<string> {\n return ctx.memo('circularNames:set', () => ast.findCircularSchemas(ctx.driver.inputNode?.schemas ?? []))\n}\n\n/**\n * Names of the schemas whose type is `enum`, computed once per build.\n */\nexport function getEnumNames(ctx: SchemaIndexContext): ReadonlySet<string> {\n return ctx.memo(\n 'enumNames:set',\n () => new Set((ctx.driver.inputNode?.schemas ?? []).flatMap((schema) => (schema.type === 'enum' && schema.name ? [schema.name] : []))),\n )\n}\n\ndeclare global {\n namespace Kubb {\n interface MemoRegistry {\n operation: string\n file: ast.FileNode['baseName']\n operationTypeNames: Array<string>\n }\n }\n}\n","import { camelCase, 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 { buildRequestParamsSignature } from '@internals/shared'\nimport { Url } from 'kubb/kit'\nimport type { 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.HttpOperationNode\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 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 // Bracket-access the path object with the raw OpenAPI param names, matching the generated `path` type's keys.\n const urlTemplate = Url.toGroupedTemplateString(node.path, { prefix: baseURL })\n\n const requestOptions = [\n `method: '${node.method}'`,\n `url: ${urlTemplate}`,\n groups.query && 'qs: query',\n groups.headers && 'headers',\n groups.body && 'body',\n '...options',\n ].filter(Boolean)\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 { operationKey, resolveDependencyOperationFile, 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 = ctx.requirePlugin(pluginTsName)\n\n const tsResolver = driver.getResolver(pluginTsName)\n\n const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })]\n const name = resolver.name(node.operationId)\n\n const meta = {\n name: resolver.resolveName({ key: operationKey(node), name }),\n file: resolver.file({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path, root, output, group: group ?? undefined }),\n fileTs: resolveDependencyOperationFile({\n cache: ctx.cache,\n node,\n resolver: tsResolver,\n root,\n output: pluginTs.options?.output ?? output,\n group: pluginTs.options?.group,\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 <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 { resolveOperationName } from '@internals/shared'\nimport { 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 name: resolveOperationName,\n})\n","import { createGroupConfig } from '@internals/shared'\nimport { addGenerator, defineExtension, Resolver, setMacros, setResolver } from 'kubb/kit'\nimport { compatibility } from '../kubb-extension.json'\nimport { version } from '../package.json'\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: './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 = defineExtension<PluginCypress>({\n kind: 'plugin',\n meta: { name: pluginCypressName, version, compatibility },\n dependencies: { [pluginTsName]: {} },\n setup(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 resolver = userResolver ? Resolver.merge<ResolverCypress>(resolverCypress, userResolver) : resolverCypress\n\n setResolver(resolver)\n if (userMacros?.length) {\n setMacros(userMacros)\n }\n addGenerator(cypressGenerator)\n\n return {\n output,\n exclude,\n include,\n override,\n group: createGroupConfig(group),\n baseURL,\n }\n },\n})\n\nexport default pluginCypress\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../internals/shared/src/operation.ts","../../../internals/utils/src/reserved.ts","../../../internals/shared/src/resolver.ts","../../../internals/shared/src/group.ts","../src/components/Request.tsx","../src/generators/cypressGenerator.tsx","../kubb-extension.json","../package.json","../src/resolvers/resolverCypress.ts","../src/plugin.ts"],"sourcesContent":["import { ast, type Group, type Memo, type Output, type Resolver, type ResolverFileParams, Url } from '@kubb/kit'\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\n/**\n * Resolves a dependency plugin's generated file for `node.operationId`, cached in `memo` (the\n * build's `ctx.memo`) under the resolver's own plugin name and the operation. Several dependents reading the\n * same dependency for the same operation in one pass (a query plugin's several hook generators, the\n * MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.\n *\n * @example Cache `plugin-ts`'s file for the current operation\n * ```ts\n * const fileTs = resolveDependencyOperationFile({ memo: ctx.memo, node, resolver: tsResolver, root, output })\n * ```\n */\nexport function resolveDependencyOperationFile(options: {\n memo: Memo\n node: ast.OperationNode\n resolver: Pick<Resolver, 'file' | 'pluginName'>\n root: string\n output: Output\n group?: Group | null\n}): ast.FileNode {\n const { memo, node, resolver, root, output, group } = options\n\n return memo(`${resolver.pluginName}:operationFile:${node.operationId}`, () =>\n resolver.file({ ...operationFileEntry(node, node.operationId), root, output, group: group ?? undefined }),\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\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 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 return node.path ? `{@link ${Url.toPath(node.path)}}` : 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\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`.\nconst requestConfigBaseType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`\n\nexport function buildRequestConfigType(node: ast.OperationNode): string {\n const request = getContentTypeInfo(node)\n const response = getResponseContentTypeInfo(node)\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 ? `${requestConfigBaseType} & { contentType?: { ${members.join('; ')} } }` : requestConfigBaseType\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 requestConfigBaseType\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 // These callers never carry the `contentType` that several media types require.\n const optionsType = hasRequestContentTypeChoice(node)\n ? `Pick<${resolver.response.options(node)}, ${names.map((name) => `'${name}'`).join(' | ')}>`\n : resolver.response.options(node)\n const firstParam = names.length > 0 ? `{ ${names.join(', ')} }: ${optionsType}${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\nconst operationParameterGroupsByNode = new WeakMap<ast.OperationNode, OperationParameterGroups>()\n\n/**\n * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each\n * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance\n * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the\n * same parameters once per plugin.\n */\nexport function getOperationParameters(node: ast.OperationNode): OperationParameterGroups {\n const cached = operationParameterGroupsByNode.get(node)\n if (cached) return cached\n\n // A malformed spec can declare the same name twice within one location. Both would resolve to the\n // same output property, so emitting both would yield an object type with a duplicate member,\n // which TypeScript rejects. Keep the first.\n const group = (location: ast.ParameterNode['in']) => {\n const seen = new Set<string>()\n\n return node.parameters.filter((param) => {\n if (param.in !== location || seen.has(param.name)) return false\n seen.add(param.name)\n return true\n })\n }\n\n const groups: OperationParameterGroups = { path: group('path'), query: group('query'), header: group('header'), cookie: group('cookie') }\n\n operationParameterGroupsByNode.set(node, groups)\n return groups\n}\n\n/**\n * Builds the combined `{ body, path, query, headers }` options object schema for an operation,\n * referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s\n * `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same\n * shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod\n * printer to emit `z.object(…)` rather than a record.\n */\nexport function hasRequestContentTypeChoice(node: ast.OperationNode): boolean {\n return (node.requestBody?.content ?? []).filter((entry) => entry.schema).length > 1\n}\n\n/**\n * Casts a call argument to the client's parameter type; a `'plain'` client is non-generic.\n */\nexport function castToClientOptions(callArg: string, clientName: string, returnType: 'full' | 'data' | 'plain' = 'full'): string {\n return `${callArg} as Parameters<typeof ${clientName}${returnType === 'plain' ? '' : '<true>'}>[0]`\n}\n\nexport function buildOptionsSchema(node: ast.OperationNode, resolver: OperationTypeNameResolver, { pairContentTypes = false } = {}): ast.SchemaNode {\n const { path, query, header } = getOperationParameters(node)\n const hasBody = Boolean(node.requestBody?.content?.[0]?.schema)\n const createNever = () => ast.factory.createSchema({ type: 'never', primitive: undefined, optional: true })\n const groups = [\n { name: 'path', params: path, resolve: resolver.param.path },\n { name: 'query', params: query, resolve: resolver.param.query },\n { name: 'headers', params: header, resolve: resolver.param.headers },\n ] as const\n\n const createOptions = (body: ast.SchemaNode, extra: Array<ast.PropertyNode> = []) =>\n // NOTE(v5-stable): the fields were renamed from the legacy beta shape\n // (`data`/`pathParams`/`queryParams`/`headerParams`) to `body`/`path`/`query`/`headers` so the\n // type matches the runtime client. Drop this note once v5 leaves beta.\n ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n deprecated: node.deprecated,\n properties: [\n ast.factory.createProperty({ name: 'body', required: hasBody, schema: body }),\n ...groups.map(({ name, params, resolve }) => {\n const required = params.some((param) => param.required)\n\n return ast.factory.createProperty({\n name,\n required,\n schema:\n params.length > 0\n ? ast.factory.createSchema({ type: 'ref', name: resolve.call(resolver.param, node, params[0]!), optional: !required })\n : createNever(),\n })\n }),\n ...extra,\n ],\n })\n\n const variants =\n pairContentTypes && hasRequestContentTypeChoice(node) ? resolveContentTypeVariants(node.requestBody?.content ?? [], resolver.response.body(node)) : []\n if (variants.length < 2) {\n return createOptions(hasBody ? ast.factory.createSchema({ type: 'ref', name: resolver.response.body(node) }) : createNever())\n }\n\n // The first media type is the runtime default, so only the others must pass `contentType`.\n return ast.factory.createSchema({\n type: 'union',\n members: variants.map((variant, index) =>\n createOptions(ast.factory.createSchema({ type: 'ref', name: variant.name }), [\n ast.factory.createProperty({\n name: 'contentType',\n required: index > 0,\n schema: ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: [\n ast.factory.createProperty({\n name: 'request',\n required: true,\n schema: ast.factory.createSchema({ type: 'enum', enumValues: [variant.contentType] }),\n }),\n ],\n }),\n }),\n ]),\n ),\n })\n}\n\n/**\n * The schema a status occupies in the `<Name>Responses` record. A status that documents several\n * content types becomes a `{ contentType; data }` union so the runtime can surface the negotiated type\n * on `result.parsed`, while the standalone `<Name>StatusNNN` alias stays the plain body union that the\n * query hooks and `result.data` use.\n */\nfunction buildResponseRecordEntry(node: ast.OperationNode, res: ast.ResponseNode, resolver: ResponseStatusNameResolver): ast.SchemaNode {\n const statusName = resolver.response.status(node, res.statusCode)\n const variants = (res.content ?? []).filter((entry) => entry.schema)\n if (variants.length <= 1) {\n return ast.factory.createSchema({ type: 'ref', name: statusName })\n }\n\n return ast.factory.createSchema({\n type: 'union',\n members: resolveContentTypeVariants(variants, statusName).map((variant) =>\n ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: [\n ast.factory.createProperty({\n name: 'contentType',\n required: true,\n schema: ast.factory.createSchema({ type: 'enum', enumValues: [variant.contentType] }),\n }),\n ast.factory.createProperty({\n name: 'data',\n required: true,\n schema: ast.factory.createSchema({ type: 'ref', name: variant.name }),\n }),\n ],\n }),\n ),\n })\n}\n\n/**\n * Builds the per-status `<Name>Responses` record for an operation, referencing the already-resolved\n * `<Name>StatusNNN` names. Shared by `@kubb/plugin-ts`'s `Responses` type and `@kubb/plugin-zod`'s\n * inferred responses schema, so both emit the same shape from the same inputs.\n *\n * Always emits the keyed record, even when an operation declares no responses. An operation with no\n * responses renders as an empty object, which keeps every consumer's import (for example the axios\n * SDK's `RequestResult<XResponses>`) resolvable instead of pointing at a missing export.\n */\nexport function buildResponses(node: ast.OperationNode, resolver: ResponseStatusNameResolver): ast.SchemaNode {\n return ast.factory.createSchema({\n type: 'object',\n primitive: 'object',\n properties: node.responses.map((res) =>\n ast.factory.createProperty({\n name: String(res.statusCode),\n required: true,\n schema: buildResponseRecordEntry(node, res, resolver),\n }),\n ),\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\n/**\n * Lists the type names an operation's types file declares, computed once per resolver and `options` so every\n * dependent reads the same list.\n */\nexport function resolveOperationTypeNames(\n node: ast.OperationNode,\n resolver: OperationTypeNameResolver & Pick<Resolver, 'memo'>,\n options: ResolveOperationTypeNameOptions = {},\n): string[] {\n const key = `${node.operationId}\\0${options.order ?? ''}\\0${options.responseStatusNames ?? ''}\\0${options.includeParams === false ? 'noparams' : ''}\\0${(options.exclude ?? []).join(',')}`\n return resolver.memo(`operationTypeNames:${key}`, () => {\n const { path, query, header } = getOperationParameters(node)\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 return names.filter((name): name is string => Boolean(name) && !exclude.has(name as string))\n })\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","/**\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 'await',\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 { ensureValidVarName, toFilePath } from '@internals/utils'\nimport { ast, camelCase } from '@kubb/kit'\nimport type { GeneratorContext, Resolver, ResolverFile } from '@kubb/kit'\n\n/**\n * The shared top-level `name` of the operation plugins, computed once per operation name and build.\n */\nexport function resolveOperationName(this: Resolver, name: string): string {\n return this.memo(`operation:${name}`, () => ensureValidVarName(camelCase(name)))\n}\n\n/**\n * Builds the allocation key for a declaration an operation owns. `scope` names which declaration\n * it is, so two of them never share an allocation even when a custom resolver gives both the same\n * name. Leave `scope` empty for the operation's own declaration.\n *\n * @example\n * ```ts\n * resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })\n * ```\n */\nexport function operationKey(node: ast.OperationNode, ...scope: Array<string | number>): Array<string | undefined> {\n return ['operation', node.method, node.path, ...scope.map(String)]\n}\n\n/**\n * The `param` namespace shared by the schema-producing plugins (ts, zod, faker):\n * per-parameter names plus the grouped `Path`/`Query`/`Headers` names, all routed\n * through the plugin's top-level `name` casing.\n */\nexport type OperationParamResolver = {\n name(this: Resolver, node: ast.OperationNode, param: ast.ParameterNode): string\n path(this: Resolver, node: ast.OperationNode): string\n query(this: Resolver, node: ast.OperationNode): string\n headers(this: Resolver, node: ast.OperationNode): string\n}\n\n/**\n * The `response` namespace shared by the schema-producing plugins: per-status,\n * body, and combined response names, all routed through the plugin's top-level\n * `name` casing.\n */\nexport type OperationResponseResolver = {\n status(this: Resolver, node: ast.OperationNode, statusCode: ast.StatusCode): string\n body(this: Resolver, node: ast.OperationNode): string\n responses(this: Resolver, node: ast.OperationNode): string\n response(this: Resolver, node: ast.OperationNode): string\n}\n\n/**\n * Builds the shared `param` namespace. Spread the result into `createResolver`\n * and override individual methods next to it when a plugin deviates.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ param: createOperationParamResolver(), ... })\n * ```\n */\nexport function createOperationParamResolver(): OperationParamResolver {\n return {\n name(node, param) {\n const name = this.name(`${node.operationId} ${param.in} ${param.name}`)\n return this.resolveName({ key: operationKey(node, 'param', 'name', param.in, param.name), name })\n },\n path(node) {\n const name = this.name(`${node.operationId} Path`)\n return this.resolveName({ key: operationKey(node, 'param', 'path'), name })\n },\n query(node) {\n const name = this.name(`${node.operationId} Query`)\n return this.resolveName({ key: operationKey(node, 'param', 'query'), name })\n },\n headers(node) {\n const name = this.name(`${node.operationId} Headers`)\n return this.resolveName({ key: operationKey(node, 'param', 'headers'), name })\n },\n }\n}\n\n/**\n * Builds the shared `response` namespace. Spread the result into\n * `createResolver` and add plugin-specific methods (`options`, `error`) next\n * to it.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ response: { ...createOperationResponseResolver(), options(node) {...} }, ... })\n * ```\n */\nexport function createOperationResponseResolver(): OperationResponseResolver {\n return {\n status(node, statusCode) {\n const name = this.name(`${node.operationId} Status ${statusCode}`)\n return this.resolveName({ key: operationKey(node, 'response', 'status', statusCode), name })\n },\n body(node) {\n const name = this.name(`${node.operationId} Body`)\n return this.resolveName({ key: operationKey(node, 'response', 'body'), name })\n },\n responses(node) {\n const name = this.name(`${node.operationId} Responses`)\n return this.resolveName({ key: operationKey(node, 'response', 'responses'), name })\n },\n response(node) {\n const name = this.name(`${node.operationId} Response`)\n return this.resolveName({ key: operationKey(node, 'response', 'response'), name })\n },\n }\n}\n\n/**\n * Builds a resolver `file` override whose base name runs every path segment\n * through `toFilePath`, casing the final segment with `caseLast`.\n *\n * @example\n * ```ts\n * createResolver<PluginTs>({ file: createCasedFile(pascalCase), ... })\n * ```\n */\nexport function createCasedFile(caseLast: (part: string) => string): ResolverFile {\n return {\n baseName({ name, extname }) {\n return this.memo(`file:${name}\\0${extname}`, (): ast.FileNode['baseName'] => `${toFilePath(name, caseLast)}${extname}`)\n },\n }\n}\n\ntype SchemaIndexContext = Pick<GeneratorContext, 'memo' | 'driver'>\n\n/**\n * Names of the schemas in a circular reference chain, computed once per build.\n */\nexport function getCircularNames(ctx: SchemaIndexContext): ReadonlySet<string> {\n return ctx.memo('circularNames:set', () => ast.findCircularSchemas(ctx.driver.inputNode?.schemas ?? []))\n}\n\n/**\n * Names of the schemas whose type is `enum`, computed once per build.\n */\nexport function getEnumNames(ctx: SchemaIndexContext): ReadonlySet<string> {\n return ctx.memo(\n 'enumNames:set',\n () => new Set((ctx.driver.inputNode?.schemas ?? []).flatMap((schema) => (schema.type === 'enum' && schema.name ? [schema.name] : []))),\n )\n}\n\ndeclare global {\n namespace Kubb {\n interface MemoRegistry {\n operation: string\n file: ast.FileNode['baseName']\n operationTypeNames: Array<string>\n }\n }\n}\n","import { camelCase, 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 { buildRequestParamsSignature } from '@internals/shared'\nimport { Url } from '@kubb/kit'\nimport type { ast } from '@kubb/kit'\nimport type { ResolverTs } from '@kubb/plugin-ts'\nimport { File, Function } from '@kubb/renderer-jsx'\nimport type { KubbReactNode } from '@kubb/renderer-jsx'\n\ntype Props = {\n /**\n * Name of the function\n */\n name: string\n /**\n * AST operation node\n */\n node: ast.HttpOperationNode\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 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 // Bracket-access the path object with the raw OpenAPI param names, matching the generated `path` type's keys.\n const urlTemplate = Url.toGroupedTemplateString(node.path, { prefix: baseURL })\n\n const requestOptions = [\n `method: '${node.method}'`,\n `url: ${urlTemplate}`,\n groups.query && 'qs: query',\n groups.headers && 'headers',\n groups.body && 'body',\n '...options',\n ].filter(Boolean)\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 { operationKey, resolveDependencyOperationFile, resolveOperationTypeNames } from '@internals/shared'\nimport { ast, defineGenerator } from '@kubb/kit'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { File, jsxRenderer } from '@kubb/renderer-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 = ctx.requirePlugin(pluginTsName)\n\n const tsResolver = driver.getResolver(pluginTsName)\n\n const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })]\n const name = resolver.name(node.operationId)\n\n const meta = {\n name: resolver.resolveName({ key: operationKey(node), name }),\n file: resolver.file({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path, root, output, group: group ?? undefined }),\n fileTs: resolveDependencyOperationFile({\n memo: ctx.memo,\n node,\n resolver: tsResolver,\n root,\n output: pluginTs.options?.output ?? output,\n group: pluginTs.options?.group,\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 <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 { resolveOperationName } from '@internals/shared'\nimport { 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 name: resolveOperationName,\n})\n","import { createGroupConfig } from '@internals/shared'\nimport { addGenerator, defineExtension, Resolver, setMacros, setResolver } from '@kubb/kit'\nimport { compatibility } from '../kubb-extension.json'\nimport { version } from '../package.json'\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: './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 = defineExtension<PluginCypress>({\n kind: 'plugin',\n meta: { name: pluginCypressName, version, compatibility },\n dependencies: { [pluginTsName]: {} },\n setup(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 resolver = userResolver ? Resolver.merge<ResolverCypress>(resolverCypress, userResolver) : resolverCypress\n\n setResolver(resolver)\n if (userMacros?.length) {\n setMacros(userMacros)\n }\n addGenerator(cypressGenerator)\n\n return {\n output,\n exclude,\n include,\n override,\n group: createGroupConfig(group),\n baseURL,\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.2.0
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "Generate Cypress request commands and e2e test fixtures with Kubb for automated API testing.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"code-generation",
|
|
@@ -68,17 +68,17 @@
|
|
|
68
68
|
"registry": "https://registry.npmjs.org/"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@kubb/
|
|
71
|
+
"@kubb/kit": "^5.15.2",
|
|
72
|
+
"@kubb/plugin-ts": "^5.4.0",
|
|
73
|
+
"@kubb/renderer-jsx": "^5.15.2"
|
|
72
74
|
},
|
|
73
75
|
"devDependencies": {
|
|
74
|
-
"@internals/shared": "0.
|
|
75
|
-
"@internals/utils": "0.
|
|
76
|
-
"cypress": "^16.2.0"
|
|
77
|
-
"kubb": "^5.15.1"
|
|
76
|
+
"@internals/shared": "0.0.0",
|
|
77
|
+
"@internals/utils": "0.0.0",
|
|
78
|
+
"cypress": "^16.2.0"
|
|
78
79
|
},
|
|
79
80
|
"peerDependencies": {
|
|
80
|
-
"cypress": "^15.0.0 || ^16.0.0"
|
|
81
|
-
"kubb": "^5.15.0"
|
|
81
|
+
"cypress": "^15.0.0 || ^16.0.0"
|
|
82
82
|
},
|
|
83
83
|
"peerDependenciesMeta": {
|
|
84
84
|
"cypress": {
|