@kubb/plugin-ts 5.0.0-alpha.8 → 5.0.0-beta.10

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 (43) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +26 -7
  3. package/dist/index.cjs +1526 -4
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.ts +574 -4
  6. package/dist/index.js +1488 -2
  7. package/dist/index.js.map +1 -0
  8. package/extension.yaml +632 -0
  9. package/package.json +43 -65
  10. package/src/components/{v2/Enum.tsx → Enum.tsx} +33 -17
  11. package/src/components/Type.tsx +31 -161
  12. package/src/constants.ts +15 -5
  13. package/src/factory.ts +295 -39
  14. package/src/generators/typeGenerator.tsx +248 -420
  15. package/src/index.ts +9 -2
  16. package/src/plugin.ts +67 -205
  17. package/src/printers/functionPrinter.ts +197 -0
  18. package/src/printers/printerTs.ts +329 -0
  19. package/src/resolvers/resolverTs.ts +66 -0
  20. package/src/types.ts +238 -94
  21. package/src/utils.ts +129 -0
  22. package/dist/components-CRu8IKY3.js +0 -729
  23. package/dist/components-CRu8IKY3.js.map +0 -1
  24. package/dist/components-DeNDKlzf.cjs +0 -982
  25. package/dist/components-DeNDKlzf.cjs.map +0 -1
  26. package/dist/components.cjs +0 -3
  27. package/dist/components.d.ts +0 -36
  28. package/dist/components.js +0 -2
  29. package/dist/generators.cjs +0 -4
  30. package/dist/generators.d.ts +0 -480
  31. package/dist/generators.js +0 -2
  32. package/dist/plugin-D5NGPj0v.js +0 -1232
  33. package/dist/plugin-D5NGPj0v.js.map +0 -1
  34. package/dist/plugin-MLTxoa8p.cjs +0 -1279
  35. package/dist/plugin-MLTxoa8p.cjs.map +0 -1
  36. package/dist/types-CsvB6X5Y.d.ts +0 -167
  37. package/src/components/index.ts +0 -1
  38. package/src/components/v2/Type.tsx +0 -59
  39. package/src/generators/index.ts +0 -2
  40. package/src/generators/v2/typeGenerator.tsx +0 -171
  41. package/src/generators/v2/utils.ts +0 -140
  42. package/src/parser.ts +0 -389
  43. package/src/printer.ts +0 -368
@@ -1,467 +1,295 @@
1
- import { pascalCase } from '@internals/utils'
2
- import type { PluginDriver } from '@kubb/core'
3
- import { useMode, usePluginDriver } from '@kubb/core/hooks'
4
- import { safePrint } from '@kubb/fabric-core/parsers/typescript'
5
- import type { Operation } from '@kubb/oas'
6
- import { isKeyword, type OperationSchemas, type OperationSchema as OperationSchemaType, SchemaGenerator, schemaKeywords } from '@kubb/plugin-oas'
7
- import { createReactGenerator } from '@kubb/plugin-oas/generators'
8
- import { useOas, useOperationManager, useSchemaManager } from '@kubb/plugin-oas/hooks'
9
- import { applyParamsCasing, getBanner, getFooter, getImports, isParameterSchema } from '@kubb/plugin-oas/utils'
10
- import { File } from '@kubb/react-fabric'
11
- import ts from 'typescript'
12
- import { Type } from '../components'
13
- import * as factory from '../factory.ts'
14
- import { createUrlTemplateType, getUnknownType, keywordTypeNodes } from '../factory.ts'
15
- import { pluginTsName } from '../plugin.ts'
1
+ import { ast, defineGenerator } from '@kubb/core'
2
+ import { File, jsxRenderer } from '@kubb/renderer-jsx'
3
+ import { Type } from '../components/Type.tsx'
4
+ import { ENUM_TYPES_WITH_KEY_SUFFIX } from '../constants.ts'
5
+ import { printerTs } from '../printers/printerTs.ts'
16
6
  import type { PluginTs } from '../types'
