@kubb/plugin-client 5.0.0-beta.56 → 5.0.0-beta.64

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.
@@ -1,281 +0,0 @@
1
- import {
2
- buildOperationComments,
3
- buildParamsMapping,
4
- buildRequestConfigType,
5
- getContentTypeInfo,
6
- getOperationParameters,
7
- getResponseType,
8
- resolveSuccessNames,
9
- } from '@internals/shared'
10
- import { isValidVarName, Url } from '@internals/utils'
11
- import { stringify } from '@kubb/ast/utils'
12
- import { ast } from '@kubb/core'
13
- import type { ResolverTs } from '@kubb/plugin-ts'
14
- import { functionPrinter } from '@kubb/plugin-ts'
15
- import type { ResolverZod } from '@kubb/plugin-zod'
16
- import { File, Function } from '@kubb/renderer-jsx'
17
- import type { KubbReactNode } from '@kubb/renderer-jsx/types'
18
- import { createFunctionParams } from '../functionParams.ts'
19
- import type { PluginClient } from '../types.ts'
20
- import { buildStatusUnionType, resolveQueryParamsParser, resolveRequestParser, resolveResponseParser } from '../utils.ts'
21
- import { buildUrlParamsNode } from './Url.tsx'
22
-
23
- type Props = {
24
- name: string
25
- urlName?: string
26
- isExportable?: boolean
27
- isIndexable?: boolean
28
- isConfigurable?: boolean
29
- returnType?: string
30
-
31
- baseURL: string | null | undefined
32
- dataReturnType: PluginClient['resolvedOptions']['dataReturnType']
33
- paramsCasing: PluginClient['resolvedOptions']['paramsCasing']
34
- paramsType: PluginClient['resolvedOptions']['pathParamsType']
35
- pathParamsType: PluginClient['resolvedOptions']['pathParamsType']
36
- parser: PluginClient['resolvedOptions']['parser'] | undefined
37
- node: ast.OperationNode
38
- tsResolver: ResolverTs
39
- zodResolver?: ResolverZod | null
40
- children?: KubbReactNode
41
- }
42
-
43
- type GetParamsProps = {
44
- paramsCasing: PluginClient['resolvedOptions']['paramsCasing']
45
- paramsType: PluginClient['resolvedOptions']['paramsType']
46
- pathParamsType: PluginClient['resolvedOptions']['pathParamsType']
47
- node: ast.OperationNode
48
- tsResolver: ResolverTs
49
- isConfigurable: boolean
50
- }
51
-
52
- const declarationPrinter = functionPrinter({ mode: 'declaration' })
53
-
54
- export function buildClientParamsNode({
55
- paramsType,
56
- paramsCasing,
57
- pathParamsType,
58
- node,
59
- tsResolver,
60
- isConfigurable,
61
- }: GetParamsProps): ast.FunctionParametersNode {
62
- return ast.createOperationParams(node, {
63
- paramsType,
64
- pathParamsType: paramsType === 'object' ? 'object' : pathParamsType === 'object' ? 'object' : 'inline',
65
- paramsCasing,
66
- resolver: tsResolver,
67
- extraParams: [
68
- ...(isConfigurable
69
- ? [
70
- ast.createFunctionParameter({
71
- name: 'config',
72
- type: ast.createParamsType({
73
- variant: 'reference',
74
- name: buildRequestConfigType(node, tsResolver),
75
- }),
76
- default: '{}',
77
- }),
78
- ]
79
- : []),
80
- ],
81
- })
82
- }
83
-
84
- export function Client({
85
- name,
86
- isExportable = true,
87
- isIndexable = true,
88
- returnType,
89
- baseURL,
90
- dataReturnType,
91
- parser,
92
- paramsType,
93
- paramsCasing,
94
- pathParamsType,
95
- node,
96
- tsResolver,
97
- zodResolver,
98
- urlName,
99
- children,
100
- isConfigurable = true,
101
- }: Props): KubbReactNode {
102
- if (!ast.isHttpOperationNode(node)) return null
103
- const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node)
104
- const isFormData = !isMultipleContentTypes && contentType === 'multipart/form-data'
105
- const responseType = getResponseType(node)
106
-
107
- const { path: originalPathParams, query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node)
108
- const { path: casedPathParams, query: casedQueryParams, header: casedHeaderParams } = getOperationParameters(node, { paramsCasing })
109
-
110
- const pathParamsMapping = paramsCasing && !urlName ? buildParamsMapping(originalPathParams, casedPathParams) : null
111
- const queryParamsMapping = paramsCasing ? buildParamsMapping(originalQueryParams, casedQueryParams) : null
112
- const headerParamsMapping = paramsCasing ? buildParamsMapping(originalHeaderParams, casedHeaderParams) : null
113
-
114
- const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null
115
- const successNames = resolveSuccessNames(node, tsResolver)
116
- const responseName = successNames.length > 0 ? successNames.join(' | ') : tsResolver.resolveResponseName(node)
117
- const queryParamsName = originalQueryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, originalQueryParams[0]!) : null
118
- const headerParamsName = originalHeaderParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, originalHeaderParams[0]!) : null
119
-
120
- const requestParser = resolveRequestParser(parser)
121
- const responseParser = resolveResponseParser(parser)
122
- const zodResponseName = zodResolver && responseParser === 'zod' ? zodResolver.resolveResponseName?.(node) : null
123
- const zodRequestName = zodResolver && requestParser === 'zod' && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null
124
- const queryParamsParser = resolveQueryParamsParser(parser)
125
- const zodQueryParamsName =
126
- zodResolver && queryParamsParser === 'zod' && originalQueryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, originalQueryParams[0]!) : null
127
-
128
- const errorNames = node.responses
129
- .filter((r) => {
130
- const code = Number.parseInt(r.statusCode, 10)
131
- return code >= 400
132
- })
133
- .map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode))
134
-
135
- const headers = [
136
- !isMultipleContentTypes && contentType !== 'application/json' && contentType !== 'multipart/form-data' ? `'Content-Type': '${contentType}'` : null,
137
- headerParamsName ? (headerParamsMapping ? '...mappedHeaders' : '...headers') : null,
138
- ].filter(Boolean)
139
-
140
- const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`
141
-
142
- const allStatusNames = node.responses.map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode))
143
- const genericsResponseName = dataReturnType === 'full' ? (allStatusNames.length > 0 ? allStatusNames.join(' | ') : responseName) : responseName
144
- // z.output<> reflects the post-transform type (e.g. date coercion turns Date → string), avoiding a compile error on the generated call
145
- const requestGenericType = parser === 'zod' && zodRequestName ? `z.output<typeof ${zodRequestName}>` : requestName || 'unknown'
146
- const generics = [genericsResponseName, TError, requestGenericType].filter(Boolean)
147
- const paramsNode = buildClientParamsNode({
148
- paramsType,
149
- paramsCasing,
150
- pathParamsType,
151
- node,
152
- tsResolver,
153
- isConfigurable,
154
- })
155
- const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
156
-
157
- const urlParamsNode = buildUrlParamsNode({
158
- paramsType,
159
- paramsCasing,
160
- pathParamsType,
161
- node,
162
- tsResolver,
163
- })
164
- const callPrinter = functionPrinter({ mode: 'call' })
165
- const urlParamsCall = callPrinter.print(urlParamsNode) ?? ''
166
-
167
- const clientParams = createFunctionParams({
168
- config: {
169
- mode: 'object',
170
- children: {
171
- method: {
172
- value: stringify(node.method.toUpperCase()),
173
- },
174
- url: {
175
- value: urlName ? `${urlName}(${urlParamsCall}).url.toString()` : Url.toTemplateString(node.path),
176
- },
177
- baseURL:
178
- baseURL && !urlName
179
- ? {
180
- value: `\`${baseURL}\``,
181
- }
182
- : null,
183
- params: queryParamsName ? (zodQueryParamsName ? { value: 'requestParams' } : queryParamsMapping ? { value: 'mappedParams' } : {}) : null,
184
- data: requestName
185
- ? {
186
- value:
187
- isMultipleContentTypes && hasFormData
188
- ? "contentType === 'multipart/form-data' ? formData as FormData : requestData"
189
- : isFormData
190
- ? 'formData as FormData'
191
- : 'requestData',
192
- }
193
- : null,
194
- contentType: isConfigurable && isMultipleContentTypes ? {} : null,
195
- responseType: responseType ? { value: stringify(responseType) } : null,
196
- requestConfig: isConfigurable
197
- ? {
198
- mode: 'inlineSpread',
199
- }
200
- : null,
201
- headers: headers.length
202
- ? {
203
- value: isConfigurable ? `{ ${headers.join(', ')}, ...requestConfig.headers }` : `{ ${headers.join(', ')} }`,
204
- }
205
- : null,
206
- },
207
- },
208
- })
209
-
210
- const statusUnionType = dataReturnType === 'full' ? buildStatusUnionType(node, tsResolver) : null
211
-
212
- const childrenElement = children ? (
213
- children
214
- ) : (
215
- <>
216
- {dataReturnType === 'full' &&
217
- responseParser === 'zod' &&
218
- zodResponseName &&
219
- statusUnionType &&
220
- `return {...res, data: ${zodResponseName}.parse(res.data)} as ${statusUnionType}`}
221
- {dataReturnType === 'full' && responseParser !== 'zod' && statusUnionType && `return res as ${statusUnionType}`}
222
- {dataReturnType === 'data' && responseParser === 'zod' && zodResponseName && `return ${zodResponseName}.parse(res.data)`}
223
- {dataReturnType === 'data' && responseParser !== 'zod' && 'return res.data'}
224
- </>
225
- )
226
-
227
- return (
228
- <>
229
- <br />
230
-
231
- <File.Source name={name} isExportable={isExportable} isIndexable={isIndexable}>
232
- <Function
233
- name={name}
234
- async
235
- export={isExportable}
236
- params={paramsSignature}
237
- JSDoc={{
238
- comments: buildOperationComments(node, { link: 'urlPath', linkPosition: 'beforeDeprecated', splitLines: true }),
239
- }}
240
- returnType={returnType}
241
- >
242
- {isConfigurable
243
- ? `const { client: request = client, ${isMultipleContentTypes ? `contentType = ${stringify(contentType)}, ` : ''}...requestConfig } = config`
244
- : ''}
245
- <br />
246
- {pathParamsMapping &&
247
- Object.entries(pathParamsMapping)
248
- .filter(([originalName, camelCaseName]) => isValidVarName(originalName) && originalName !== camelCaseName)
249
- .map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`)
250
- .join('\n')}
251
- {pathParamsMapping && <br />}
252
- {queryParamsMapping && queryParamsName && (
253
- <>
254
- {`const mappedParams = params ? { ${Object.entries(queryParamsMapping)
255
- .map(([originalName, camelCaseName]) => `"${originalName}": params.${camelCaseName}`)
256
- .join(', ')} } : undefined`}
257
- <br />
258
- </>
259
- )}
260
- {headerParamsMapping && headerParamsName && (
261
- <>
262
- {`const mappedHeaders = headers ? { ${Object.entries(headerParamsMapping)
263
- .map(([originalName, camelCaseName]) => `"${originalName}": headers.${camelCaseName}`)
264
- .join(', ')} } : undefined`}
265
- <br />
266
- </>
267
- )}
268
- {requestParser === 'zod' && zodRequestName ? `const requestData = ${zodRequestName}.parse(data)` : requestName && 'const requestData = data'}
269
- {zodQueryParamsName && `const requestParams = ${zodQueryParamsName}.parse(params)`}
270
- {(isFormData || (isMultipleContentTypes && hasFormData)) && requestName && 'const formData = buildFormData(requestData)'}
271
- <br />
272
- {isConfigurable
273
- ? `const res = await request<${generics.join(', ')}>(${clientParams.toCall()})`
274
- : `const res = await client<${generics.join(', ')}>(${clientParams.toCall()})`}
275
- <br />
276
- {childrenElement}
277
- </Function>
278
- </File.Source>
279
- </>
280
- )
281
- }
@@ -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
- }
@@ -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
- }
@@ -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
- }