@kubb/plugin-cypress 5.0.0-alpha.23 → 5.0.0-alpha.24

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/plugin-cypress",
3
- "version": "5.0.0-alpha.23",
3
+ "version": "5.0.0-alpha.24",
4
4
  "description": "Cypress test generator plugin for Kubb, creating end-to-end tests from OpenAPI specifications for automated API testing.",
5
5
  "keywords": [
6
6
  "cypress",
@@ -34,33 +34,10 @@
34
34
  "import": "./dist/index.js",
35
35
  "require": "./dist/index.cjs"
36
36
  },
37
- "./components": {
38
- "import": "./dist/components.js",
39
- "require": "./dist/components.cjs"
40
- },
41
- "./generators": {
42
- "import": "./dist/generators.js",
43
- "require": "./dist/generators.cjs"
44
- },
45
37
  "./package.json": "./package.json"
46
38
  },
47
39
  "types": "./dist/index.d.ts",
48
- "typesVersions": {
49
- "*": {
50
- "utils": [
51
- "./dist/utils.d.ts"
52
- ],
53
- "hooks": [
54
- "./dist/hooks.d.ts"
55
- ],
56
- "components": [
57
- "./dist/components.d.ts"
58
- ],
59
- "generators": [
60
- "./dist/generators.d.ts"
61
- ]
62
- }
63
- },
40
+ "typesVersions": {},
64
41
  "files": [
65
42
  "src",
66
43
  "dist",
@@ -77,10 +54,9 @@
77
54
  ],
78
55
  "dependencies": {
79
56
  "@kubb/react-fabric": "0.15.1",
80
- "@kubb/core": "5.0.0-alpha.23",
81
- "@kubb/oas": "5.0.0-alpha.23",
82
- "@kubb/plugin-oas": "5.0.0-alpha.23",
83
- "@kubb/plugin-ts": "5.0.0-alpha.23"
57
+ "@kubb/ast": "5.0.0-alpha.24",
58
+ "@kubb/core": "5.0.0-alpha.24",
59
+ "@kubb/plugin-ts": "5.0.0-alpha.24"
84
60
  },