7
+ import { buildData, buildResponses, buildResponseUnion } from '../utils.ts'
8
+
9
+ function getContentTypeSuffix(contentType: string): string {
10
+ const baseType = contentType.split(';')[0]!.trim()
11
+ if (baseType === 'application/json') return 'Json'
12
+ if (baseType === 'multipart/form-data') return 'FormData'
13
+ if (baseType === 'application/x-www-form-urlencoded') return 'FormUrlEncoded'
14
+ const subtype = baseType.split('/').pop() ?? baseType
15
+ const parts = subtype.split(/[^a-zA-Z0-9]+/).filter(Boolean)
16
+ if (parts.length === 0) return 'Unknown'
17
+ return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('')
18
+ }
17
19
 
18
- function printCombinedSchema({ name, schemas, driver }: { name: string; schemas: OperationSchemas; driver: PluginDriver }): string {
19
- const properties: Record<string, ts.TypeNode> = {}
20
-
21
- if (schemas.response) {
22
- properties['response'] = factory.createUnionDeclaration({
23
- nodes: schemas.responses.map((res) => {
24
- const identifier = driver.resolveName({
25
- name: res.name,
26
- pluginName: pluginTsName,
27
- type: 'function',
28
- })
29
-
30
- return factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
31
- }),
32
- })!
33
- }
34
-
35
- if (schemas.request) {
36
- const identifier = driver.resolveName({
37
- name: schemas.request.name,
38
- pluginName: pluginTsName,
39
- type: 'function',
40
- })
41
- properties['request'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
42
- }
43
-
44
- if (schemas.pathParams) {
45
- const identifier = driver.resolveName({
46
- name: schemas.pathParams.name,
47
- pluginName: pluginTsName,
48
- type: 'function',
49
- })
50
- properties['pathParams'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
51
- }
52
-
53
- if (schemas.queryParams) {
54
- const identifier = driver.resolveName({
55
- name: schemas.queryParams.name,
56
- pluginName: pluginTsName,
57
- type: 'function',
58
- })
59
- properties['queryParams'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
60
- }
61
-
62
- if (schemas.headerParams) {
63
- const identifier = driver.resolveName({
64
- name: schemas.headerParams.name,
65
- pluginName: pluginTsName,
66
- type: 'function',
67
- })
68
- properties['headerParams'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
69
- }
70
-
71
- if (schemas.errors) {
72
- properties['errors'] = factory.createUnionDeclaration({
73
- nodes: schemas.errors.map((error) => {
74
- const identifier = driver.resolveName({
75
- name: error.name,
76
- pluginName: pluginTsName,
77
- type: 'function',
78
- })
79
-
80
- return factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
81
- }),
82
- })!
20
+ function getPerContentTypeName(dataName: string, suffix: string): string {
21
+ if (dataName.endsWith('Data')) {
22
+ return suffix.endsWith('Data') ? dataName.slice(0, -4) + suffix : `${dataName.slice(0, -4)}${suffix}Data`
83
23
  }
84
-
85
- const namespaceNode = factory.createTypeAliasDeclaration({
86
- name,
87
- type: factory.createTypeLiteralNode(
88
- Object.keys(properties)
89
- .map((key) => {
90
- const type = properties[key]
91
- if (!type) {
92
- return undefined
93
- }
94
-
95
- return factory.createPropertySignature({
96
- name: pascalCase(key),
97
- type,
98
- })
99
- })
100
- .filter(Boolean),
101
- ),
102
- modifiers: [factory.modifiers.export],
103
- })
104
-
105
- return safePrint(namespaceNode)
24
+ return dataName + suffix
106
25
  }
107
26
 
108
- function printRequestSchema({
109
- baseName,
110
- operation,
111
- schemas,
112
- driver,
113
- }: {
114
- baseName: string
115
- operation: Operation
116
- schemas: OperationSchemas
117
- driver: PluginDriver
118
- }): string {
119
- const name = driver.resolveName({
120
- name: `${baseName} Request`,
121
- pluginName: pluginTsName,
122
- type: 'type',
123
- })
124
-
125
- const results: string[] = []
126
-
127
- // Generate DataRequest type
128
- const dataRequestProperties: ts.PropertySignature[] = []
129
-
130
- if (schemas.request) {
131
- const identifier = driver.resolveName({
132
- name: schemas.request.name,
133
- pluginName: pluginTsName,
134
- type: 'type',
135
- })
136
- dataRequestProperties.push(
137
- factory.createPropertySignature({
138
- name: 'data',
139
- questionToken: true,
140
- type: factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined),
141
- }),
142
- )
143
- } else {
144
- dataRequestProperties.push(
145
- factory.createPropertySignature({
146
- name: 'data',
147
- questionToken: true,
148
- type: keywordTypeNodes.never,
149
- }),
150
- )
151
- }
27
+ export const typeGenerator = defineGenerator<PluginTs>({
28
+ name: 'typescript',
29
+ renderer: jsxRenderer,
30
+ schema(node, ctx) {
31
+ const { enumType, enumTypeSuffix, enumKeyCasing, syntaxType, optionalType, arrayType, output, group, printer } = ctx.options
32
+ const { adapter, config, resolver, root } = ctx
152
33
 
153
- // Add pathParams property
154
- if (schemas.pathParams) {
155
- const identifier = driver.resolveName({
156
- name: schemas.pathParams.name,
157
- pluginName: pluginTsName,
158
- type: 'type',
159
- })
160
- dataRequestProperties.push(
161
- factory.createPropertySignature({
162
- name: 'pathParams',
163
- type: factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined),
164
- }),
165
- )
166
- } else {
167
- dataRequestProperties.push(
168
- factory.createPropertySignature({
169
- name: 'pathParams',
170
- questionToken: true,
171
- type: keywordTypeNodes.never,
172
- }),
173
- )
174
- }
34
+ if (!node.name) {
35
+ return
36
+ }
37
+ const mode = ctx.getMode(output)
38
+ // Build a set of schema names that are enums so the ref handler and getImports
39
+ // callback can use the suffixed type name (e.g. `StatusKey`) for those refs.
40
+ const enumSchemaNames = new Set((adapter.inputNode?.schemas ?? []).filter((s) => ast.narrowSchema(s, ast.schemaTypes.enum) && s.name).map((s) => s.name!))
41
+
42
+ function resolveImportName(schemaName: string): string {
43
+ if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && enumTypeSuffix && enumSchemaNames.has(schemaName)) {
44
+ return resolver.resolveEnumKeyName({ name: schemaName }, enumTypeSuffix)
45
+ }
46
+ return resolver.resolveTypeName(schemaName)
47
+ }
175
48
 
176
- // Add queryParams property
177
- if (schemas.queryParams) {
178
- const identifier = driver.resolveName({
179
- name: schemas.queryParams.name,
180
- pluginName: pluginTsName,
181
- type: 'type',
49
+ const imports = adapter.getImports(node, (schemaName) => ({
50
+ name: resolveImportName(schemaName),
51
+ path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
52
+ }))
53
+
54
+ const isEnumSchema = !!ast.narrowSchema(node, ast.schemaTypes.enum)
55
+
56
+ const meta = {
57
+ name: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && isEnumSchema ? resolver.resolveEnumKeyName(node, enumTypeSuffix) : resolver.resolveTypeName(node.name),
58
+ file: resolver.resolveFile({ name: node.name, extname: '.ts' }, { root, output, group }),
59
+ } as const
60
+
61
+ const schemaPrinter = printerTs({
62
+ optionalType,
63
+ arrayType,
64
+ enumType,
65
+ enumTypeSuffix,
66
+ name: meta.name,
67
+ syntaxType,
68
+ description: node.description,
69
+ resolver,
70
+ enumSchemaNames,
71
+ nodes: printer?.nodes,
182
72
  })
183
- dataRequestProperties.push(
184
- factory.createPropertySignature({
185
- name: 'queryParams',
186
- questionToken: true,
187
- type: factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined),
188
- }),
189
- )
190
- } else {
191
- dataRequestProperties.push(
192
- factory.createPropertySignature({
193
- name: 'queryParams',
194
- questionToken: true,
195
- type: keywordTypeNodes.never,
196
- }),
197
- )
198
- }
199
73
 
200
- // Add headerParams property
201
- if (schemas.headerParams) {
202
- const identifier = driver.resolveName({
203
- name: schemas.headerParams.name,
204
- pluginName: pluginTsName,
205
- type: 'type',
206
- })
207
- dataRequestProperties.push(
208
- factory.createPropertySignature({
209
- name: 'headerParams',
210
- questionToken: true,
211
- type: factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined),
212
- }),
213
- )
214
- } else {
215
- dataRequestProperties.push(
216
- factory.createPropertySignature({
217
- name: 'headerParams',
218
- questionToken: true,
219
- type: keywordTypeNodes.never,
220
- }),
74
+ return (
75
+ <File
76
+ baseName={meta.file.baseName}
77
+ path={meta.file.path}
78
+ meta={meta.file.meta}
79
+ banner={resolver.resolveBanner(adapter.inputNode, { output, config })}
80
+ footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
81
+ >
82
+ {mode === 'split' &&
83
+ imports.map((imp) => (
84
+ <File.Import key={[node.name, imp.path, imp.isTypeOnly].join('-')} root={meta.file.path} path={imp.path} name={imp.name} isTypeOnly />
85
+ ))}
86
+ <Type
87
+ name={meta.name}
88
+ node={node}
89
+ enumType={enumType}
90
+ enumTypeSuffix={enumTypeSuffix}
91
+ enumKeyCasing={enumKeyCasing}
92
+ resolver={resolver}
93
+ printer={schemaPrinter}
94
+ />
95
+ </File>
221
96
  )
222
- }
97
+ },
98
+ operation(node, ctx) {
99
+ const { enumType, enumTypeSuffix, enumKeyCasing, optionalType, arrayType, syntaxType, paramsCasing, group, output, printer } = ctx.options
100
+ const { adapter, config, resolver, root } = ctx
223
101
 
224
- // Add url property with template literal type
225
- dataRequestProperties.push(
226
- factory.createPropertySignature({
227
- name: 'url',
228
- type: createUrlTemplateType(operation.path),
229
- }),
230
- )
102
+ const mode = ctx.getMode(output)
231
103
 
232
- const dataRequestNode = factory.createTypeAliasDeclaration({
233
- name,
234
- type: factory.createTypeLiteralNode(dataRequestProperties),
235
- modifiers: [factory.modifiers.export],
236
- })
104
+ const params = ast.caseParams(node.parameters, paramsCasing)
237
105
 
238
- results.push(safePrint(dataRequestNode))
106
+ const meta = {
107
+ file: resolver.resolveFile({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
108
+ } as const
239
109
 
240
- return results.join('\n\n')
241
- }
110
+ // Build a set of schema names that are enums so the ref handler and getImports
111
+ // callback can use the suffixed type name (e.g. `StatusKey`) for those refs.
112
+ const enumSchemaNames = new Set((adapter.inputNode?.schemas ?? []).filter((s) => ast.narrowSchema(s, ast.schemaTypes.enum) && s.name).map((s) => s.name!))
242
113
 
243
- function printResponseSchema({
244
- baseName,
245
- schemas,
246
- driver,
247
- unknownType,
248
- }: {
249
- baseName: string
250
- schemas: OperationSchemas
251
- driver: PluginDriver
252
- unknownType: PluginTs['resolvedOptions']['unknownType']
253
- }): string {
254
- const results: string[] = []
255
-
256
- const name = driver.resolveName({
257
- name: `${baseName} ResponseData`,
258
- pluginName: pluginTsName,
259
- type: 'type',
260
- })
261
-
262
- // Generate Responses type (mapping status codes to response types)
263
- if (schemas.responses && schemas.responses.length > 0) {
264
- const responsesProperties: ts.PropertySignature[] = schemas.responses.map((res) => {
265
- const identifier = driver.resolveName({
266
- name: res.name,
267
- pluginName: pluginTsName,
268
- type: 'type',
269
- })
114
+ function resolveImportName(schemaName: string): string {
115
+ if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && enumTypeSuffix && enumSchemaNames.has(schemaName)) {
116
+ return resolver.resolveEnumKeyName({ name: schemaName }, enumTypeSuffix)
117
+ }
118
+ return resolver.resolveTypeName(schemaName)
119
+ }
270
120
 
271
- return factory.createPropertySignature({
272
- name: res.statusCode?.toString() ?? 'default',
273
- type: factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined),
121
+ function renderSchemaType({ schema, name, keysToOmit }: { schema: ast.SchemaNode | null; name: string; keysToOmit?: Array<string> }) {
122
+ if (!schema) return null
123
+
124
+ const imports = adapter.getImports(schema, (schemaName) => ({
125
+ name: resolveImportName(schemaName),
126
+ path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
127
+ }))
128
+
129
+ const schemaPrinter = printerTs({
130
+ optionalType,
131
+ arrayType,
132
+ enumType,
133
+ enumTypeSuffix,
134
+ name,
135
+ syntaxType,
136
+ description: schema.description,
137
+ keysToOmit,
138
+ resolver,
139
+ enumSchemaNames,
140
+ nodes: printer?.nodes,
274
141
  })
275
- })
276
-
277
- const responsesNode = factory.createTypeAliasDeclaration({
278
- name: `${baseName}Responses`,
279
- type: factory.createTypeLiteralNode(responsesProperties),
280
- modifiers: [factory.modifiers.export],
281
- })
282
-
283
- results.push(safePrint(responsesNode))
284
-
285
- // Generate Response type (union via indexed access)
286
- const responseNode = factory.createTypeAliasDeclaration({
287
- name,
288
- type: factory.createIndexedAccessTypeNode(
289
- factory.createTypeReferenceNode(factory.createIdentifier(`${baseName}Responses`), undefined),
290
- factory.createTypeOperatorNode(
291
- ts.SyntaxKind.KeyOfKeyword,
292
- factory.createTypeReferenceNode(factory.createIdentifier(`${baseName}Responses`), undefined),
293
- ),
294
- ),
295
- modifiers: [factory.modifiers.export],
296
- })
297
-
298
- results.push(safePrint(responseNode))
299
- } else {
300
- const responseNode = factory.createTypeAliasDeclaration({
301
- name,
302
- modifiers: [factory.modifiers.export],
303
- type: getUnknownType(unknownType),
304
- })
305
-
306
- results.push(safePrint(responseNode))
307
- }
308
-
309
- return results.join('\n\n')
310
- }
311
-
312
- export const typeGenerator = createReactGenerator<PluginTs>({
313
- name: 'typescript',
314
- Operation({ operation, generator, plugin }) {
315
- const {
316
- options,
317
- options: { enumType, enumKeyCasing, syntaxType, optionalType, arrayType, unknownType, paramsCasing },
318
- } = plugin
319
-
320
- const mode = useMode()
321
- const driver = usePluginDriver()
322
-
323
- const oas = useOas()
324
- const { getSchemas, getFile, getName, getGroup } = useOperationManager(generator)
325
- const schemaManager = useSchemaManager()
326
-
327
- const name = getName(operation, { type: 'type', pluginName: pluginTsName })
328
-
329
- const file = getFile(operation)
330
- const schemas = getSchemas(operation)
331
- const schemaGenerator = new SchemaGenerator(options, {
332
- fabric: generator.context.fabric,
333
- oas,
334
- events: generator.context.events,
335
- plugin,
336
- driver,
337
- mode,
338
- override: options.override,
339
- })
340
-
341
- const operationSchemas = [schemas.pathParams, schemas.queryParams, schemas.headerParams, schemas.statusCodes, schemas.request, schemas.response]
342
- .flat()
343
- .filter(Boolean)
344
-
345
- const mapOperationSchema = ({ name, schema, description, keysToOmit, ...options }: OperationSchemaType) => {
346
- // Apply paramsCasing transformation to pathParams, queryParams, and headerParams (not response)
347
- const shouldTransform = paramsCasing && isParameterSchema(name)
348
- const transformedSchema = shouldTransform ? applyParamsCasing(schema, paramsCasing) : schema
349
-
350
- const tree = schemaGenerator.parse({ schema: transformedSchema, name, parentName: null })
351
- const imports = getImports(tree)
352
- const group = options.operation ? getGroup(options.operation) : undefined
353
-
354
- const type = {
355
- name: schemaManager.getName(name, { type: 'type' }),
356
- typedName: schemaManager.getName(name, { type: 'type' }),
357
- file: schemaManager.getFile(options.operationName || name, { group }),
358
- }
359
142
 
360
143
  return (
361
144
  <>
362
145
  {mode === 'split' &&
363
146
  imports.map((imp) => (
364
- <File.Import key={[name, imp.name, imp.path, imp.isTypeOnly].join('-')} root={file.path} path={imp.path} name={imp.name} isTypeOnly />
147
+ <File.Import key={[name, imp.path, imp.isTypeOnly].join('-')} root={meta.file.path} path={imp.path} name={imp.name} isTypeOnly />
365
148
  ))}
366
149
  <Type
367
- name={type.name}
368
- typedName={type.typedName}
369
- description={description}
370
- tree={tree}
371
- schema={transformedSchema}
150
+ name={name}
151
+ node={schema}
372
152
  enumType={enumType}
153
+ enumTypeSuffix={enumTypeSuffix}
373
154
  enumKeyCasing={enumKeyCasing}
374
- optionalType={optionalType}
375
- arrayType={arrayType}
376
- keysToOmit={keysToOmit}
377
- syntaxType={syntaxType}
155
+ resolver={resolver}
156
+ printer={schemaPrinter}
378
157
  />
379
158
  </>
380
159
  )
381
160
  }
382
161
 
383
- const responseName = schemaManager.getName(schemas.response.name, {
384
- type: 'type',
385
- })
162
+ const paramTypes = params.map((param) =>
163
+ renderSchemaType({
164
+ schema: param.schema,
165
+ name: resolver.resolveParamName(node, param),
166
+ }),
167
+ )
168
+
169
+ const requestBodyContent = node.requestBody?.content ?? []
170
+
171
+ function buildRequestType() {
172
+ if (requestBodyContent.length === 0) return null
173
+ if (requestBodyContent.length === 1) {
174
+ const entry = requestBodyContent[0]!
175
+ if (!entry.schema) return null
176
+ return renderSchemaType({
177
+ schema: {
178
+ ...entry.schema,
179
+ description: node.requestBody!.description ?? entry.schema.description,
180
+ },
181
+ name: resolver.resolveDataName(node),
182
+ keysToOmit: entry.keysToOmit,
183
+ })
184
+ }
185
+ // Multiple content types — generate individual types + union alias
186
+ const dataName = resolver.resolveDataName(node)
187
+ const usedNames = new Set<string>()
188
+ const individualItems = requestBodyContent
189
+ .filter((entry) => entry.schema)
190
+ .map((entry) => {
191
+ const baseSuffix = getContentTypeSuffix(entry.contentType)
192
+ let individualName = getPerContentTypeName(dataName, baseSuffix)
193
+ let counter = 2
194
+ while (usedNames.has(individualName)) {
195
+ individualName = getPerContentTypeName(dataName, `${baseSuffix}${counter++}`)
196
+ }
197
+ usedNames.add(individualName)
198
+ return {
199
+ name: individualName,
200
+ rendered: renderSchemaType({
201
+ schema: {
202
+ ...entry.schema!,
203
+ description: node.requestBody!.description ?? entry.schema!.description,
204
+ },
205
+ name: individualName,
206
+ keysToOmit: entry.keysToOmit,
207
+ }),
208
+ }
209
+ })
210
+ const unionSchema = ast.createSchema({
211
+ type: 'union',
212
+ members: individualItems.map((item) => ast.createSchema({ type: 'ref', name: item.name })),
213
+ })
214
+ const unionType = renderSchemaType({ schema: unionSchema, name: dataName })
215
+ return (
216
+ <>
217
+ {individualItems.map((item) => item.rendered)}
218
+ {unionType}
219
+ </>
220
+ )
221
+ }
386
222
 
387
- const combinedSchemaName = operation.method === 'get' ? `${name}Query` : `${name}Mutation`
223
+ const requestType = buildRequestType()
388
224
 
389
- return (
390
- <File
391
- baseName={file.baseName}
392
- path={file.path}
393
- meta={file.meta}
394
- banner={getBanner({ oas, output: plugin.options.output, config: driver.config })}
395
- footer={getFooter({ oas, output: plugin.options.output })}
396
- >
397
- {operationSchemas.map(mapOperationSchema)}
398
-
399
- {generator.context.UNSTABLE_NAMING ? (
400
- <>
401
- <File.Source name={`${name}Request`} isExportable isIndexable isTypeOnly>
402
- {printRequestSchema({ baseName: name, operation, schemas, driver })}
403
- </File.Source>
404
- <File.Source name={responseName} isExportable isIndexable isTypeOnly>
405
- {printResponseSchema({ baseName: name, schemas, driver, unknownType })}
406
- </File.Source>
407
- </>
408
- ) : (
409
- <File.Source name={combinedSchemaName} isExportable isIndexable isTypeOnly>
410
- {printCombinedSchema({ name: combinedSchemaName, schemas, driver })}
411
- </File.Source>
412
- )}
413
- </File>
225
+ const responseTypes = node.responses.map((res) =>
226
+ renderSchemaType({
227
+ schema: res.schema,
228
+ name: resolver.resolveResponseStatusName(node, res.statusCode),
229
+ keysToOmit: res.keysToOmit,
230
+ }),
414
231
  )
415
- },
416
- Schema({ schema, plugin }) {
417
- const {
418
- options: { enumType, enumKeyCasing, syntaxType, optionalType, arrayType, output },
419
- } = plugin
420
- const mode = useMode()
421
232
 
422
- const oas = useOas()
423
- const driver = usePluginDriver()
233
+ const dataType = renderSchemaType({
234
+ schema: buildData({ ...node, parameters: params }, { resolver }),
235
+ name: resolver.resolveRequestConfigName(node),
236
+ })
237
+
238
+ const responsesType = renderSchemaType({
239
+ schema: buildResponses(node, { resolver }),
240
+ name: resolver.resolveResponsesName(node),
241
+ })
424
242
 
425
- const { getName, getFile } = useSchemaManager()
426
- const imports = getImports(schema.tree)
427
- const schemaFromTree = schema.tree.find((item) => item.keyword === schemaKeywords.schema)
243
+ function buildResponseType() {
244
+ if (!node.responses.some((res) => res.schema)) {
245
+ return null
246
+ }
428
247
 
429
- let typedName = getName(schema.name, { type: 'type' })
248
+ const responseName = resolver.resolveResponseName(node)
249
+
250
+ const responsesWithSchema = node.responses.filter((res) => res.schema)
251
+ const importedNames = new Set(
252
+ responsesWithSchema.flatMap((res) =>
253
+ res.schema
254
+ ? adapter
255
+ .getImports(res.schema, (schemaName) => ({
256
+ name: resolveImportName(schemaName),
257
+ path: '',
258
+ }))
259
+ .flatMap((imp) => (Array.isArray(imp.name) ? imp.name : [imp.name]))
260
+ : [],
261
+ ),
262
+ )
430
263
 
431
- if (['asConst', 'asPascalConst'].includes(enumType) && schemaFromTree && isKeyword(schemaFromTree, schemaKeywords.enum)) {
432
- typedName = typedName += 'Key' //Suffix for avoiding collisions (https://github.com/kubb-labs/kubb/issues/1873)
433
- }
264
+ if (importedNames.has(responseName)) {
265
+ return null
266
+ }
434
267
 
435
- const type = {
436
- name: getName(schema.name, { type: 'function' }),
437
- typedName,
438
- file: getFile(schema.name),
268
+ return renderSchemaType({
269
+ schema: {
270
+ ...buildResponseUnion(node, { resolver })!,
271
+ description: 'Union of all possible responses',
272
+ },
273
+ name: responseName,
274
+ })
439
275
  }
440
276
 
277
+ const responseType = buildResponseType()
278
+
441
279
  return (
442
280
  <File
443
- baseName={type.file.baseName}
444
- path={type.file.path}
445
- meta={type.file.meta}
446
- banner={getBanner({ oas, output, config: driver.config })}
447
- footer={getFooter({ oas, output })}
281
+ baseName={meta.file.baseName}
282
+ path={meta.file.path}
283
+ meta={meta.file.meta}
284
+ banner={resolver.resolveBanner(adapter.inputNode, { output, config })}
285
+ footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
448
286
  >
449
- {mode === 'split' &&
450
- imports.map((imp) => (
451
- <File.Import key={[schema.name, imp.path, imp.isTypeOnly].join('-')} root={type.file.path} path={imp.path} name={imp.name} isTypeOnly />
452
- ))}
453
- <Type
454
- name={type.name}
455
- typedName={type.typedName}
456
- description={schema.value.description}
457
- tree={schema.tree}
458
- schema={schema.value}
459
- enumType={enumType}
460
- enumKeyCasing={enumKeyCasing}
461
- optionalType={optionalType}
462
- arrayType={arrayType}
463
- syntaxType={syntaxType}
464
- />
287
+ {paramTypes}
288
+ {responseTypes}
289
+ {requestType}
290
+ {dataType}
291
+ {responsesType}
292
+ {responseType}
465
293
  </File>
466
294
  )
467
295
  },