@kubb/plugin-cypress 5.0.0-alpha.22 → 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/dist/index.cjs +509 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +213 -4
- package/dist/index.js +485 -53
- package/dist/index.js.map +1 -1
- package/package.json +5 -29
- package/src/components/Request.tsx +85 -102
- package/src/generators/cypressGenerator.tsx +55 -43
- package/src/index.ts +8 -1
- package/src/plugin.ts +97 -73
- package/src/presets.ts +23 -0
- package/src/resolvers/resolverCypress.ts +26 -0
- package/src/types.ts +96 -38
- package/dist/components-BO5E__bN.js +0 -310
- package/dist/components-BO5E__bN.js.map +0 -1
- package/dist/components-Cm0DWd-3.cjs +0 -358
- package/dist/components-Cm0DWd-3.cjs.map +0 -1
- package/dist/components.cjs +0 -3
- package/dist/components.d.ts +0 -50
- package/dist/components.js +0 -2
- package/dist/generators-BELLqi5J.cjs +0 -75
- package/dist/generators-BELLqi5J.cjs.map +0 -1
- package/dist/generators-wVWvhp28.js +0 -71
- package/dist/generators-wVWvhp28.js.map +0 -1
- package/dist/generators.cjs +0 -3
- package/dist/generators.d.ts +0 -9
- package/dist/generators.js +0 -2
- package/dist/types-BzXXi6dv.d.ts +0 -85
- package/src/components/index.ts +0 -1
- package/src/generators/index.ts +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/plugin-cypress",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
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/
|
|
81
|
-
"@kubb/
|
|
82
|
-
"@kubb/plugin-
|
|
83
|
-
"@kubb/plugin-ts": "5.0.0-alpha.22"
|
|
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 {
|
|
3
|
-
import type {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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
|
-
|
|
15
|
-
|
|
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
|
-
|
|
25
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const params = getParams({ paramsType, paramsCasing, pathParamsType, typeSchemas })
|
|
55
|
+
return declarationPrinter.print(paramsNode) ?? ''
|
|
56
|
+
}
|
|
104
57
|
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
109
|
-
const
|
|
61
|
+
const responseType = resolver.resolveResponseName(node)
|
|
62
|
+
const returnType = dataReturnType === 'data' ? `Cypress.Chainable<${responseType}>` : `Cypress.Chainable<Cypress.Response<${responseType}>>`
|
|
110
63
|
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
120
|
-
if (
|
|
121
|
-
|
|
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
|
-
|
|
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={
|
|
117
|
+
<Function name={name} export params={paramsSignature} returnType={returnType}>
|
|
135
118
|
{dataReturnType === 'data'
|
|
136
|
-
? `return cy.request<${
|
|
119
|
+
? `return cy.request<${responseType}>({
|
|
137
120
|
${requestOptions.join(',\n ')}
|
|
138
121
|
}).then((res) => res.body)`
|
|
139
|
-
: `return cy.request<${
|
|
122
|
+
: `return cy.request<${responseType}>({
|
|
140
123
|
${requestOptions.join(',\n ')}
|
|
141
124
|
})`}
|
|
142
125
|
</Function>
|
|
@@ -1,64 +1,76 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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 =
|
|
10
|
+
export const cypressGenerator = defineGenerator<PluginCypress>({
|
|
11
11
|
name: 'cypress',
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
|
19
|
-
const { getSchemas, getName, getFile } = useOperationManager(generator)
|
|
17
|
+
const pluginTs = driver.getPlugin<PluginTs>(pluginTsName)
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
file: getFile(operation),
|
|
19
|
+
if (!pluginTs) {
|
|
20
|
+
return null
|
|
24
21
|
}
|
|
25
22
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
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={
|
|
34
|
-
path={
|
|
35
|
-
meta={
|
|
36
|
-
banner={
|
|
37
|
-
footer={
|
|
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={
|
|
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
|
-
|
|
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 {
|
|
4
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
dataReturnType,
|
|
33
|
-
group,
|
|
34
|
-
baseURL,
|
|
35
|
-
|
|
36
|
-
paramsCasing,
|
|
37
|
-
paramsType,
|
|
38
|
-
pathParamsType,
|
|
60
|
+
get resolver() {
|
|
61
|
+
return preset.resolver
|
|
39
62
|
},
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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 (
|
|
54
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
110
|
+
if (resolvedOptions === null) {
|
|
111
|
+
return
|
|
112
|
+
}
|
|
83
113
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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
|
+
})
|