@kubb/plugin-ts 4.13.1 → 4.14.1

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 (45) hide show
  1. package/dist/{components-x14CeHxX.js → components-BE9rQGox.js} +74 -58
  2. package/dist/components-BE9rQGox.js.map +1 -0
  3. package/dist/{components-BkxV2jhh.cjs → components-CGcs8968.cjs} +103 -63
  4. package/dist/components-CGcs8968.cjs.map +1 -0
  5. package/dist/components.cjs +1 -2
  6. package/dist/components.d.cts +4 -17
  7. package/dist/components.d.ts +4 -17
  8. package/dist/components.js +2 -2
  9. package/dist/generators.cjs +1 -1
  10. package/dist/generators.d.cts +1 -1
  11. package/dist/generators.d.ts +1 -1
  12. package/dist/generators.js +1 -1
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.d.cts +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/{plugin-BM1VkXZS.cjs → plugin-B96TNDf4.cjs} +174 -21
  18. package/dist/plugin-B96TNDf4.cjs.map +1 -0
  19. package/dist/{plugin-BiVCDKei.js → plugin-DXyNbr_u.js} +175 -23
  20. package/dist/plugin-DXyNbr_u.js.map +1 -0
  21. package/dist/{types-WHo75HZq.d.cts → types-CKtzgWEC.d.cts} +22 -6
  22. package/dist/{types-De3dRAE2.d.ts → types-CnQREd_1.d.ts} +22 -6
  23. package/package.json +4 -4
  24. package/src/components/Type.tsx +33 -22
  25. package/src/components/index.ts +0 -1
  26. package/src/factory.ts +79 -5
  27. package/src/generators/__snapshots__/createPet.ts +1 -1
  28. package/src/generators/__snapshots__/createPetWithEmptySchemaTypeUnknown.ts +1 -1
  29. package/src/generators/__snapshots__/createPetWithEmptySchemaTypeVoid.ts +1 -1
  30. package/src/generators/__snapshots__/createPetWithUnknownTypeUnknown.ts +1 -1
  31. package/src/generators/__snapshots__/createPetWithUnknownTypeVoid.ts +1 -1
  32. package/src/generators/__snapshots__/deletePet.ts +1 -1
  33. package/src/generators/__snapshots__/enumNamesInlineLiteral.ts +6 -0
  34. package/src/generators/__snapshots__/getPets.ts +1 -1
  35. package/src/generators/__snapshots__/showPetById.ts +1 -1
  36. package/src/generators/__snapshots__/systemsWithExplodeForm.ts +1 -1
  37. package/src/generators/typeGenerator.tsx +232 -8
  38. package/src/parser.ts +28 -23
  39. package/src/plugin.ts +4 -0
  40. package/src/types.ts +16 -2
  41. package/dist/components-BkxV2jhh.cjs.map +0 -1
  42. package/dist/components-x14CeHxX.js.map +0 -1
  43. package/dist/plugin-BM1VkXZS.cjs.map +0 -1
  44. package/dist/plugin-BiVCDKei.js.map +0 -1
  45. package/src/components/OasType.tsx +0 -28
