@kubb/plugin-client 5.0.0-alpha.3 → 5.0.0-alpha.31

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.
Files changed (42) hide show
  1. package/dist/clients/axios.d.ts +2 -2
  2. package/dist/index.cjs +1893 -74
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +480 -4
  5. package/dist/index.js +1885 -77
  6. package/dist/index.js.map +1 -1
  7. package/package.json +10 -25
  8. package/src/components/ClassClient.tsx +42 -138
  9. package/src/components/Client.tsx +85 -124
  10. package/src/components/ClientLegacy.tsx +501 -0
  11. package/src/components/Operations.tsx +8 -8
  12. package/src/components/StaticClassClient.tsx +41 -135
  13. package/src/components/Url.tsx +37 -46
  14. package/src/generators/classClientGenerator.tsx +125 -148
  15. package/src/generators/clientGenerator.tsx +93 -82
  16. package/src/generators/groupedClientGenerator.tsx +47 -50
  17. package/src/generators/operationsGenerator.tsx +9 -17
  18. package/src/generators/staticClassClientGenerator.tsx +159 -164
  19. package/src/index.ts +11 -1
  20. package/src/plugin.ts +115 -108
  21. package/src/presets.ts +25 -0
  22. package/src/resolvers/resolverClient.ts +26 -0
  23. package/src/resolvers/resolverClientLegacy.ts +26 -0
  24. package/src/types.ts +105 -40
  25. package/src/utils.ts +148 -0
  26. package/dist/StaticClassClient-By-aMAe4.cjs +0 -677
  27. package/dist/StaticClassClient-By-aMAe4.cjs.map +0 -1
  28. package/dist/StaticClassClient-CCn9g9eF.js +0 -636
  29. package/dist/StaticClassClient-CCn9g9eF.js.map +0 -1
  30. package/dist/components.cjs +0 -7
  31. package/dist/components.d.ts +0 -216
  32. package/dist/components.js +0 -2
  33. package/dist/generators-C2jT7XCH.js +0 -723
  34. package/dist/generators-C2jT7XCH.js.map +0 -1
  35. package/dist/generators-qkDW17Hf.cjs +0 -753
  36. package/dist/generators-qkDW17Hf.cjs.map +0 -1
  37. package/dist/generators.cjs +0 -7
  38. package/dist/generators.d.ts +0 -512
  39. package/dist/generators.js +0 -2
  40. package/dist/types-CdM4DK1M.d.ts +0 -169
  41. package/src/components/index.ts +0 -5
  42. package/src/generators/index.ts +0 -5