85
61
  "engines": {
86
62
  "node": ">=22"
@@ -1,8 +1,9 @@
1
- import { URLPath } from '@internals/utils'
2
- import { type HttpMethod, isAllOptional, isOptional } from '@kubb/oas'
3
- import type { OperationSchemas } from '@kubb/plugin-oas'
4
- import { getPathParams } from '@kubb/plugin-oas/utils'
5
- import { File, Function, FunctionParams } from '@kubb/react-fabric'
1
+ import { camelCase, URLPath } from '@internals/utils'
2
+ import { caseParams, createFunctionParameter, createOperationParams, createTypeNode } from '@kubb/ast'
3
+ import type { OperationNode } from '@kubb/ast/types'
4
+ import type { ResolverTs } from '@kubb/plugin-ts'
5
+ import { functionPrinter } from '@kubb/plugin-ts'
6
+ import { File, Function } from '@kubb/react-fabric'
6
7
  import type { FabricReactNode } from '@kubb/react-fabric/types'
7
8
  import type { PluginCypress } from '../types.ts'
8
9
 
@@ -11,132 +12,114 @@ type Props = {
11
12
  * Name of the function
12
13
  */
13
14
  name: string
14
- typeSchemas: OperationSchemas
15
- url: string
15
+ /**
16
+ * AST operation node
17
+ */
18
+ node: OperationNode
19
+ /**
20
+ * TypeScript resolver for resolving param/data/response type names
21
+ */
22
+ resolver: ResolverTs
16
23
  baseURL: string | undefined
17
24
  dataReturnType: PluginCypress['resolvedOptions']['dataReturnType']
18
25
  paramsCasing: PluginCypress['resolvedOptions']['paramsCasing']
19
26
  paramsType: PluginCypress['resolvedOptions']['paramsType']
20
27
  pathParamsType: PluginCypress['resolvedOptions']['pathParamsType']
21
- method: HttpMethod
22
28
  }
23
29
 
24
- type GetParamsProps = {
25
- paramsCasing: PluginCypress['resolvedOptions']['paramsCasing']
30
+ const declarationPrinter = functionPrinter({ mode: 'declaration' })
31
+
32
+ function getParams({
33
+ paramsType,
34
+ pathParamsType,
35
+ paramsCasing,
36
+ resolver,
37
+ node,
38
+ }: {
26
39
  paramsType: PluginCypress['resolvedOptions']['paramsType']
27
40
  pathParamsType: PluginCypress['resolvedOptions']['pathParamsType']
28
- typeSchemas: OperationSchemas
29
- }
30
-
31
- function getParams({ paramsType, paramsCasing, pathParamsType, typeSchemas }: GetParamsProps) {
32
- if (paramsType === 'object') {
33
- const pathParams = getPathParams(typeSchemas.pathParams, { typed: true, casing: paramsCasing })
34
-
35
- return FunctionParams.factory({
36
- data: {
37
- mode: 'object',
38
- children: {
39
- ...pathParams,
40
- data: typeSchemas.request?.name
41
- ? {
42
- type: typeSchemas.request?.name,
43
- optional: isOptional(typeSchemas.request?.schema),
44
- }
45
- : undefined,
46
- params: typeSchemas.queryParams?.name
47
- ? {
48
- type: typeSchemas.queryParams?.name,
49
- optional: isOptional(typeSchemas.queryParams?.schema),
50
- }
51
- : undefined,
52
- headers: typeSchemas.headerParams?.name
53
- ? {
54
- type: typeSchemas.headerParams?.name,
55
- optional: isOptional(typeSchemas.headerParams?.schema),
56
- }
57
- : undefined,
58
- },
59
- },
60
- options: {
61
- type: 'Partial<Cypress.RequestOptions>',
62
- default: '{}',
63
- },
64
- })
65
- }
66
-
67
- return FunctionParams.factory({
68
- pathParams: typeSchemas.pathParams?.name
69
- ? {
70
- mode: pathParamsType === 'object' ? 'object' : 'inlineSpread',
71
- children: getPathParams(typeSchemas.pathParams, { typed: true, casing: paramsCasing }),
72
- default: isAllOptional(typeSchemas.pathParams?.schema) ? '{}' : undefined,
73
- }
74
- : undefined,
75
- data: typeSchemas.request?.name
76
- ? {
77
- type: typeSchemas.request?.name,
78
- optional: isOptional(typeSchemas.request?.schema),
79
- }
80
- : undefined,
81
- params: typeSchemas.queryParams?.name
82
- ? {
83
- type: typeSchemas.queryParams?.name,
84
- optional: isOptional(typeSchemas.queryParams?.schema),
85
- }
86
- : undefined,
87
- headers: typeSchemas.headerParams?.name
88
- ? {
89
- type: typeSchemas.headerParams?.name,
90
- optional: isOptional(typeSchemas.headerParams?.schema),
91
- }
92
- : undefined,
93
- options: {
94
- type: 'Partial<Cypress.RequestOptions>',
95
- default: '{}',
96
- },
41
+ paramsCasing: PluginCypress['resolvedOptions']['paramsCasing']
42
+ resolver: ResolverTs
43
+ node: OperationNode
44
+ }): string {
45
+ const paramsNode = createOperationParams(node, {
46
+ paramsType,
47
+ pathParamsType,
48
+ paramsCasing,
49
+ resolver,
50
+ extraParams: [
51
+ createFunctionParameter({ name: 'options', type: createTypeNode({ variant: 'reference', name: 'Partial<Cypress.RequestOptions>' }), default: '{}' }),
52
+ ],
97
53
  })
98
- }
99
54
 
100
- export function Request({ baseURL = '', name, dataReturnType, typeSchemas, url, method, paramsType, paramsCasing, pathParamsType }: Props): FabricReactNode {
101
- const path = new URLPath(url, { casing: paramsCasing })
102
-
103
- const params = getParams({ paramsType, paramsCasing, pathParamsType, typeSchemas })
55
+ return declarationPrinter.print(paramsNode) ?? ''
56
+ }
104
57
 
105
- const returnType =
106
- dataReturnType === 'data' ? `Cypress.Chainable<${typeSchemas.response.name}>` : `Cypress.Chainable<Cypress.Response<${typeSchemas.response.name}>>`
58
+ export function Request({ baseURL = '', name, dataReturnType, resolver, node, paramsType, pathParamsType, paramsCasing }: Props): FabricReactNode {
59
+ const paramsSignature = getParams({ paramsType, pathParamsType, paramsCasing, resolver, node })
107
60
 
108
- // Build the URL template string - this will convert /pets/:petId to /pets/${petId}
109
- const urlTemplate = path.toTemplateString({ prefix: baseURL })
61
+ const responseType = resolver.resolveResponseName(node)
62
+ const returnType = dataReturnType === 'data' ? `Cypress.Chainable<${responseType}>` : `Cypress.Chainable<Cypress.Response<${responseType}>>`
110
63
 
111
- // Build request options object
112
- const requestOptions: string[] = [`method: '${method}'`, `url: ${urlTemplate}`]
64
+ const casedPathParams = caseParams(
65
+ node.parameters.filter((p) => p.in === 'path'),
66
+ paramsCasing,
67
+ )
68
+ // Build a lookup keyed by camelCase-normalized name so that path-template names
69
+ // (e.g. `{pet_id}`) correctly resolve to the function-parameter name (`petId`)
70
+ // even when the OpenAPI spec has inconsistent casing between the two.
71
+ const pathParamNameMap = new Map(casedPathParams.map((p) => [camelCase(p.name), p.name]))
72
+
73
+ const urlPath = new URLPath(node.path, { casing: paramsCasing })
74
+ const urlTemplate = urlPath.toTemplateString({
75
+ prefix: baseURL,
76
+ replacer: (param) => pathParamNameMap.get(camelCase(param)) ?? param,
77
+ })
113
78
 
114
- // Add query params if they exist
115
- if (typeSchemas.queryParams?.name) {
116
- requestOptions.push('qs: params')
79
+ const requestOptions: string[] = [`method: '${node.method}'`, `url: ${urlTemplate}`]
80
+
81
+ const queryParams = node.parameters.filter((p) => p.in === 'query')
82
+ if (queryParams.length > 0) {
83
+ const casedQueryParams = caseParams(queryParams, paramsCasing)
84
+ // When paramsCasing renames query params (e.g. page_size → pageSize), we must remap
85
+ // the camelCase keys back to the original API names before passing them to `qs`.
86
+ const needsQsTransform = casedQueryParams.some((p, i) => p.name !== queryParams[i]!.name)
87
+ if (needsQsTransform) {
88
+ const pairs = queryParams.map((orig, i) => `${orig.name}: params.${casedQueryParams[i]!.name}`).join(', ')
89
+ requestOptions.push(`qs: params ? { ${pairs} } : undefined`)
90
+ } else {
91
+ requestOptions.push('qs: params')
92
+ }
117
93
  }
118
94
 
119
- // Add headers if they exist
120
- if (typeSchemas.headerParams?.name) {
121
- requestOptions.push('headers')
95
+ const headerParams = node.parameters.filter((p) => p.in === 'header')
96
+ if (headerParams.length > 0) {
97
+ const casedHeaderParams = caseParams(headerParams, paramsCasing)
98
+ // When paramsCasing renames header params (e.g. x-api-key → xApiKey), we must remap
99
+ // the camelCase keys back to the original API names before passing them to `headers`.
100
+ const needsHeaderTransform = casedHeaderParams.some((p, i) => p.name !== headerParams[i]!.name)
101
+ if (needsHeaderTransform) {
102
+ const pairs = headerParams.map((orig, i) => `'${orig.name}': headers.${casedHeaderParams[i]!.name}`).join(', ')
103
+ requestOptions.push(`headers: headers ? { ${pairs} } : undefined`)
104
+ } else {
105
+ requestOptions.push('headers')
106
+ }
122
107
  }
123
108
 
124
- // Add body if request schema exists
125
- if (typeSchemas.request?.name) {
109
+ if (node.requestBody?.schema) {
126
110
  requestOptions.push('body: data')
127
111
  }
128
112
 
129
- // Spread additional Cypress options
130
113
  requestOptions.push('...options')
131
114
 
132
115
  return (
133
116
  <File.Source name={name} isIndexable isExportable>
134
- <Function name={name} export params={params.toConstructor()} returnType={returnType}>
117
+ <Function name={name} export params={paramsSignature} returnType={returnType}>
135
118
  {dataReturnType === 'data'
136
- ? `return cy.request<${typeSchemas.response.name}>({
119
+ ? `return cy.request<${responseType}>({
137
120
  ${requestOptions.join(',\n ')}
138
121
  }).then((res) => res.body)`
139
- : `return cy.request<${typeSchemas.response.name}>({
122
+ : `return cy.request<${responseType}>({
140
123
  ${requestOptions.join(',\n ')}
141
124
  })`}
142
125
  </Function>
@@ -1,64 +1,76 @@
1
- import { useDriver } from '@kubb/core/hooks'
2
- import { createReactGenerator } from '@kubb/plugin-oas/generators'
3
- import { useOas, useOperationManager } from '@kubb/plugin-oas/hooks'
4
- import { getBanner, getFooter } from '@kubb/plugin-oas/utils'
1
+ import path from 'node:path'
2
+ import { caseParams } from '@kubb/ast'
3
+ import { defineGenerator } from '@kubb/core'
4
+ import type { PluginTs } from '@kubb/plugin-ts'
5
5
  import { pluginTsName } from '@kubb/plugin-ts'
6
6
  import { File } from '@kubb/react-fabric'
7
- import { Request } from '../components'
8
- import type { PluginCypress } from '../types'
7
+ import { Request } from '../components/Request.tsx'
8
+ import type { PluginCypress } from '../types.ts'
9
9
 
10
- export const cypressGenerator = createReactGenerator<PluginCypress>({
10
+ export const cypressGenerator = defineGenerator<PluginCypress>({
11
11
  name: 'cypress',
12
- Operation({ operation, generator, plugin }) {
13
- const {
14
- options: { output, baseURL, dataReturnType, paramsCasing, paramsType, pathParamsType },
15
- } = plugin
16
- const driver = useDriver()
12
+ type: 'react',
13
+ Operation({ node, adapter, options, config, driver, resolver }) {
14
+ const { output, baseURL, dataReturnType, paramsCasing, paramsType, pathParamsType, group } = options
15
+ const root = path.resolve(config.root, config.output.path)
17
16
 
18
- const oas = useOas()
19
- const { getSchemas, getName, getFile } = useOperationManager(generator)
17
+ const pluginTs = driver.getPlugin<PluginTs>(pluginTsName)
20
18
 
21
- const request = {
22
- name: getName(operation, { type: 'function' }),
23
- file: getFile(operation),
19
+ if (!pluginTs) {
20
+ return null
24
21
  }
25
22
 
26
- const type = {
27
- file: getFile(operation, { pluginName: pluginTsName }),
28
- schemas: getSchemas(operation, { pluginName: pluginTsName, type: 'type' }),
29
- }
23
+ const file = resolver.resolveFile({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group })
24
+ const tsFile = pluginTs.resolver.resolveFile(
25
+ { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
26
+ {
27
+ root,
28
+ output: pluginTs.options?.output ?? output,
29
+ group: pluginTs.options?.group,
30
+ },
31
+ )
32
+
33
+ const name = resolver.resolveName(node.operationId)
34
+
35
+ const casedParams = caseParams(node.parameters, paramsCasing)
36
+ const tsResolver = pluginTs.resolver
37
+
38
+ const pathParams = casedParams.filter((p) => p.in === 'path')
39
+ const queryParams = casedParams.filter((p) => p.in === 'query')
40
+ const headerParams = casedParams.filter((p) => p.in === 'header')
41
+
42
+ const importedTypeNames = [
43
+ ...(pathParams.length && tsResolver.resolvePathParamsName
44
+ ? pathParams.map((p) => tsResolver.resolvePathParamsName!(node, p))
45
+ : pathParams.map((p) => tsResolver.resolveParamName(node, p))),
46
+ ...(queryParams.length && tsResolver.resolveQueryParamsName
47
+ ? queryParams.map((p) => tsResolver.resolveQueryParamsName!(node, p))
48
+ : queryParams.map((p) => tsResolver.resolveParamName(node, p))),
49
+ ...(headerParams.length && tsResolver.resolveHeaderParamsName
50
+ ? headerParams.map((p) => tsResolver.resolveHeaderParamsName!(node, p))
51
+ : headerParams.map((p) => tsResolver.resolveParamName(node, p))),
52
+ node.requestBody?.schema ? tsResolver.resolveDataName(node) : undefined,
53
+ tsResolver.resolveResponseName(node),
54
+ ].filter(Boolean)
30
55
 
31
56
  return (
32
57
  <File
33
- baseName={request.file.baseName}
34
- path={request.file.path}
35
- meta={request.file.meta}
36
- banner={getBanner({ oas, output, config: driver.config })}
37
- footer={getFooter({ oas, output })}
58
+ baseName={file.baseName}
59
+ path={file.path}
60
+ meta={file.meta}
61
+ banner={resolver.resolveBanner(adapter.rootNode, { output, config })}
62
+ footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
38
63
  >
39
- <File.Import
40
- name={[
41
- type.schemas.request?.name,
42
- type.schemas.response.name,
43
- type.schemas.pathParams?.name,
44
- type.schemas.queryParams?.name,
45
- type.schemas.headerParams?.name,
46
- ...(type.schemas.statusCodes?.map((item) => item.name) || []),
47
- ].filter(Boolean)}
48
- root={request.file.path}
49
- path={type.file.path}
50
- isTypeOnly
51
- />
64
+ {tsFile && importedTypeNames.length > 0 && <File.Import name={Array.from(new Set(importedTypeNames))} root={file.path} path={tsFile.path} isTypeOnly />}
52
65
  <Request
53
- name={request.name}
66
+ name={name}
67
+ node={node}
68
+ resolver={tsResolver}
54
69
  dataReturnType={dataReturnType}
55
70
  paramsCasing={paramsCasing}
56
71
  paramsType={paramsType}
57
72
  pathParamsType={pathParamsType}
58
- typeSchemas={type.schemas}
59
- method={operation.method}
60
73
  baseURL={baseURL}
61
- url={operation.path}
62
74
  />
63
75
  </File>
64
76
  )
package/src/index.ts CHANGED
@@ -1,2 +1,9 @@
1
+ export { Request } from './components/Request.tsx'
2
+
3
+ export { cypressGenerator } from './generators/cypressGenerator.tsx'
4
+
1
5
  export { pluginCypress, pluginCypressName } from './plugin.ts'
2
- export type { PluginCypress } from './types.ts'
6
+
7
+ export { resolverCypress } from './resolvers/resolverCypress.ts'
8
+
9
+ export type { PluginCypress, ResolverCypress } from './types.ts'
package/src/plugin.ts CHANGED
@@ -1,13 +1,34 @@
1
1
  import path from 'node:path'
2
2
  import { camelCase } from '@internals/utils'
3
- import { createPlugin, type Group, getBarrelFiles, getMode } from '@kubb/core'
4
- import { OperationGenerator, pluginOasName } from '@kubb/plugin-oas'
3
+ import { walk } from '@kubb/ast'
4
+ import { createPlugin, type Group, getBarrelFiles, getPreset, renderOperation } from '@kubb/core'
5
5
  import { pluginTsName } from '@kubb/plugin-ts'
6
- import { cypressGenerator } from './generators'
6
+ import { presets } from './presets.ts'
7
+ import { resolverCypress } from './resolvers/resolverCypress.ts'
7
8
  import type { PluginCypress } from './types.ts'
8
9
 
10
+ /**
11
+ * Canonical plugin name for `@kubb/plugin-cypress`, used to identify the plugin
12
+ * in driver lookups and warnings.
13
+ */
9
14
  export const pluginCypressName = 'plugin-cypress' satisfies PluginCypress['name']
10
15
 
16
+ /**
17
+ * The `@kubb/plugin-cypress` plugin factory.
18
+ *
19
+ * Generates Cypress `cy.request()` test functions from an OpenAPI/AST `RootNode`.
20
+ * Walks operations, delegates rendering to the active generators,
21
+ * and writes barrel files based on `output.barrelType`.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * import { pluginCypress } from '@kubb/plugin-cypress'
26
+ *
27
+ * export default defineConfig({
28
+ * plugins: [pluginCypress({ output: { path: 'cypress' } })],
29
+ * })
30
+ * ```
31
+ */
11
32
  export const pluginCypress = createPlugin<PluginCypress>((options) => {
12
33
  const {
13
34
  output = { path: 'cypress', barrelType: 'named' },
@@ -16,94 +37,97 @@ export const pluginCypress = createPlugin<PluginCypress>((options) => {
16
37
  exclude = [],
17
38
  include,
18
39
  override = [],
19
- transformers = {},
20
- generators = [cypressGenerator].filter(Boolean),
21
- contentType,
22
40
  baseURL,
23
41
  paramsCasing,
24
42
  paramsType = 'inline',
25
43
  pathParamsType = paramsType === 'object' ? 'object' : options.pathParamsType || 'inline',
44
+ compatibilityPreset = 'default',
45
+ resolvers: userResolvers = [],
46
+ transformers: userTransformers = [],
47
+ generators: userGenerators = [],
26
48
  } = options
27
49
 
50
+ const preset = getPreset({
51
+ preset: compatibilityPreset,
52
+ presets,
53
+ resolvers: [resolverCypress, ...userResolvers],
54
+ transformers: userTransformers,
55
+ generators: userGenerators,
56
+ })
57
+
28
58
  return {
29
59
  name: pluginCypressName,
30
- options: {
31
- output,
32
- dataReturnType,
33
- group,
34
- baseURL,
35
-
36
- paramsCasing,
37
- paramsType,
38
- pathParamsType,
60
+ get resolver() {
61
+ return preset.resolver
39
62
  },
40
- pre: [pluginOasName, pluginTsName].filter(Boolean),
41
- resolvePath(baseName, pathMode, options) {
42
- const root = path.resolve(this.config.root, this.config.output.path)
43
- const mode = pathMode ?? getMode(path.resolve(root, output.path))
44
-
45
- if (mode === 'single') {
46
- /**
47
- * when output is a file then we will always append to the same file(output file), see fileManager.addOrAppend
48
- * Other plugins then need to call addOrAppend instead of just add from the fileManager class
49
- */
50
- return path.resolve(root, output.path)
63
+ get options() {
64
+ return {
65
+ output,
66
+ dataReturnType,
67
+ group: group
68
+ ? ({
69
+ ...options.group,
70
+ name: options.group?.name
71
+ ? options.group.name
72
+ : (ctx: { group: string }) => {
73
+ if (group.type === 'path') {
74
+ return `${ctx.group.split('/')[1]}`
75
+ }
76
+ return `${camelCase(ctx.group)}Requests`
77
+ },
78
+ } as Group)
79
+ : undefined,
80
+ baseURL,
81
+ paramsCasing,
82
+ paramsType,
83
+ pathParamsType,
84
+ resolver: preset.resolver,
85
+ transformers: preset.transformers,
51
86
  }
87
+ },
88
+ pre: [pluginTsName].filter(Boolean),
89
+ async install() {
90
+ const { config, fabric, plugin, adapter, rootNode, driver } = this
91
+ const root = path.resolve(config.root, config.output.path)
92
+ const resolver = preset.resolver
52
93
 
53
- if (group && (options?.group?.path || options?.group?.tag)) {
54
- const groupName: Group['name'] = group?.name
55
- ? group.name
56
- : (ctx) => {
57
- if (group?.type === 'path') {
58
- return `${ctx.group.split('/')[1]}`
59
- }
60
- return `${camelCase(ctx.group)}Requests`
61
- }
62
-
63
- return path.resolve(
64
- root,
65
- output.path,
66
- groupName({
67
- group: group.type === 'path' ? options.group.path! : options.group.tag!,
68
- }),
69
- baseName,
70
- )
94
+ if (!adapter) {
95
+ throw new Error('Plugin cannot work without adapter being set')
71
96
  }
72
97
 
73
- return path.resolve(root, output.path, baseName)
74
- },
75
- resolveName(name, type) {
76
- const resolvedName = camelCase(name, {
77
- isFile: type === 'file',
78
- })
98
+ await walk(rootNode, {
99
+ depth: 'shallow',
100
+ async operation(operationNode) {
101
+ const writeTasks = preset.generators.map(async (generator) => {
102
+ if (generator.type === 'react' && generator.version === '2') {
103
+ const resolvedOptions = resolver.resolveOptions(operationNode, {
104
+ options: plugin.options,
105
+ exclude,
106
+ include,
107
+ override,
108
+ })
79
109
 
80
- if (type) {
81
- return transformers?.name?.(resolvedName, type) || resolvedName
82
- }
110
+ if (resolvedOptions === null) {
111
+ return
112
+ }
83
113
 
84
- return resolvedName
85
- },
86
- async install() {
87
- const root = path.resolve(this.config.root, this.config.output.path)
88
- const mode = getMode(path.resolve(root, output.path))
89
- const oas = await this.getOas()
114
+ await renderOperation(operationNode, {
115
+ options: resolvedOptions,
116
+ adapter,
117
+ config,
118
+ fabric,
119
+ Component: generator.Operation,
120
+ plugin,
121
+ driver,
122
+ resolver,
123
+ })
124
+ }
125
+ })
90
126
 
91
- const operationGenerator = new OperationGenerator(this.plugin.options, {
92
- fabric: this.fabric,
93
- oas,
94
- driver: this.driver,
95
- events: this.events,
96
- plugin: this.plugin,
97
- contentType,
98
- exclude,
99
- include,
100
- override,
101
- mode,
127
+ await Promise.all(writeTasks)
128
+ },
102
129
  })
103
130
 
104
- const files = await operationGenerator.build(...generators)
105
- await this.upsertFile(...files)
106
-
107
131
  const barrelFiles = await getBarrelFiles(this.fabric.files, {
108
132
  type: output.barrelType ?? 'named',
109
133
  root,
package/src/presets.ts ADDED
@@ -0,0 +1,23 @@
1
+ import { definePresets } from '@kubb/core'
2
+ import { cypressGenerator } from './generators/cypressGenerator.tsx'
3
+ import { resolverCypress } from './resolvers/resolverCypress.ts'
4
+ import type { ResolverCypress } from './types.ts'
5
+
6
+ /**
7
+ * Built-in preset registry for `@kubb/plugin-cypress`.
8
+ *
9
+ * - `default` — uses `resolverCypress` and `cypressGenerator`.
10
+ * - `kubbV4` — uses `resolverCypress` and `cypressGenerator`.
11
+ */
12
+ export const presets = definePresets<ResolverCypress>({
13
+ default: {
14
+ name: 'default',
15
+ resolvers: [resolverCypress],
16
+ generators: [cypressGenerator],
17
+ },
18
+ kubbV4: {
19
+ name: 'kubbV4',
20
+ resolvers: [resolverCypress],
21
+ generators: [cypressGenerator],
22
+ },
23
+ })