@kubb/plugin-client 5.0.0-beta.56 → 5.5.2
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/README.md +8 -61
- package/dist/index.cjs +754 -1745
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +170 -349
- package/dist/index.js +733 -1733
- package/dist/index.js.map +1 -1
- package/package.json +10 -63
- package/src/generators/clientGenerator.tsx +6 -132
- package/src/index.ts +1 -9
- package/src/plugin.ts +32 -122
- package/src/types.ts +27 -249
- package/dist/chunk-Bx3C2hgW.cjs +0 -38
- package/dist/clients/axios.cjs +0 -68
- package/dist/clients/axios.cjs.map +0 -1
- package/dist/clients/axios.d.ts +0 -49
- package/dist/clients/axios.js +0 -58
- package/dist/clients/axios.js.map +0 -1
- package/dist/clients/fetch.cjs +0 -128
- package/dist/clients/fetch.cjs.map +0 -1
- package/dist/clients/fetch.d.ts +0 -50
- package/dist/clients/fetch.js +0 -120
- package/dist/clients/fetch.js.map +0 -1
- package/dist/templates/clients/axios.source.cjs +0 -7
- package/dist/templates/clients/axios.source.cjs.map +0 -1
- package/dist/templates/clients/axios.source.d.ts +0 -7
- package/dist/templates/clients/axios.source.js +0 -6
- package/dist/templates/clients/axios.source.js.map +0 -1
- package/dist/templates/clients/fetch.source.cjs +0 -7
- package/dist/templates/clients/fetch.source.cjs.map +0 -1
- package/dist/templates/clients/fetch.source.d.ts +0 -7
- package/dist/templates/clients/fetch.source.js +0 -6
- package/dist/templates/clients/fetch.source.js.map +0 -1
- package/dist/templates/config.source.cjs +0 -7
- package/dist/templates/config.source.cjs.map +0 -1
- package/dist/templates/config.source.d.ts +0 -7
- package/dist/templates/config.source.js +0 -6
- package/dist/templates/config.source.js.map +0 -1
- package/src/clients/axios.ts +0 -113
- package/src/clients/fetch.ts +0 -201
- package/src/components/ClassClient.tsx +0 -161
- package/src/components/Client.tsx +0 -281
- package/src/components/StaticClassClient.tsx +0 -153
- package/src/components/Url.tsx +0 -90
- package/src/components/WrapperClient.tsx +0 -33
- package/src/functionParams.ts +0 -118
- package/src/generators/classClientGenerator.tsx +0 -261
- package/src/generators/groupedClientGenerator.tsx +0 -82
- package/src/generators/operationsGenerator.ts +0 -47
- package/src/generators/staticClassClientGenerator.tsx +0 -240
- package/src/resolvers/resolverClient.ts +0 -46
- package/src/templates/clients/axios.source.ts +0 -4
- package/src/templates/clients/fetch.source.ts +0 -4
- package/src/templates/config.source.ts +0 -4
- package/src/utils.ts +0 -259
- /package/dist/{chunk-C0LytTxp.js → rolldown-runtime-C0LytTxp.js} +0 -0
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { buildOperationComments, getContentTypeInfo, getOperationParameters } from '@internals/shared'
|
|
2
|
-
import { Url } from '@internals/utils'
|
|
3
|
-
import { buildJSDoc, stringify } from '@kubb/ast/utils'
|
|
4
|
-
import { ast } from '@kubb/core'
|
|
5
|
-
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
6
|
-
import { functionPrinter } from '@kubb/plugin-ts'
|
|
7
|
-
import type { ResolverZod } from '@kubb/plugin-zod'
|
|
8
|
-
import { File } from '@kubb/renderer-jsx'
|
|
9
|
-
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
10
|
-
import type { PluginClient } from '../types.ts'
|
|
11
|
-
import {
|
|
12
|
-
buildClassClientParams,
|
|
13
|
-
buildFormDataLine,
|
|
14
|
-
buildGenerics,
|
|
15
|
-
buildHeaders,
|
|
16
|
-
buildQueryParamsLine,
|
|
17
|
-
buildRequestDataLine,
|
|
18
|
-
buildReturnStatement,
|
|
19
|
-
resolveQueryParamsParser,
|
|
20
|
-
} from '../utils.ts'
|
|
21
|
-
import { buildClientParamsNode } from './Client.tsx'
|
|
22
|
-
|
|
23
|
-
type OperationData = {
|
|
24
|
-
node: ast.OperationNode
|
|
25
|
-
name: string
|
|
26
|
-
tsResolver: ResolverTs
|
|
27
|
-
zodResolver?: ResolverZod | null
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
type Props = {
|
|
31
|
-
name: string
|
|
32
|
-
isExportable?: boolean
|
|
33
|
-
isIndexable?: boolean
|
|
34
|
-
operations: Array<OperationData>
|
|
35
|
-
baseURL: string | null | undefined
|
|
36
|
-
dataReturnType: PluginClient['resolvedOptions']['dataReturnType']
|
|
37
|
-
paramsCasing: PluginClient['resolvedOptions']['paramsCasing']
|
|
38
|
-
paramsType: PluginClient['resolvedOptions']['pathParamsType']
|
|
39
|
-
pathParamsType: PluginClient['resolvedOptions']['pathParamsType']
|
|
40
|
-
parser: PluginClient['resolvedOptions']['parser'] | undefined
|
|
41
|
-
children?: KubbReactNode
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
type GenerateMethodProps = {
|
|
45
|
-
node: ast.OperationNode
|
|
46
|
-
name: string
|
|
47
|
-
tsResolver: ResolverTs
|
|
48
|
-
zodResolver?: ResolverZod | null
|
|
49
|
-
baseURL: string | null | undefined
|
|
50
|
-
dataReturnType: PluginClient['resolvedOptions']['dataReturnType']
|
|
51
|
-
parser: PluginClient['resolvedOptions']['parser'] | undefined
|
|
52
|
-
paramsType: PluginClient['resolvedOptions']['paramsType']
|
|
53
|
-
paramsCasing: PluginClient['resolvedOptions']['paramsCasing']
|
|
54
|
-
pathParamsType: PluginClient['resolvedOptions']['pathParamsType']
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const declarationPrinter = functionPrinter({ mode: 'declaration' })
|
|
58
|
-
|
|
59
|
-
function generateMethod({
|
|
60
|
-
node,
|
|
61
|
-
name,
|
|
62
|
-
tsResolver,
|
|
63
|
-
zodResolver,
|
|
64
|
-
baseURL,
|
|
65
|
-
dataReturnType,
|
|
66
|
-
parser,
|
|
67
|
-
paramsType,
|
|
68
|
-
paramsCasing,
|
|
69
|
-
pathParamsType,
|
|
70
|
-
}: GenerateMethodProps): string {
|
|
71
|
-
if (!ast.isHttpOperationNode(node)) return ''
|
|
72
|
-
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node)
|
|
73
|
-
const isFormData = !isMultipleContentTypes && contentType === 'multipart/form-data'
|
|
74
|
-
const { header: headerParams } = getOperationParameters(node)
|
|
75
|
-
const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]!) : null
|
|
76
|
-
const headers = isMultipleContentTypes ? (headerParamsName ? ['...headers'] : []) : buildHeaders(contentType, !!headerParamsName)
|
|
77
|
-
const generics = buildGenerics(node, tsResolver, { dataReturnType, zodResolver, parser })
|
|
78
|
-
const paramsNode = buildClientParamsNode({ paramsType, paramsCasing, pathParamsType, node, tsResolver, isConfigurable: true })
|
|
79
|
-
const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
|
|
80
|
-
const { query: queryParams } = getOperationParameters(node)
|
|
81
|
-
const zodQueryParamsName =
|
|
82
|
-
zodResolver && resolveQueryParamsParser(parser) === 'zod' && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]!) : null
|
|
83
|
-
const clientParams = buildClassClientParams({
|
|
84
|
-
node,
|
|
85
|
-
url: Url.toTemplateString(node.path, { casing: paramsCasing }),
|
|
86
|
-
baseURL,
|
|
87
|
-
tsResolver,
|
|
88
|
-
isFormData,
|
|
89
|
-
isMultipleContentTypes,
|
|
90
|
-
hasFormData,
|
|
91
|
-
headers,
|
|
92
|
-
zodQueryParamsName,
|
|
93
|
-
})
|
|
94
|
-
const jsdoc = buildJSDoc(buildOperationComments(node, { link: 'urlPath', linkPosition: 'beforeDeprecated', splitLines: true }))
|
|
95
|
-
|
|
96
|
-
const requestDataLine = buildRequestDataLine({ parser, node, zodResolver })
|
|
97
|
-
const queryParamsLine = buildQueryParamsLine({ parser, node, zodResolver })
|
|
98
|
-
const formDataLine = buildFormDataLine(isFormData || (isMultipleContentTypes && hasFormData), !!node.requestBody?.content?.[0]?.schema)
|
|
99
|
-
const returnStatement = buildReturnStatement({ dataReturnType, parser, node, zodResolver, tsResolver })
|
|
100
|
-
|
|
101
|
-
const methodBody = [
|
|
102
|
-
`const { client: request = client, ${isMultipleContentTypes ? `contentType = ${stringify(contentType)}, ` : ''}...requestConfig } = mergeConfig(this.#config, config)`,
|
|
103
|
-
'',
|
|
104
|
-
requestDataLine,
|
|
105
|
-
queryParamsLine,
|
|
106
|
-
formDataLine,
|
|
107
|
-
`const res = await request<${generics.join(', ')}>(${clientParams.toCall()})`,
|
|
108
|
-
returnStatement,
|
|
109
|
-
]
|
|
110
|
-
.filter(Boolean)
|
|
111
|
-
.map((line) => ` ${line}`)
|
|
112
|
-
.join('\n')
|
|
113
|
-
|
|
114
|
-
return `${jsdoc} static async ${name}(${paramsSignature}) {\n${methodBody}\n }`
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export function StaticClassClient({
|
|
118
|
-
name,
|
|
119
|
-
isExportable = true,
|
|
120
|
-
isIndexable = true,
|
|
121
|
-
operations,
|
|
122
|
-
baseURL,
|
|
123
|
-
dataReturnType,
|
|
124
|
-
parser,
|
|
125
|
-
paramsType,
|
|
126
|
-
paramsCasing,
|
|
127
|
-
pathParamsType,
|
|
128
|
-
children,
|
|
129
|
-
}: Props): KubbReactNode {
|
|
130
|
-
const methods = operations.map(({ node, name: methodName, tsResolver, zodResolver }) =>
|
|
131
|
-
generateMethod({
|
|
132
|
-
node,
|
|
133
|
-
name: methodName,
|
|
134
|
-
tsResolver,
|
|
135
|
-
zodResolver,
|
|
136
|
-
baseURL,
|
|
137
|
-
dataReturnType,
|
|
138
|
-
parser,
|
|
139
|
-
paramsType,
|
|
140
|
-
paramsCasing,
|
|
141
|
-
pathParamsType,
|
|
142
|
-
}),
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
const classCode = `export class ${name} {\n static #config: Partial<RequestConfig> & { client?: Client } = {}\n\n${methods.join('\n\n')}\n}`
|
|
146
|
-
|
|
147
|
-
return (
|
|
148
|
-
<File.Source name={name} isExportable={isExportable} isIndexable={isIndexable}>
|
|
149
|
-
{classCode}
|
|
150
|
-
{children}
|
|
151
|
-
</File.Source>
|
|
152
|
-
)
|
|
153
|
-
}
|
package/src/components/Url.tsx
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { buildParamsMapping, getOperationParameters } from '@internals/shared'
|
|
2
|
-
import { isValidVarName, Url as UrlHelper } from '@internals/utils'
|
|
3
|
-
import { ast } from '@kubb/core'
|
|
4
|
-
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
5
|
-
import { functionPrinter } from '@kubb/plugin-ts'
|
|
6
|
-
import { Const, File, Function } from '@kubb/renderer-jsx'
|
|
7
|
-
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
8
|
-
import type { PluginClient } from '../types.ts'
|
|
9
|
-
|
|
10
|
-
type Props = {
|
|
11
|
-
name: string
|
|
12
|
-
isExportable?: boolean
|
|
13
|
-
isIndexable?: boolean
|
|
14
|
-
|
|
15
|
-
baseURL: string | null | undefined
|
|
16
|
-
paramsCasing: PluginClient['resolvedOptions']['paramsCasing']
|
|
17
|
-
paramsType: PluginClient['resolvedOptions']['pathParamsType']
|
|
18
|
-
pathParamsType: PluginClient['resolvedOptions']['pathParamsType']
|
|
19
|
-
node: ast.OperationNode
|
|
20
|
-
tsResolver: ResolverTs
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
type GetParamsProps = {
|
|
24
|
-
paramsCasing: PluginClient['resolvedOptions']['paramsCasing']
|
|
25
|
-
paramsType: PluginClient['resolvedOptions']['paramsType']
|
|
26
|
-
pathParamsType: PluginClient['resolvedOptions']['pathParamsType']
|
|
27
|
-
node: ast.OperationNode
|
|
28
|
-
tsResolver: ResolverTs
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const declarationPrinter = functionPrinter({ mode: 'declaration' })
|
|
32
|
-
|
|
33
|
-
export function buildUrlParamsNode({ paramsType, paramsCasing, pathParamsType, node, tsResolver }: GetParamsProps): ast.FunctionParametersNode {
|
|
34
|
-
// Build a URL-only node with only path params (no body, query, header)
|
|
35
|
-
const urlNode: ast.OperationNode = {
|
|
36
|
-
...node,
|
|
37
|
-
parameters: node.parameters.filter((p) => p.in === 'path'),
|
|
38
|
-
requestBody: undefined,
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return ast.createOperationParams(urlNode, {
|
|
42
|
-
paramsType: paramsType === 'object' ? 'object' : 'inline',
|
|
43
|
-
pathParamsType: paramsType === 'object' ? 'object' : pathParamsType === 'object' ? 'object' : 'inline',
|
|
44
|
-
paramsCasing,
|
|
45
|
-
resolver: tsResolver,
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function Url({
|
|
50
|
-
name,
|
|
51
|
-
isExportable = true,
|
|
52
|
-
isIndexable = true,
|
|
53
|
-
baseURL,
|
|
54
|
-
paramsType,
|
|
55
|
-
paramsCasing,
|
|
56
|
-
pathParamsType,
|
|
57
|
-
node,
|
|
58
|
-
tsResolver,
|
|
59
|
-
}: Props): KubbReactNode {
|
|
60
|
-
if (!ast.isHttpOperationNode(node)) return null
|
|
61
|
-
|
|
62
|
-
const paramsNode = buildUrlParamsNode({
|
|
63
|
-
paramsType,
|
|
64
|
-
paramsCasing,
|
|
65
|
-
pathParamsType,
|
|
66
|
-
node,
|
|
67
|
-
tsResolver,
|
|
68
|
-
})
|
|
69
|
-
const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
|
|
70
|
-
|
|
71
|
-
const { path: originalPathParams } = getOperationParameters(node)
|
|
72
|
-
const { path: casedPathParams } = getOperationParameters(node, { paramsCasing })
|
|
73
|
-
const pathParamsMapping = paramsCasing ? buildParamsMapping(originalPathParams, casedPathParams) : null
|
|
74
|
-
|
|
75
|
-
return (
|
|
76
|
-
<File.Source name={name} isExportable={isExportable} isIndexable={isIndexable}>
|
|
77
|
-
<Function name={name} export={isExportable} params={paramsSignature}>
|
|
78
|
-
{pathParamsMapping &&
|
|
79
|
-
Object.entries(pathParamsMapping)
|
|
80
|
-
.filter(([originalName, camelCaseName]) => isValidVarName(originalName) && originalName !== camelCaseName)
|
|
81
|
-
.map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`)
|
|
82
|
-
.join('\n')}
|
|
83
|
-
{pathParamsMapping && Object.keys(pathParamsMapping).length > 0 && <br />}
|
|
84
|
-
<Const name={'res'}>{`{ method: '${node.method.toUpperCase()}', url: ${UrlHelper.toTemplateString(node.path, { prefix: baseURL })} as const }`}</Const>
|
|
85
|
-
<br />
|
|
86
|
-
return res
|
|
87
|
-
</Function>
|
|
88
|
-
</File.Source>
|
|
89
|
-
)
|
|
90
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { File } from '@kubb/renderer-jsx'
|
|
2
|
-
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
3
|
-
|
|
4
|
-
type ClientController = {
|
|
5
|
-
className: string
|
|
6
|
-
propertyName: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
type Props = {
|
|
10
|
-
name: string
|
|
11
|
-
controllers: Array<ClientController>
|
|
12
|
-
isExportable?: boolean
|
|
13
|
-
isIndexable?: boolean
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function WrapperClient({ name, controllers, isExportable = true, isIndexable = true }: Props): KubbReactNode {
|
|
17
|
-
const properties = controllers.map(({ className, propertyName }) => ` readonly ${propertyName}: ${className}`).join('\n')
|
|
18
|
-
const assignments = controllers.map(({ className, propertyName }) => ` this.${propertyName} = new ${className}(config)`).join('\n')
|
|
19
|
-
|
|
20
|
-
const classCode = `export class ${name} {
|
|
21
|
-
${properties}
|
|
22
|
-
|
|
23
|
-
constructor(config: Partial<RequestConfig> & { client?: Client } = {}) {
|
|
24
|
-
${assignments}
|
|
25
|
-
}
|
|
26
|
-
}`
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<File.Source name={name} isExportable={isExportable} isIndexable={isIndexable}>
|
|
30
|
-
{classCode}
|
|
31
|
-
</File.Source>
|
|
32
|
-
)
|
|
33
|
-
}
|
package/src/functionParams.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { ast } from '@kubb/core'
|
|
2
|
-
import { functionPrinter } from '@kubb/plugin-ts'
|
|
3
|
-
|
|
4
|
-
type ParamLeaf = {
|
|
5
|
-
type?: string
|
|
6
|
-
optional?: boolean
|
|
7
|
-
default?: string
|
|
8
|
-
value?: string
|
|
9
|
-
mode?: 'inlineSpread'
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
type ParamGroup = {
|
|
13
|
-
mode: 'object' | 'inlineSpread'
|
|
14
|
-
children: Record<string, ParamLeaf | null | undefined>
|
|
15
|
-
default?: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
type ParamSpec = ParamLeaf | ParamGroup
|
|
19
|
-
|
|
20
|
-
const declarationPrinter = functionPrinter({ mode: 'declaration' })
|
|
21
|
-
const callPrinter = functionPrinter({ mode: 'call' })
|
|
22
|
-
|
|
23
|
-
function isGroup(spec: ParamSpec): spec is ParamGroup {
|
|
24
|
-
return 'children' in spec
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function createType(type?: string) {
|
|
28
|
-
return type ? ast.createParamsType({ variant: 'reference', name: type }) : null
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function createDeclarationLeaf(name: string, spec: ParamLeaf): ast.FunctionParameterNode {
|
|
32
|
-
if (spec.default !== undefined) {
|
|
33
|
-
return ast.createFunctionParameter({
|
|
34
|
-
name,
|
|
35
|
-
type: createType(spec.type) ?? undefined,
|
|
36
|
-
default: spec.default,
|
|
37
|
-
rest: spec.mode === 'inlineSpread',
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return ast.createFunctionParameter({
|
|
42
|
-
name,
|
|
43
|
-
type: createType(spec.type) ?? undefined,
|
|
44
|
-
optional: !!spec.optional,
|
|
45
|
-
rest: spec.mode === 'inlineSpread',
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function createDeclarationParam(name: string, spec: ParamSpec): ast.FunctionParameterNode | ast.ParameterGroupNode {
|
|
50
|
-
if (isGroup(spec)) {
|
|
51
|
-
return ast.createParameterGroup({
|
|
52
|
-
inline: spec.mode === 'inlineSpread',
|
|
53
|
-
default: spec.default,
|
|
54
|
-
properties: Object.entries(spec.children)
|
|
55
|
-
.filter(([, child]) => child != null)
|
|
56
|
-
.map(([childName, child]) => createDeclarationLeaf(childName, child!)),
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return createDeclarationLeaf(name, spec)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function createCallParam(name: string, spec: ParamSpec): ast.FunctionParameterNode | ast.ParameterGroupNode {
|
|
64
|
-
if (isGroup(spec)) {
|
|
65
|
-
return ast.createParameterGroup({
|
|
66
|
-
inline: spec.mode === 'inlineSpread',
|
|
67
|
-
properties: Object.entries(spec.children)
|
|
68
|
-
.filter(([, child]) => child != null)
|
|
69
|
-
.map(([childName, child]) =>
|
|
70
|
-
ast.createFunctionParameter({
|
|
71
|
-
name:
|
|
72
|
-
child?.mode === 'inlineSpread'
|
|
73
|
-
? spec.mode === 'inlineSpread'
|
|
74
|
-
? (child.value ?? childName)
|
|
75
|
-
: `...${child.value ?? childName}`
|
|
76
|
-
: child?.value
|
|
77
|
-
? `${childName}: ${child.value}`
|
|
78
|
-
: childName,
|
|
79
|
-
rest: spec.mode === 'inlineSpread' && child?.mode === 'inlineSpread',
|
|
80
|
-
}),
|
|
81
|
-
),
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return ast.createFunctionParameter({
|
|
86
|
-
name: spec.value ?? name,
|
|
87
|
-
rest: spec.mode === 'inlineSpread',
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Creates function parameter builders for generating function signatures and calls.
|
|
93
|
-
* Returns utilities to output constructor signatures (`toConstructor()`) or call expressions (`toCall()`).
|
|
94
|
-
*/
|
|
95
|
-
export function createFunctionParams(params: Record<string, ParamSpec | null | undefined>) {
|
|
96
|
-
const entries = Object.entries(params).filter(([, spec]) => spec != null) as Array<[string, ParamSpec]>
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
toConstructor() {
|
|
100
|
-
return (
|
|
101
|
-
declarationPrinter.print(
|
|
102
|
-
ast.createFunctionParameters({
|
|
103
|
-
params: entries.map(([name, spec]) => createDeclarationParam(name, spec)),
|
|
104
|
-
}),
|
|
105
|
-
) ?? ''
|
|
106
|
-
)
|
|
107
|
-
},
|
|
108
|
-
toCall() {
|
|
109
|
-
return (
|
|
110
|
-
callPrinter.print(
|
|
111
|
-
ast.createFunctionParameters({
|
|
112
|
-
params: entries.map(([name, spec]) => createCallParam(name, spec)),
|
|
113
|
-
}),
|
|
114
|
-
) ?? ''
|
|
115
|
-
)
|
|
116
|
-
},
|
|
117
|
-
}
|
|
118
|
-
}
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
import { getOperationParameters, operationFileEntry, resolveOperationTypeNames } from '@internals/shared'
|
|
3
|
-
import { camelCase } from '@internals/utils'
|
|
4
|
-
import { ast, defineGenerator } from '@kubb/core'
|
|
5
|
-
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
6
|
-
import { pluginTsName } from '@kubb/plugin-ts'
|
|
7
|
-
import type { ResolverZod } from '@kubb/plugin-zod'
|
|
8
|
-
import { pluginZodName } from '@kubb/plugin-zod'
|
|
9
|
-
import { File, jsxRenderer } from '@kubb/renderer-jsx'
|
|
10
|
-
import { ClassClient } from '../components/ClassClient'
|
|
11
|
-
import { WrapperClient } from '../components/WrapperClient'
|
|
12
|
-
import type { PluginClient } from '../types'
|
|
13
|
-
import { isParserEnabled, resolveQueryParamsParser, resolveRequestParser, resolveResponseParser } from '../utils.ts'
|
|
14
|
-
|
|
15
|
-
type OperationData = {
|
|
16
|
-
node: ast.OperationNode
|
|
17
|
-
name: string
|
|
18
|
-
tsResolver: ResolverTs
|
|
19
|
-
zodResolver: ResolverZod | null
|
|
20
|
-
typeFile: ast.FileNode
|
|
21
|
-
zodFile: ast.FileNode | null
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
type Controller = {
|
|
25
|
-
name: string
|
|
26
|
-
propertyName: string
|
|
27
|
-
file: ast.FileNode
|
|
28
|
-
operations: Array<OperationData>
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function resolveTypeImportNames(node: ast.OperationNode, tsResolver: ResolverTs): Array<string> {
|
|
32
|
-
return resolveOperationTypeNames(node, tsResolver, { order: 'body-response-first' })
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function resolveZodImportNames(node: ast.OperationNode, zodResolver: ResolverZod, parser: PluginClient['resolvedOptions']['parser']): Array<string> {
|
|
36
|
-
const { query: queryParams } = getOperationParameters(node)
|
|
37
|
-
const names: Array<string | null | undefined> = [
|
|
38
|
-
resolveResponseParser(parser) === 'zod' ? zodResolver.resolveResponseName?.(node) : null,
|
|
39
|
-
resolveRequestParser(parser) === 'zod' && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
|
|
40
|
-
resolveQueryParamsParser(parser) === 'zod' && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]!) : null,
|
|
41
|
-
]
|
|
42
|
-
return names.filter((n): n is string => Boolean(n))
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Built-in `operations` generator for `@kubb/plugin-client` when
|
|
47
|
-
* `clientType: 'class'`. Emits one class per tag, with one instance method
|
|
48
|
-
* per operation and a shared constructor for request configuration.
|
|
49
|
-
*/
|
|
50
|
-
export const classClientGenerator = defineGenerator<PluginClient>({
|
|
51
|
-
name: 'classClient',
|
|
52
|
-
renderer: jsxRenderer,
|
|
53
|
-
operations(nodes, ctx) {
|
|
54
|
-
const { config, driver, resolver, root } = ctx
|
|
55
|
-
const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, sdk } = ctx.options
|
|
56
|
-
const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL
|
|
57
|
-
|
|
58
|
-
const pluginTs = driver.getPlugin(pluginTsName)
|
|
59
|
-
if (!pluginTs) return null
|
|
60
|
-
|
|
61
|
-
const tsResolver = driver.getResolver(pluginTsName)
|
|
62
|
-
const tsPluginOptions = pluginTs.options
|
|
63
|
-
const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : null
|
|
64
|
-
const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
|
|
65
|
-
|
|
66
|
-
function buildOperationData(node: ast.OperationNode): OperationData {
|
|
67
|
-
const typeFile = tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
68
|
-
root,
|
|
69
|
-
output: tsPluginOptions?.output ?? output,
|
|
70
|
-
group: tsPluginOptions?.group,
|
|
71
|
-
})
|
|
72
|
-
const zodFile =
|
|
73
|
-
zodResolver && pluginZod?.options
|
|
74
|
-
? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
75
|
-
root,
|
|
76
|
-
output: pluginZod.options?.output ?? output,
|
|
77
|
-
group: pluginZod.options?.group ?? undefined,
|
|
78
|
-
})
|
|
79
|
-
: null
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
node: node,
|
|
83
|
-
name: resolver.resolveName(node.operationId),
|
|
84
|
-
tsResolver,
|
|
85
|
-
zodResolver,
|
|
86
|
-
typeFile,
|
|
87
|
-
zodFile,
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const controllers = nodes.reduce((acc, operationNode) => {
|
|
92
|
-
if (!ast.isHttpOperationNode(operationNode)) return acc
|
|
93
|
-
const tag = operationNode.tags[0]
|
|
94
|
-
const groupName = tag ? (group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag)) : resolver.resolveClassName('Client')
|
|
95
|
-
|
|
96
|
-
if (!tag && !group) {
|
|
97
|
-
const name = resolver.resolveClassName('ApiClient')
|
|
98
|
-
const file = resolver.resolveFile({ name, extname: '.ts' }, { root, output, group: group ?? undefined })
|
|
99
|
-
const operationData = buildOperationData(operationNode)
|
|
100
|
-
const previous = acc.find((item) => item.file.path === file.path)
|
|
101
|
-
|
|
102
|
-
if (previous) {
|
|
103
|
-
previous.operations.push(operationData)
|
|
104
|
-
} else {
|
|
105
|
-
acc.push({ name, propertyName: resolver.resolveClientPropertyName(name), file, operations: [operationData] })
|
|
106
|
-
}
|
|
107
|
-
return acc
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (tag) {
|
|
111
|
-
const name = groupName
|
|
112
|
-
const file = resolver.resolveFile({ name, extname: '.ts', tag }, { root, output, group: group ?? undefined })
|
|
113
|
-
const operationData = buildOperationData(operationNode)
|
|
114
|
-
const previous = acc.find((item) => item.file.path === file.path)
|
|
115
|
-
|
|
116
|
-
if (previous) {
|
|
117
|
-
previous.operations.push(operationData)
|
|
118
|
-
} else {
|
|
119
|
-
acc.push({ name, propertyName: resolver.resolveClientPropertyName(name), file, operations: [operationData] })
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return acc
|
|
124
|
-
}, [] as Array<Controller>)
|
|
125
|
-
|
|
126
|
-
function collectTypeImports(ops: Array<OperationData>) {
|
|
127
|
-
const typeImportsByFile = new Map<string, Set<string>>()
|
|
128
|
-
const typeFilesByPath = new Map<string, ast.FileNode>()
|
|
129
|
-
|
|
130
|
-
ops.forEach((op) => {
|
|
131
|
-
const names = resolveTypeImportNames(op.node, tsResolver)
|
|
132
|
-
if (!typeImportsByFile.has(op.typeFile.path)) {
|
|
133
|
-
typeImportsByFile.set(op.typeFile.path, new Set())
|
|
134
|
-
}
|
|
135
|
-
const imports = typeImportsByFile.get(op.typeFile.path)!
|
|
136
|
-
names.forEach((n) => {
|
|
137
|
-
imports.add(n)
|
|
138
|
-
})
|
|
139
|
-
typeFilesByPath.set(op.typeFile.path, op.typeFile)
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
return { typeImportsByFile, typeFilesByPath }
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function collectZodImports(ops: Array<OperationData>) {
|
|
146
|
-
const zodImportsByFile = new Map<string, Set<string>>()
|
|
147
|
-
const zodFilesByPath = new Map<string, ast.FileNode>()
|
|
148
|
-
|
|
149
|
-
ops.forEach((op) => {
|
|
150
|
-
if (!op.zodFile || !zodResolver) return
|
|
151
|
-
const names = resolveZodImportNames(op.node, zodResolver, parser)
|
|
152
|
-
if (!zodImportsByFile.has(op.zodFile.path)) {
|
|
153
|
-
zodImportsByFile.set(op.zodFile.path, new Set())
|
|
154
|
-
}
|
|
155
|
-
const imports = zodImportsByFile.get(op.zodFile.path)!
|
|
156
|
-
names.forEach((n) => {
|
|
157
|
-
imports.add(n)
|
|
158
|
-
})
|
|
159
|
-
zodFilesByPath.set(op.zodFile.path, op.zodFile)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
return { zodImportsByFile, zodFilesByPath }
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const files = controllers.map(({ name, file, operations: ops }) => {
|
|
166
|
-
const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops)
|
|
167
|
-
const { zodImportsByFile, zodFilesByPath } = isParserEnabled(parser)
|
|
168
|
-
? collectZodImports(ops)
|
|
169
|
-
: { zodImportsByFile: new Map<string, Set<string>>(), zodFilesByPath: new Map<string, ast.FileNode>() }
|
|
170
|
-
const hasFormData = ops.some((op) => op.node.requestBody?.content?.some((e) => e.contentType === 'multipart/form-data') ?? false)
|
|
171
|
-
|
|
172
|
-
return (
|
|
173
|
-
<File
|
|
174
|
-
key={file.path}
|
|
175
|
-
baseName={file.baseName}
|
|
176
|
-
path={file.path}
|
|
177
|
-
meta={file.meta}
|
|
178
|
-
banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } })}
|
|
179
|
-
footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } })}
|
|
180
|
-
>
|
|
181
|
-
{importPath ? (
|
|
182
|
-
<>
|
|
183
|
-
<File.Import name={'client'} path={importPath} />
|
|
184
|
-
<File.Import name={['mergeConfig']} path={importPath} />
|
|
185
|
-
<File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={importPath} isTypeOnly />
|
|
186
|
-
</>
|
|
187
|
-
) : (
|
|
188
|
-
<>
|
|
189
|
-
<File.Import name={['client']} root={file.path} path={path.resolve(root, '.kubb/client.ts')} />
|
|
190
|
-
<File.Import name={['mergeConfig']} root={file.path} path={path.resolve(root, '.kubb/client.ts')} />
|
|
191
|
-
<File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} root={file.path} path={path.resolve(root, '.kubb/client.ts')} isTypeOnly />
|
|
192
|
-
</>
|
|
193
|
-
)}
|
|
194
|
-
|
|
195
|
-
{hasFormData && <File.Import name={['buildFormData']} root={file.path} path={path.resolve(root, '.kubb/config.ts')} />}
|
|
196
|
-
|
|
197
|
-
{parser === 'zod' && zodResolver && ops.some((op) => op.node.requestBody?.content?.[0]?.schema != null) && (
|
|
198
|
-
<File.Import name={['z']} path="zod" isTypeOnly />
|
|
199
|
-
)}
|
|
200
|
-
|
|
201
|
-
{Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
202
|
-
const typeFile = typeFilesByPath.get(filePath)
|
|
203
|
-
if (!typeFile) return null
|
|
204
|
-
const importNames = Array.from(importSet).filter(Boolean)
|
|
205
|
-
if (importNames.length === 0) return null
|
|
206
|
-
return <File.Import key={filePath} name={importNames} root={file.path} path={typeFile.path} isTypeOnly />
|
|
207
|
-
})}
|
|
208
|
-
|
|
209
|
-
{isParserEnabled(parser) &&
|
|
210
|
-
Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
211
|
-
const zodFile = zodFilesByPath.get(filePath)
|
|
212
|
-
if (!zodFile) return null
|
|
213
|
-
const importNames = Array.from(importSet).filter(Boolean)
|
|
214
|
-
if (importNames.length === 0) return null
|
|
215
|
-
return <File.Import key={filePath} name={importNames} root={file.path} path={zodFile.path} />
|
|
216
|
-
})}
|
|
217
|
-
|
|
218
|
-
<ClassClient
|
|
219
|
-
name={name}
|
|
220
|
-
operations={ops}
|
|
221
|
-
baseURL={baseURL}
|
|
222
|
-
dataReturnType={dataReturnType}
|
|
223
|
-
pathParamsType={pathParamsType}
|
|
224
|
-
paramsCasing={paramsCasing}
|
|
225
|
-
paramsType={paramsType}
|
|
226
|
-
parser={parser}
|
|
227
|
-
/>
|
|
228
|
-
</File>
|
|
229
|
-
)
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
if (sdk) {
|
|
233
|
-
const sdkFile = resolver.resolveFile({ name: sdk.className, extname: '.ts' }, { root, output, group: group ?? undefined })
|
|
234
|
-
|
|
235
|
-
files.push(
|
|
236
|
-
<File
|
|
237
|
-
key={sdkFile.path}
|
|
238
|
-
baseName={sdkFile.baseName}
|
|
239
|
-
path={sdkFile.path}
|
|
240
|
-
meta={sdkFile.meta}
|
|
241
|
-
banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: sdkFile.path, baseName: sdkFile.baseName } })}
|
|
242
|
-
footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: sdkFile.path, baseName: sdkFile.baseName } })}
|
|
243
|
-
>
|
|
244
|
-
{importPath ? (
|
|
245
|
-
<File.Import name={['Client', 'RequestConfig']} path={importPath} isTypeOnly />
|
|
246
|
-
) : (
|
|
247
|
-
<File.Import name={['Client', 'RequestConfig']} root={sdkFile.path} path={path.resolve(root, '.kubb/client.ts')} isTypeOnly />
|
|
248
|
-
)}
|
|
249
|
-
|
|
250
|
-
{controllers.map(({ name, file }) => (
|
|
251
|
-
<File.Import key={name} name={[name]} root={sdkFile.path} path={file.path} />
|
|
252
|
-
))}
|
|
253
|
-
|
|
254
|
-
<WrapperClient name={sdk.className} controllers={controllers.map(({ name, propertyName }) => ({ className: name, propertyName }))} />
|
|
255
|
-
</File>,
|
|
256
|
-
)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return <>{files}</>
|
|
260
|
-
},
|
|
261
|
-
})
|