@@ -0,0 +1,501 @@
1
+ import { camelCase, isValidVarName, URLPath } from '@internals/utils'
2
+ import { Const, File, Function, FunctionParams } from '@kubb/react-fabric'
3
+ import type { FabricReactNode, Params } from '@kubb/react-fabric/types'
4
+
5
+ /**
6
+ * Structural type matching OperationSchema from @kubb/plugin-oas.
7
+ * Avoids importing from @kubb/oas or @kubb/plugin-oas.
8
+ * Uses broad types so that OperationSchemas is assignable without imports.
9
+ */
10
+ type LegacyOperationSchema = {
11
+ name?: string
12
+ schema?: Record<string, any>
13
+ statusCode?: string | number
14
+ [key: string]: unknown
15
+ }
16
+
17
+ type LegacyOperationSchemas = {
18
+ pathParams?: LegacyOperationSchema
19
+ queryParams?: LegacyOperationSchema
20
+ headerParams?: LegacyOperationSchema
21
+ request?: LegacyOperationSchema
22
+ response: LegacyOperationSchema & { name: string }
23
+ statusCodes?: Array<LegacyOperationSchema & { name: string }>
24
+ errors?: Array<LegacyOperationSchema & { name: string }>
25
+ [key: string]: unknown
26
+ }
27
+
28
+ type LegacyOperation = {
29
+ path: string
30
+ method: string
31
+ getDescription?(): string | undefined
32
+ getSummary?(): string | undefined
33
+ isDeprecated?(): boolean
34
+ getContentType?(): string
35
+ }
36
+
37
+ function isSchemaRequired(schema?: LegacyOperationSchema['schema']): boolean {
38
+ if (!schema) return false
39
+ return Array.isArray(schema.required) ? !!schema.required.length : !!schema.required
40
+ }
41
+
42
+ function isSchemaOptional(schema?: LegacyOperationSchema['schema']): boolean {
43
+ return !isSchemaRequired(schema)
44
+ }
45
+
46
+ function isAllOptionalDeep(schema?: any): boolean {
47
+ if (!schema) return true
48
+ if (Array.isArray(schema.required) && schema.required.length > 0) return false
49
+ if (schema.allOf) return (schema.allOf as any[]).every(isAllOptionalDeep)
50
+ return true
51
+ }
52
+
53
+ function getSchemaDefaultValue(schema?: LegacyOperationSchema['schema']): string | undefined {
54
+ if (!schema || !isSchemaOptional(schema)) return undefined
55
+ if (schema.type === 'array') return '[]'
56
+ if (schema.anyOf || schema.oneOf) {
57
+ const variants = (schema.anyOf || schema.oneOf) as any[]
58
+ if (!Array.isArray(variants)) return undefined
59
+ if (variants.some(isAllOptionalDeep)) return '{}'
60
+ return undefined
61
+ }
62
+ if (schema.type === 'object' || schema.properties) return '{}'
63
+ return undefined
64
+ }
65
+
66
+ function legacyGetPathParams(operationSchema: LegacyOperationSchema | undefined, options: { typed?: boolean; casing?: 'camelcase' } = {}): Params {
67
+ if (!operationSchema?.schema?.properties || !operationSchema.name) return {}
68
+
69
+ const requiredFields = Array.isArray(operationSchema.schema.required) ? operationSchema.schema.required : []
70
+
71
+ return Object.entries(operationSchema.schema.properties).reduce((acc, [name]) => {
72
+ if (!name) return acc
73
+ let paramName = name
74
+ if (options.casing === 'camelcase') {
75
+ paramName = camelCase(name)
76
+ } else if (!isValidVarName(name)) {
77
+ paramName = camelCase(name)
78
+ }
79
+
80
+ const accessName = options.casing === 'camelcase' ? camelCase(name) : name
81
+
82
+ acc[paramName] = {
83
+ default: undefined,
84
+ type: options.typed ? `${operationSchema.name}["${accessName}"]` : undefined,
85
+ optional: !requiredFields.includes(name),
86
+ }
87
+ return acc
88
+ }, {} as Params)
89
+ }
90
+
91
+ function legacyGetParamsMapping(
92
+ operationSchema: LegacyOperationSchema | undefined,
93
+ options: { casing?: 'camelcase' } = {},
94
+ ): Record<string, string> | undefined {
95
+ if (!operationSchema?.schema?.properties) return undefined
96
+
97
+ const allEntries: Array<[string, string]> = []
98
+ let hasTransformation = false
99
+
100
+ Object.entries(operationSchema.schema.properties).forEach(([originalName]) => {
101
+ let transformedName = originalName
102
+ if (options.casing === 'camelcase') {
103
+ transformedName = camelCase(originalName)
104
+ } else if (!isValidVarName(originalName)) {
105
+ transformedName = camelCase(originalName)
106
+ }
107
+ allEntries.push([originalName, transformedName])
108
+ if (transformedName !== originalName) hasTransformation = true
109
+ })
110
+
111
+ if (options.casing === 'camelcase' && hasTransformation) {
112
+ return Object.fromEntries(allEntries)
113
+ }
114
+
115
+ const mapping: Record<string, string> = {}
116
+ allEntries.forEach(([originalName, transformedName]) => {
117
+ if (transformedName !== originalName) mapping[originalName] = transformedName
118
+ })
119
+
120
+ return Object.keys(mapping).length > 0 ? mapping : undefined
121
+ }
122
+
123
+ function legacyGetComments(operation: LegacyOperation): string[] {
124
+ return [
125
+ operation.getDescription?.() && `@description ${operation.getDescription!()}`,
126
+ operation.getSummary?.() && `@summary ${operation.getSummary!()}`,
127
+ operation.path && `{@link ${new URLPath(operation.path).URL}}`,
128
+ operation.isDeprecated?.() && '@deprecated',
129
+ ]
130
+ .filter((x): x is string => Boolean(x))
131
+ .flatMap((text) => text.split(/\r?\n/).map((line) => line.trim()))
132
+ .filter((x): x is string => Boolean(x))
133
+ }
134
+
135
+ type Props = {
136
+ name: string
137
+ urlName?: string
138
+ isExportable?: boolean
139
+ isIndexable?: boolean
140
+ isConfigurable?: boolean
141
+ returnType?: string
142
+ baseURL: string | undefined
143
+ dataReturnType: 'data' | 'full'
144
+ paramsCasing?: 'camelcase'
145
+ paramsType: 'object' | 'inline'
146
+ pathParamsType: 'object' | 'inline'
147
+ parser: 'client' | 'zod' | undefined
148
+ typeSchemas: LegacyOperationSchemas
149
+ zodSchemas: LegacyOperationSchemas | undefined
150
+ operation: LegacyOperation
151
+ children?: FabricReactNode
152
+ }
153
+
154
+ type GetParamsProps = {
155
+ paramsCasing?: 'camelcase'
156
+ paramsType: 'object' | 'inline'
157
+ pathParamsType: 'object' | 'inline'
158
+ typeSchemas: LegacyOperationSchemas
159
+ isConfigurable: boolean
160
+ }
161
+
162
+ function getParams({ paramsType, paramsCasing, pathParamsType, typeSchemas, isConfigurable }: GetParamsProps) {
163
+ if (paramsType === 'object') {
164
+ const pathParams = legacyGetPathParams(typeSchemas.pathParams, {
165
+ typed: true,
166
+ casing: paramsCasing,
167
+ })
168
+
169
+ const children = {
170
+ ...pathParams,
171
+ data: typeSchemas.request?.name
172
+ ? {
173
+ type: typeSchemas.request?.name,
174
+ optional: isSchemaOptional(typeSchemas.request?.schema),
175
+ }
176
+ : undefined,
177
+ params: typeSchemas.queryParams?.name
178
+ ? {
179
+ type: typeSchemas.queryParams?.name,
180
+ optional: isSchemaOptional(typeSchemas.queryParams?.schema),
181
+ }
182
+ : undefined,
183
+ headers: typeSchemas.headerParams?.name
184
+ ? {
185
+ type: typeSchemas.headerParams?.name,
186
+ optional: isSchemaOptional(typeSchemas.headerParams?.schema),
187
+ }
188
+ : undefined,
189
+ }
190
+
191
+ const allChildrenAreOptional = Object.values(children).every((child) => !child || child.optional)
192
+
193
+ return FunctionParams.factory({
194
+ data: {
195
+ mode: 'object' as const,
196
+ children,
197
+ default: allChildrenAreOptional ? '{}' : undefined,
198
+ },
199
+ config: isConfigurable
200
+ ? {
201
+ type: typeSchemas.request?.name
202
+ ? `Partial<RequestConfig<${typeSchemas.request?.name}>> & { client?: Client }`
203
+ : 'Partial<RequestConfig> & { client?: Client }',
204
+ default: '{}',
205
+ }
206
+ : undefined,
207
+ })
208
+ }
209
+
210
+ return FunctionParams.factory({
211
+ pathParams: typeSchemas.pathParams?.name
212
+ ? {
213
+ mode: pathParamsType === 'object' ? ('object' as const) : ('inlineSpread' as const),
214
+ children: legacyGetPathParams(typeSchemas.pathParams, {
215
+ typed: true,
216
+ casing: paramsCasing,
217
+ }),
218
+ default: getSchemaDefaultValue(typeSchemas.pathParams?.schema),
219
+ }
220
+ : undefined,
221
+ data: typeSchemas.request?.name
222
+ ? {
223
+ type: typeSchemas.request?.name,
224
+ optional: isSchemaOptional(typeSchemas.request?.schema),
225
+ }
226
+ : undefined,
227
+ params: typeSchemas.queryParams?.name
228
+ ? {
229
+ type: typeSchemas.queryParams?.name,
230
+ optional: isSchemaOptional(typeSchemas.queryParams?.schema),
231
+ }
232
+ : undefined,
233
+ headers: typeSchemas.headerParams?.name
234
+ ? {
235
+ type: typeSchemas.headerParams?.name,
236
+ optional: isSchemaOptional(typeSchemas.headerParams?.schema),
237
+ }
238
+ : undefined,
239
+ config: isConfigurable
240
+ ? {
241
+ type: typeSchemas.request?.name
242
+ ? `Partial<RequestConfig<${typeSchemas.request?.name}>> & { client?: Client }`
243
+ : 'Partial<RequestConfig> & { client?: Client }',
244
+ default: '{}',
245
+ }
246
+ : undefined,
247
+ })
248
+ }
249
+
250
+ export function ClientLegacy({
251
+ name,
252
+ isExportable = true,
253
+ isIndexable = true,
254
+ returnType,
255
+ typeSchemas,
256
+ baseURL,
257
+ dataReturnType,
258
+ parser,
259
+ zodSchemas,
260
+ paramsType,
261
+ paramsCasing,
262
+ pathParamsType,
263
+ operation,
264
+ urlName,
265
+ children,
266
+ isConfigurable = true,
267
+ }: Props): FabricReactNode {
268
+ const path = new URLPath(operation.path)
269
+ const contentType = operation.getContentType?.() ?? 'application/json'
270
+ const isFormData = contentType === 'multipart/form-data'
271
+
272
+ const pathParamsMapping = paramsCasing && !urlName ? legacyGetParamsMapping(typeSchemas.pathParams, { casing: paramsCasing }) : undefined
273
+ const queryParamsMapping = paramsCasing ? legacyGetParamsMapping(typeSchemas.queryParams, { casing: paramsCasing }) : undefined
274
+ const headerParamsMapping = paramsCasing ? legacyGetParamsMapping(typeSchemas.headerParams, { casing: paramsCasing }) : undefined
275
+
276
+ const headers = [
277
+ contentType !== 'application/json' && contentType !== 'multipart/form-data' ? `'Content-Type': '${contentType}'` : undefined,
278
+ typeSchemas.headerParams?.name ? (headerParamsMapping ? '...mappedHeaders' : '...headers') : undefined,
279
+ ].filter(Boolean)
280
+
281
+ const TError = `ResponseErrorConfig<${typeSchemas.errors?.map((item) => item.name).join(' | ') || 'Error'}>`
282
+
283
+ const generics = [typeSchemas.response.name, TError, typeSchemas.request?.name || 'unknown'].filter(Boolean)
284
+ const params = getParams({
285
+ paramsType,
286
+ paramsCasing,
287
+ pathParamsType,
288
+ typeSchemas,
289
+ isConfigurable,
290
+ })
291
+ const urlParams = UrlLegacy.getParams({
292
+ paramsType,
293
+ paramsCasing,
294
+ pathParamsType,
295
+ typeSchemas,
296
+ })
297
+
298
+ const clientParams = FunctionParams.factory({
299
+ config: {
300
+ mode: 'object' as const,
301
+ children: {
302
+ method: {
303
+ value: JSON.stringify(operation.method.toUpperCase()),
304
+ },
305
+ url: {
306
+ value: urlName ? `${urlName}(${urlParams.toCall()}).url.toString()` : path.template,
307
+ },
308
+ baseURL:
309
+ baseURL && !urlName
310
+ ? {
311
+ value: `\`${baseURL}\``,
312
+ }
313
+ : undefined,
314
+ params: typeSchemas.queryParams?.name ? (queryParamsMapping ? { value: 'mappedParams' } : {}) : undefined,
315
+ data: typeSchemas.request?.name
316
+ ? {
317
+ value: isFormData ? 'formData as FormData' : 'requestData',
318
+ }
319
+ : undefined,
320
+ requestConfig: isConfigurable
321
+ ? {
322
+ mode: 'inlineSpread' as const,
323
+ }
324
+ : undefined,
325
+ headers: headers.length
326
+ ? {
327
+ value: isConfigurable ? `{ ${headers.join(', ')}, ...requestConfig.headers }` : `{ ${headers.join(', ')} }`,
328
+ }
329
+ : undefined,
330
+ },
331
+ },
332
+ })
333
+
334
+ const childrenElement = children ? (
335
+ children
336
+ ) : (
337
+ <>
338
+ {dataReturnType === 'full' && parser === 'zod' && zodSchemas && `return {...res, data: ${zodSchemas.response.name}.parse(res.data)}`}
339
+ {dataReturnType === 'data' && parser === 'zod' && zodSchemas && `return ${zodSchemas.response.name}.parse(res.data)`}
340
+ {dataReturnType === 'full' && parser === 'client' && 'return res'}
341
+ {dataReturnType === 'data' && parser === 'client' && 'return res.data'}
342
+ </>
343
+ )
344
+
345
+ return (
346
+ <>
347
+ <br />
348
+
349
+ <File.Source name={name} isExportable={isExportable} isIndexable={isIndexable}>
350
+ <Function
351
+ name={name}
352
+ async
353
+ export={isExportable}
354
+ params={params.toConstructor()}
355
+ JSDoc={{
356
+ comments: legacyGetComments(operation),
357
+ }}
358
+ returnType={returnType}
359
+ >
360
+ {isConfigurable ? 'const { client: request = fetch, ...requestConfig } = config' : ''}
361
+ <br />
362
+ <br />
363
+ {pathParamsMapping &&
364
+ Object.entries(pathParamsMapping)
365
+ .filter(([originalName, camelCaseName]) => originalName !== camelCaseName && isValidVarName(originalName))
366
+ .map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`)
367
+ .join('\n')}
368
+ {pathParamsMapping && (
369
+ <>
370
+ <br />
371
+ <br />
372
+ </>
373
+ )}
374
+ {queryParamsMapping && typeSchemas.queryParams?.name && (
375
+ <>
376
+ {`const mappedParams = params ? { ${Object.entries(queryParamsMapping)
377
+ .map(([originalName, camelCaseName]) => `"${originalName}": params.${camelCaseName}`)
378
+ .join(', ')} } : undefined`}
379
+ <br />
380
+ <br />
381
+ </>
382
+ )}
383
+ {headerParamsMapping && typeSchemas.headerParams?.name && (
384
+ <>
385
+ {`const mappedHeaders = headers ? { ${Object.entries(headerParamsMapping)
386
+ .map(([originalName, camelCaseName]) => `"${originalName}": headers.${camelCaseName}`)
387
+ .join(', ')} } : undefined`}
388
+ <br />
389
+ <br />
390
+ </>
391
+ )}
392
+ {parser === 'zod' && zodSchemas?.request?.name
393
+ ? `const requestData = ${zodSchemas.request.name}.parse(data)`
394
+ : typeSchemas?.request?.name && 'const requestData = data'}
395
+ <br />
396
+ {isFormData && typeSchemas?.request?.name && 'const formData = buildFormData(requestData)'}
397
+ <br />
398
+ {isConfigurable
399
+ ? `const res = await request<${generics.join(', ')}>(${clientParams.toCall()})`
400
+ : `const res = await fetch<${generics.join(', ')}>(${clientParams.toCall()})`}
401
+ <br />
402
+ {childrenElement}
403
+ </Function>
404
+ </File.Source>
405
+ </>
406
+ )
407
+ }
408
+
409
+ ClientLegacy.getParams = getParams
410
+
411
+ // --- UrlLegacy ---
412
+
413
+ type UrlProps = {
414
+ name: string
415
+ isExportable?: boolean
416
+ isIndexable?: boolean
417
+ baseURL: string | undefined
418
+ paramsCasing?: 'camelcase'
419
+ paramsType: 'object' | 'inline'
420
+ pathParamsType: 'object' | 'inline'
421
+ typeSchemas: LegacyOperationSchemas
422
+ operation: LegacyOperation
423
+ }
424
+
425
+ type UrlGetParamsProps = {
426
+ paramsCasing?: 'camelcase'
427
+ paramsType: 'object' | 'inline'
428
+ pathParamsType: 'object' | 'inline'
429
+ typeSchemas: LegacyOperationSchemas
430
+ }
431
+
432
+ function getUrlParams({ paramsType, paramsCasing, pathParamsType, typeSchemas }: UrlGetParamsProps) {
433
+ if (paramsType === 'object') {
434
+ const pathParams = legacyGetPathParams(typeSchemas.pathParams, {
435
+ typed: true,
436
+ casing: paramsCasing,
437
+ })
438
+
439
+ return FunctionParams.factory({
440
+ data: {
441
+ mode: 'object' as const,
442
+ children: {
443
+ ...pathParams,
444
+ },
445
+ },
446
+ })
447
+ }
448
+
449
+ return FunctionParams.factory({
450
+ pathParams: typeSchemas.pathParams?.name
451
+ ? {
452
+ mode: pathParamsType === 'object' ? ('object' as const) : ('inlineSpread' as const),
453
+ children: legacyGetPathParams(typeSchemas.pathParams, {
454
+ typed: true,
455
+ casing: paramsCasing,
456
+ }),
457
+ default: getSchemaDefaultValue(typeSchemas.pathParams?.schema),
458
+ }
459
+ : undefined,
460
+ })
461
+ }
462
+
463
+ export function UrlLegacy({
464
+ name,
465
+ isExportable = true,
466
+ isIndexable = true,
467
+ typeSchemas,
468
+ baseURL,
469
+ paramsType,
470
+ paramsCasing,
471
+ pathParamsType,
472
+ operation,
473
+ }: UrlProps): FabricReactNode {
474
+ const path = new URLPath(operation.path)
475
+ const params = getUrlParams({
476
+ paramsType,
477
+ paramsCasing,
478
+ pathParamsType,
479
+ typeSchemas,
480
+ })
481
+
482
+ const pathParamsMapping = paramsCasing ? legacyGetParamsMapping(typeSchemas.pathParams, { casing: paramsCasing }) : undefined
483
+
484
+ return (
485
+ <File.Source name={name} isExportable={isExportable} isIndexable={isIndexable}>
486
+ <Function name={name} export={isExportable} params={params.toConstructor()}>
487
+ {pathParamsMapping &&
488
+ Object.entries(pathParamsMapping)
489
+ .filter(([originalName, camelCaseName]) => originalName !== camelCaseName && isValidVarName(originalName))
490
+ .map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`)
491
+ .join('\n')}
492
+ {pathParamsMapping && <br />}
493
+ <Const name={'res'}>{`{ method: '${operation.method.toUpperCase()}', url: ${path.toTemplateString({ prefix: baseURL })} as const }`}</Const>
494
+ <br />
495
+ return res
496
+ </Function>
497
+ </File.Source>
498
+ )
499
+ }
500
+
501
+ UrlLegacy.getParams = getUrlParams
@@ -1,20 +1,20 @@
1
1
  import { URLPath } from '@internals/utils'
2
- import type { HttpMethod, Operation } from '@kubb/oas'
2
+ import type { OperationNode } from '@kubb/ast/types'
3
3
  import { Const, File } from '@kubb/react-fabric'
4
4
  import type { FabricReactNode } from '@kubb/react-fabric/types'
5
5
 
6
6
  type OperationsProps = {
7
7
  name: string
8
- operations: Array<Operation>
8
+ nodes: Array<OperationNode>
9
9
  }
10
10
 
11
- export function Operations({ name, operations }: OperationsProps): FabricReactNode {
12
- const operationsObject: Record<string, { path: string; method: HttpMethod }> = {}
11
+ export function Operations({ name, nodes }: OperationsProps): FabricReactNode {
12
+ const operationsObject: Record<string, { path: string; method: string }> = {}
13
13
 
14
- operations.forEach((operation) => {
15
- operationsObject[operation.getOperationId()] = {
16
- path: new URLPath(operation.path).URL,
17
- method: operation.method,
14
+ nodes.forEach((node) => {
15
+ operationsObject[node.operationId] = {
16
+ path: new URLPath(node.path).URL,
17
+ method: node.method.toLowerCase(),
18
18
  }
19
19
  })
20
20