@@ -15,6 +15,7 @@ type Props = {
15
15
  schema: SchemaObject
16
16
  tree: Array<Schema>
17
17
  optionalType: PluginTs['resolvedOptions']['optionalType']
18
+ arrayType: PluginTs['resolvedOptions']['arrayType']
18
19
  enumType: PluginTs['resolvedOptions']['enumType']
19
20
  mapper: PluginTs['resolvedOptions']['mapper']
20
21
  syntaxType: PluginTs['resolvedOptions']['syntaxType']
@@ -22,7 +23,7 @@ type Props = {
22
23
  keysToOmit?: string[]
23
24
  }
24
25
 
25
- export function Type({ name, typedName, tree, keysToOmit, schema, optionalType, syntaxType, enumType, mapper, description }: Props): KubbNode {
26
+ export function Type({ name, typedName, tree, keysToOmit, schema, optionalType, arrayType, syntaxType, enumType, mapper, description }: Props): KubbNode {
26
27
  const typeNodes: ts.Node[] = []
27
28
 
28
29
  if (!tree.length) {
@@ -39,6 +40,7 @@ export function Type({ name, typedName, tree, keysToOmit, schema, optionalType,
39
40
  { name, schema, parent: undefined, current, siblings },
40
41
  {
41
42
  optionalType,
43
+ arrayType,
42
44
  enumType,
43
45
  mapper,
44
46
  },
@@ -59,7 +61,11 @@ export function Type({ name, typedName, tree, keysToOmit, schema, optionalType,
59
61
  type = factory.createTypeReferenceNode(typeNameWithKey)
60
62
 
61
63
  if (schema.type === 'array') {
62
- type = factory.createArrayTypeNode(type)
64
+ if (arrayType === 'generic') {
65
+ type = factory.createTypeReferenceNode(factory.createIdentifier('Array'), [type])
66
+ } else {
67
+ type = factory.createArrayTypeNode(type)
68
+ }
63
69
  }
64
70
  }
65
71
  }
@@ -135,28 +141,33 @@ export function Type({ name, typedName, tree, keysToOmit, schema, optionalType,
135
141
  }
136
142
  })
137
143
 
144
+ // Skip enum exports when using inlineLiteral
145
+ const shouldExportEnums = enumType !== 'inlineLiteral'
146
+ const shouldExportType = enumType === 'inlineLiteral' || enums.every((item) => item.typeName !== name)
147
+
138
148
  return (
139
149
  <>
140
- {enums.map(({ name, nameNode, typeName, typeNode }) => (
141
- <>
142
- {nameNode && (
143
- <File.Source name={name} isExportable isIndexable>
144
- {safePrint(nameNode)}
145
- </File.Source>
146
- )}
147
- {
148
- <File.Source
149
- name={typeName}
150
- isIndexable
151
- isExportable={['enum', 'asConst', 'constEnum', 'literal', undefined].includes(enumType)}
152
- isTypeOnly={['asConst', 'literal', undefined].includes(enumType)}
153
- >
154
- {safePrint(typeNode)}
155
- </File.Source>
156
- }
157
- </>
158
- ))}
159
- {enums.every((item) => item.typeName !== name) && (
150
+ {shouldExportEnums &&
151
+ enums.map(({ name, nameNode, typeName, typeNode }) => (
152
+ <>
153
+ {nameNode && (
154
+ <File.Source name={name} isExportable isIndexable>
155
+ {safePrint(nameNode)}
156
+ </File.Source>
157
+ )}
158
+ {
159
+ <File.Source
160
+ name={typeName}
161
+ isIndexable
162
+ isExportable={['enum', 'asConst', 'constEnum', 'literal', undefined].includes(enumType)}
163
+ isTypeOnly={['asConst', 'literal', undefined].includes(enumType)}
164
+ >
165
+ {safePrint(typeNode)}
166
+ </File.Source>
167
+ }
168
+ </>
169
+ ))}
170
+ {shouldExportType && (
160
171
  <File.Source name={typedName} isTypeOnly isExportable isIndexable>
161
172
  {safePrint(...typeNodes)}
162
173
  </File.Source>
@@ -1,2 +1 @@
1
- export { OasType } from './OasType.tsx'
2
1
  export { Type } from './Type.tsx'
package/src/factory.ts CHANGED
@@ -17,6 +17,16 @@ export const syntaxKind = {
17
17
  union: SyntaxKind.UnionType as 192,
18
18
  } as const
19
19
 
20
+ export function getUnknownType(unknownType: 'any' | 'unknown' | 'void' | undefined) {
21
+ if (unknownType === 'any') {
22
+ return keywordTypeNodes.any
23
+ }
24
+ if (unknownType === 'void') {
25
+ return keywordTypeNodes.void
26
+ }
27
+
28
+ return keywordTypeNodes.unknown
29
+ }
20
30
  function isValidIdentifier(str: string): boolean {
21
31
  if (!str.length || str.trim() !== str) {
22
32
  return false
@@ -86,16 +96,29 @@ export function createTupleDeclaration({ nodes, withParentheses }: { nodes: Arra
86
96
  return node
87
97
  }
88
98
 
89
- export function createArrayDeclaration({ nodes }: { nodes: Array<ts.TypeNode> }): ts.TypeNode | null {
99
+ export function createArrayDeclaration({ nodes, arrayType = 'array' }: { nodes: Array<ts.TypeNode>; arrayType?: 'array' | 'generic' }): ts.TypeNode | null {
90
100
  if (!nodes.length) {
91
101
  return factory.createTupleTypeNode([])
92
102
  }
93
103
 
94
104
  if (nodes.length === 1) {
95
- return factory.createArrayTypeNode(nodes.at(0)!)
105
+ const node = nodes[0]
106
+ if (!node) {
107
+ return null
108
+ }
109
+ if (arrayType === 'generic') {
110
+ return factory.createTypeReferenceNode(factory.createIdentifier('Array'), [node])
111
+ }
112
+ return factory.createArrayTypeNode(node)
96
113
  }
97
114
 
98
- return factory.createExpressionWithTypeArguments(factory.createIdentifier('Array'), [factory.createUnionTypeNode(nodes)])
115
+ // For union types (multiple nodes), respect arrayType preference
116
+ const unionType = factory.createUnionTypeNode(nodes)
117
+ if (arrayType === 'generic') {
118
+ return factory.createTypeReferenceNode(factory.createIdentifier('Array'), [unionType])
119
+ }
120
+ // For array syntax with unions, we need parentheses: (string | number)[]
121
+ return factory.createArrayTypeNode(factory.createParenthesizedType(unionType))
99
122
  }
100
123
 
101
124
  /**
@@ -408,7 +431,7 @@ export function createEnumDeclaration({
408
431
  * - `literal`: literal union type
409
432
  * @default `'enum'`
410
433
  */
411
- type?: 'enum' | 'asConst' | 'asPascalConst' | 'constEnum' | 'literal'
434
+ type?: 'enum' | 'asConst' | 'asPascalConst' | 'constEnum' | 'literal' | 'inlineLiteral'
412
435
  /**
413
436
  * Enum name in camelCase.
414
437
  */
@@ -419,7 +442,7 @@ export function createEnumDeclaration({
419
442
  typeName: string
420
443
  enums: [key: string | number, value: string | number | boolean][]
421
444
  }): [name: ts.Node | undefined, type: ts.Node] {
422
- if (type === 'literal') {
445
+ if (type === 'literal' || type === 'inlineLiteral') {
423
446
  return [
424
447
  undefined,
425
448
  factory.createTypeAliasDeclaration(
@@ -572,8 +595,56 @@ export const keywordTypeNodes = {
572
595
  boolean: factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword),
573
596
  undefined: factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
574
597
  null: factory.createLiteralTypeNode(factory.createToken(ts.SyntaxKind.NullKeyword)),
598
+ never: factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword),
575
599
  } as const
576
600
 
601
+ /**
602
+ * Converts a path like '/pet/{petId}/uploadImage' to a template literal type
603
+ * like `/pet/${string}/uploadImage`
604
+ */
605
+ export function createUrlTemplateType(path: string): ts.TypeNode {
606
+ // If no parameters, return literal string type
607
+ if (!path.includes('{')) {
608
+ return factory.createLiteralTypeNode(factory.createStringLiteral(path))
609
+ }
610
+
611
+ // Split path by parameter placeholders, e.g. '/pet/{petId}/upload' -> ['/pet/', 'petId', '/upload']
612
+ const segments = path.split(/(\{[^}]+\})/)
613
+
614
+ // Separate static parts from parameter placeholders
615
+ const parts: string[] = []
616
+ const parameterIndices: number[] = []
617
+
618
+ segments.forEach((segment) => {
619
+ if (segment.startsWith('{') && segment.endsWith('}')) {
620
+ // This is a parameter placeholder
621
+ parameterIndices.push(parts.length)
622
+ parts.push(segment) // Will be replaced with ${string}
623
+ } else if (segment) {
624
+ // This is a static part
625
+ parts.push(segment)
626
+ }
627
+ })
628
+
629
+ // Build template literal type
630
+ // Template literal structure: head + templateSpans[]
631
+ // For '/pet/{petId}/upload': head = '/pet/', spans = [{ type: string, literal: '/upload' }]
632
+
633
+ const head = ts.factory.createTemplateHead(parts[0] || '')
634
+ const templateSpans: ts.TemplateLiteralTypeSpan[] = []
635
+
636
+ parameterIndices.forEach((paramIndex, i) => {
637
+ const isLast = i === parameterIndices.length - 1
638
+ const nextPart = parts[paramIndex + 1] || ''
639
+
640
+ const literal = isLast ? ts.factory.createTemplateTail(nextPart) : ts.factory.createTemplateMiddle(nextPart)
641
+
642
+ templateSpans.push(ts.factory.createTemplateLiteralTypeSpan(keywordTypeNodes.string, literal))
643
+ })
644
+
645
+ return ts.factory.createTemplateLiteralType(head, templateSpans)
646
+ }
647
+
577
648
  export const createTypeLiteralNode = factory.createTypeLiteralNode
578
649
 
579
650
  export const createTypeReferenceNode = factory.createTypeReferenceNode
@@ -581,6 +652,7 @@ export const createNumericLiteral = factory.createNumericLiteral
581
652
  export const createStringLiteral = factory.createStringLiteral
582
653
 
583
654
  export const createArrayTypeNode = factory.createArrayTypeNode
655
+ export const createParenthesizedType = factory.createParenthesizedType
584
656
 
585
657
  export const createLiteralTypeNode = factory.createLiteralTypeNode
586
658
  export const createNull = factory.createNull
@@ -591,3 +663,5 @@ export const createTupleTypeNode = factory.createTupleTypeNode
591
663
  export const createRestTypeNode = factory.createRestTypeNode
592
664
  export const createTrue = factory.createTrue
593
665
  export const createFalse = factory.createFalse
666
+ export const createIndexedAccessTypeNode = factory.createIndexedAccessTypeNode
667
+ export const createTypeOperatorNode = factory.createTypeOperatorNode
@@ -40,7 +40,7 @@ export type CreatePetsMutationRequest = {
40
40
 
41
41
  export type CreatePetsMutationResponse = createPets201 | createPets202
42
42
 
43
- export type createPetsMutation = {
43
+ export type CreatePetsMutation = {
44
44
  Response: createPets201 | createPets202
45
45
  Request: createPetsMutationRequest
46
46
  Errors: any
@@ -40,7 +40,7 @@ export type CreatePetsMutationRequest = {
40
40
 
41
41
  export type CreatePetsMutationResponse = createPets201 | createPets202
42
42
 
43
- export type createPetsMutation = {
43
+ export type CreatePetsMutation = {
44
44
  Response: createPets201 | createPets202
45
45
  Request: createPetsMutationRequest
46
46
  Errors: any
@@ -40,7 +40,7 @@ export type CreatePetsMutationRequest = {
40
40
 
41
41
  export type CreatePetsMutationResponse = createPets201 | createPets202
42
42
 
43
- export type createPetsMutation = {
43
+ export type CreatePetsMutation = {
44
44
  Response: createPets201 | createPets202
45
45
  Request: createPetsMutationRequest
46
46
  Errors: any
@@ -40,7 +40,7 @@ export type CreatePetsMutationRequest = {
40
40
 
41
41
  export type CreatePetsMutationResponse = createPets201 | createPets202
42
42
 
43
- export type createPetsMutation = {
43
+ export type CreatePetsMutation = {
44
44
  Response: createPets201 | createPets202
45
45
  Request: createPetsMutationRequest
46
46
  Errors: any
@@ -40,7 +40,7 @@ export type CreatePetsMutationRequest = {
40
40
 
41
41
  export type CreatePetsMutationResponse = createPets201 | createPets202
42
42
 
43
- export type createPetsMutation = {
43
+ export type CreatePetsMutation = {
44
44
  Response: createPets201 | createPets202
45
45
  Request: createPetsMutationRequest
46
46
  Errors: any
@@ -5,7 +5,7 @@
5
5
 
6
6
  export type DeletePetsPetidMutationResponse = any
7
7
 
8
- export type deletePetsPetidMutation = {
8
+ export type DeletePetsPetidMutation = {
9
9
  Response: any
10
10
  Errors: any
11
11
  }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Generated by Kubb (https://kubb.dev/).
3
+ * Do not edit manually.
4
+ */
5
+
6
+ export type enumNamesType = 0 | 1
@@ -23,7 +23,7 @@ export type ListPetsError = error
23
23
 
24
24
  export type ListPetsQueryResponse = listPets200
25
25
 
26
- export type listPetsQuery = {
26
+ export type ListPetsQuery = {
27
27
  Response: listPets200
28
28
  QueryParams: listPetsQueryParams
29
29
  Errors: any
@@ -28,7 +28,7 @@ export type ShowPetByIdError = error
28
28
 
29
29
  export type ShowPetByIdQueryResponse = showPetById200
30
30
 
31
- export type showPetByIdQuery = {
31
+ export type ShowPetByIdQuery = {
32
32
  Response: showPetById200
33
33
  PathParams: showPetByIdPathParams
34
34
  Errors: any
@@ -17,7 +17,7 @@ export type Systems200 = object
17
17
 
18
18
  export type SystemsQueryResponse = systems200
19
19
 
20
- export type systemsQuery = {
20
+ export type SystemsQuery = {
21
21
  Response: systems200
22
22
  QueryParams: systemsQueryParams
23
23
  Errors: any
@@ -2,14 +2,16 @@ import type { PluginManager } from '@kubb/core'
2
2
  import { useMode, usePluginManager } from '@kubb/core/hooks'
3
3
  import transformers from '@kubb/core/transformers'
4
4
  import { safePrint } from '@kubb/fabric-core/parsers/typescript'
5
+ import type { Operation } from '@kubb/oas'
5
6
  import { isKeyword, type OperationSchemas, type OperationSchema as OperationSchemaType, SchemaGenerator, schemaKeywords } from '@kubb/plugin-oas'
6
7
  import { createReactGenerator } from '@kubb/plugin-oas/generators'
7
8
  import { useOas, useOperationManager, useSchemaManager } from '@kubb/plugin-oas/hooks'
8
9
  import { getBanner, getFooter } from '@kubb/plugin-oas/utils'
9
10
  import { File } from '@kubb/react-fabric'
10
- import type ts from 'typescript'
11
+ import ts from 'typescript'
11
12
  import { Type } from '../components'
12
13
  import * as factory from '../factory.ts'
14
+ import { createUrlTemplateType, getUnknownType, keywordTypeNodes } from '../factory.ts'
13
15
  import { pluginTsName } from '../plugin.ts'
14
16
  import type { PluginTs } from '../types'
15
17
 
@@ -103,12 +105,216 @@ function printCombinedSchema({ name, schemas, pluginManager }: { name: string; s
103
105
  return safePrint(namespaceNode)
104
106
  }
105
107
 
108
+ function printRequestSchema({
109
+ baseName,
110
+ operation,
111
+ schemas,
112
+ pluginManager,
113
+ }: {
114
+ baseName: string
115
+ operation: Operation
116
+ schemas: OperationSchemas
117
+ pluginManager: PluginManager
118
+ }): string {
119
+ const name = pluginManager.resolveName({
120
+ name: `${baseName} Request`,
121
+ pluginKey: [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 = pluginManager.resolveName({
132
+ name: schemas.request.name,
133
+ pluginKey: [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
+ }
152
+
153
+ // Add pathParams property
154
+ if (schemas.pathParams) {
155
+ const identifier = pluginManager.resolveName({
156
+ name: schemas.pathParams.name,
157
+ pluginKey: [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
+ }
175
+
176
+ // Add queryParams property
177
+ if (schemas.queryParams) {
178
+ const identifier = pluginManager.resolveName({
179
+ name: schemas.queryParams.name,
180
+ pluginKey: [pluginTsName],
181
+ type: 'type',
182
+ })
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
+
200
+ // Add headerParams property
201
+ if (schemas.headerParams) {
202
+ const identifier = pluginManager.resolveName({
203
+ name: schemas.headerParams.name,
204
+ pluginKey: [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
+ }),
221
+ )
222
+ }
223
+
224
+ // Add url property with template literal type
225
+ dataRequestProperties.push(
226
+ factory.createPropertySignature({
227
+ name: 'url',
228
+ type: createUrlTemplateType(operation.path),
229
+ }),
230
+ )
231
+
232
+ const dataRequestNode = factory.createTypeAliasDeclaration({
233
+ name,
234
+ type: factory.createTypeLiteralNode(dataRequestProperties),
235
+ modifiers: [factory.modifiers.export],
236
+ })
237
+
238
+ results.push(safePrint(dataRequestNode))
239
+
240
+ return results.join('\n\n')
241
+ }
242
+
243
+ function printResponseSchema({
244
+ baseName,
245
+ schemas,
246
+ pluginManager,
247
+ unknownType,
248
+ }: {
249
+ baseName: string
250
+ schemas: OperationSchemas
251
+ pluginManager: PluginManager
252
+ unknownType: PluginTs['resolvedOptions']['unknownType']
253
+ }): string {
254
+ const results: string[] = []
255
+
256
+ const name = pluginManager.resolveName({
257
+ name: `${baseName} ResponseData`,
258
+ pluginKey: [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 = pluginManager.resolveName({
266
+ name: res.name,
267
+ pluginKey: [pluginTsName],
268
+ type: 'type',
269
+ })
270
+
271
+ return factory.createPropertySignature({
272
+ name: res.statusCode?.toString() ?? 'default',
273
+ type: factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined),
274
+ })
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
+
106
312
  export const typeGenerator = createReactGenerator<PluginTs>({
107
313
  name: 'typescript',
108
314
  Operation({ operation, generator, plugin }) {
109
315
  const {
110
316
  options,
111
- options: { mapper, enumType, syntaxType, optionalType },
317
+ options: { mapper, enumType, syntaxType, optionalType, arrayType, unknownType },
112
318
  } = plugin
113
319
 
114
320
  const mode = useMode()
@@ -118,10 +324,10 @@ export const typeGenerator = createReactGenerator<PluginTs>({
118
324
  const { getSchemas, getFile, getName, getGroup } = useOperationManager(generator)
119
325
  const schemaManager = useSchemaManager()
120
326
 
327
+ const name = getName(operation, { type: 'type', pluginKey: [pluginTsName] })
328
+
121
329
  const file = getFile(operation)
122
330
  const schemas = getSchemas(operation)
123
- const type = getName(operation, { type: 'function', pluginKey: [pluginTsName] })
124
- const combinedSchemaName = operation.method === 'get' ? `${type}Query` : `${type}Mutation`
125
331
  const schemaGenerator = new SchemaGenerator(options, {
126
332
  fabric: generator.context.fabric,
127
333
  oas,
@@ -162,6 +368,7 @@ export const typeGenerator = createReactGenerator<PluginTs>({
162
368
  mapper={mapper}
163
369
  enumType={enumType}
164
370
  optionalType={optionalType}
371
+ arrayType={arrayType}
165
372
  keysToOmit={keysToOmit}
166
373
  syntaxType={syntaxType}
167
374
  />
@@ -169,6 +376,11 @@ export const typeGenerator = createReactGenerator<PluginTs>({
169
376
  )
170
377
  }
171
378
 
379
+ const responseName = schemaManager.getName(schemas.response.name, {
380
+ type: 'type',
381
+ })
382
+ const combinedSchemaName = operation.method === 'get' ? `${name}Query` : `${name}Mutation`
383
+
172
384
  return (
173
385
  <File
174
386
  baseName={file.baseName}
@@ -179,15 +391,26 @@ export const typeGenerator = createReactGenerator<PluginTs>({
179
391
  >
180
392
  {operationSchemas.map(mapOperationSchema)}
181
393
 
182
- <File.Source name={combinedSchemaName} isExportable isIndexable isTypeOnly>
183
- {printCombinedSchema({ name: combinedSchemaName, schemas, pluginManager })}
184
- </File.Source>
394
+ {generator.context.UNSTABLE_NAMING ? (
395
+ <>
396
+ <File.Source name={`${name}Request`} isExportable isIndexable isTypeOnly>
397
+ {printRequestSchema({ baseName: name, operation, schemas, pluginManager })}
398
+ </File.Source>
399
+ <File.Source name={responseName} isExportable isIndexable isTypeOnly>
400
+ {printResponseSchema({ baseName: name, schemas, pluginManager, unknownType })}
401
+ </File.Source>
402
+ </>
403
+ ) : (
404
+ <File.Source name={combinedSchemaName} isExportable isIndexable isTypeOnly>
405
+ {printCombinedSchema({ name: combinedSchemaName, schemas, pluginManager })}
406
+ </File.Source>
407
+ )}
185
408
  </File>
186
409
  )
187
410
  },
188
411
  Schema({ schema, plugin }) {
189
412
  const {
190
- options: { mapper, enumType, syntaxType, optionalType, output },
413
+ options: { mapper, enumType, syntaxType, optionalType, arrayType, output },
191
414
  } = plugin
192
415
  const mode = useMode()
193
416
 
@@ -231,6 +454,7 @@ export const typeGenerator = createReactGenerator<PluginTs>({
231
454
  mapper={mapper}
232
455
  enumType={enumType}
233
456
  optionalType={optionalType}
457
+ arrayType={arrayType}
234
458
  syntaxType={syntaxType}
235
459
  />
236
460
  </File>