@kubb/plugin-ts 5.0.0-alpha.1 → 5.0.0-alpha.11

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 (41) hide show
  1. package/dist/{components-LmqJfxMv.js → components-CRu8IKY3.js} +19 -11
  2. package/dist/components-CRu8IKY3.js.map +1 -0
  3. package/dist/{components-9wydyqUx.cjs → components-DeNDKlzf.cjs} +144 -10
  4. package/dist/components-DeNDKlzf.cjs.map +1 -0
  5. package/dist/components.cjs +1 -1
  6. package/dist/components.d.ts +1 -3
  7. package/dist/components.js +1 -1
  8. package/dist/generators.cjs +3 -2
  9. package/dist/generators.d.ts +60 -48
  10. package/dist/generators.js +2 -2
  11. package/dist/index.cjs +2 -1
  12. package/dist/index.d.ts +41 -2
  13. package/dist/index.js +2 -2
  14. package/dist/plugin-CJ29AwE2.cjs +1320 -0
  15. package/dist/plugin-CJ29AwE2.cjs.map +1 -0
  16. package/dist/plugin-D60XNJSD.js +1267 -0
  17. package/dist/plugin-D60XNJSD.js.map +1 -0
  18. package/dist/types-mSXmB8WU.d.ts +298 -0
  19. package/package.json +8 -8
  20. package/src/components/Type.tsx +0 -3
  21. package/src/components/v2/Enum.tsx +67 -0
  22. package/src/components/v2/Type.tsx +59 -0
  23. package/src/constants.ts +29 -0
  24. package/src/factory.ts +14 -16
  25. package/src/generators/index.ts +1 -0
  26. package/src/generators/typeGenerator.tsx +46 -48
  27. package/src/generators/v2/typeGenerator.tsx +167 -0
  28. package/src/generators/v2/utils.ts +140 -0
  29. package/src/index.ts +1 -0
  30. package/src/parser.ts +1 -8
  31. package/src/plugin.ts +64 -19
  32. package/src/printer.ts +238 -91
  33. package/src/resolverTs.ts +77 -0
  34. package/src/types.ts +144 -15
  35. package/dist/components-9wydyqUx.cjs.map +0 -1
  36. package/dist/components-LmqJfxMv.js.map +0 -1
  37. package/dist/plugin-BHE4J4aP.cjs +0 -508
  38. package/dist/plugin-BHE4J4aP.cjs.map +0 -1
  39. package/dist/plugin-DnKRpgGK.js +0 -476
  40. package/dist/plugin-DnKRpgGK.js.map +0 -1
  41. package/dist/types-BpeKGgCn.d.ts +0 -170
@@ -0,0 +1,59 @@
1
+ import { collect } from '@kubb/ast'
2
+ import type { EnumSchemaNode, SchemaNode } from '@kubb/ast/types'
3
+ import { safePrint } from '@kubb/fabric-core/parsers/typescript'
4
+ import { File } from '@kubb/react-fabric'
5
+ import type { FabricReactNode } from '@kubb/react-fabric/types'
6
+ import { printerTs } from '../../printer.ts'
7
+ import type { PluginTs } from '../../types.ts'
8
+ import { Enum, getEnumNames } from './Enum.tsx'
9
+
10
+ type Props = {
11
+ name: string
12
+ typedName: string
13
+ node: SchemaNode
14
+ optionalType: PluginTs['resolvedOptions']['optionalType']
15
+ arrayType: PluginTs['resolvedOptions']['arrayType']
16
+ enumType: PluginTs['resolvedOptions']['enumType']
17
+ enumKeyCasing: PluginTs['resolvedOptions']['enumKeyCasing']
18
+ syntaxType: PluginTs['resolvedOptions']['syntaxType']
19
+ description?: string
20
+ keysToOmit?: string[]
21
+ }
22
+
23
+ export function Type({ name, typedName, node, keysToOmit, optionalType, arrayType, syntaxType, enumType, enumKeyCasing, description }: Props): FabricReactNode {
24
+ const resolvedDescription = description || node?.description
25
+ const enumSchemaNodes = collect<EnumSchemaNode>(node, {
26
+ schema(n): EnumSchemaNode | undefined {
27
+ if (n.type === 'enum' && n.name) return n as EnumSchemaNode
28
+ },
29
+ })
30
+
31
+ const printer = printerTs({ optionalType, arrayType, enumType, typeName: name, syntaxType, description: resolvedDescription, keysToOmit })
32
+ const typeNode = printer.print(node)
33
+
34
+ if (!typeNode) {
35
+ return
36
+ }
37
+
38
+ const enums = [...new Map(enumSchemaNodes.map((n) => [n.name, n])).values()].map((node) => {
39
+ return {
40
+ node,
41
+ ...getEnumNames(node, enumType),
42
+ }
43
+ })
44
+
45
+ // Skip enum exports when using inlineLiteral
46
+ const shouldExportEnums = enumType !== 'inlineLiteral'
47
+ const shouldExportType = enumType === 'inlineLiteral' || enums.every((item) => item.typeName !== name)
48
+
49
+ return (
50
+ <>
51
+ {shouldExportEnums && enums.map(({ node }) => <Enum node={node} enumType={enumType} enumKeyCasing={enumKeyCasing} />)}
52
+ {shouldExportType && (
53
+ <File.Source name={typedName} isTypeOnly isExportable isIndexable>
54
+ {safePrint(typeNode)}
55
+ </File.Source>
56
+ )}
57
+ </>
58
+ )
59
+ }
@@ -0,0 +1,29 @@
1
+ import type { PluginTs } from './types.ts'
2
+
3
+ type OptionalType = PluginTs['resolvedOptions']['optionalType']
4
+ type EnumType = PluginTs['resolvedOptions']['enumType']
5
+
6
+ /**
7
+ * `optionalType` values that cause a property's type to include `| undefined`.
8
+ */
9
+ export const OPTIONAL_ADDS_UNDEFINED = new Set<OptionalType>(['undefined', 'questionTokenAndUndefined'] as const)
10
+
11
+ /**
12
+ * `optionalType` values that render the property key with a `?` token.
13
+ */
14
+ export const OPTIONAL_ADDS_QUESTION_TOKEN = new Set<OptionalType>(['questionToken', 'questionTokenAndUndefined'] as const)
15
+
16
+ /**
17
+ * `enumType` values that append a `Key` suffix to the generated enum type alias.
18
+ */
19
+ export const ENUM_TYPES_WITH_KEY_SUFFIX = new Set<EnumType>(['asConst', 'asPascalConst'] as const)
20
+
21
+ /**
22
+ * `enumType` values that require a runtime value declaration (object, enum, or literal).
23
+ */
24
+ export const ENUM_TYPES_WITH_RUNTIME_VALUE = new Set<EnumType | undefined>(['enum', 'asConst', 'asPascalConst', 'constEnum', 'literal', undefined] as const)
25
+
26
+ /**
27
+ * `enumType` values whose type declaration is type-only (no runtime value emitted for the type alias).
28
+ */
29
+ export const ENUM_TYPES_WITH_TYPE_ONLY = new Set<EnumType | undefined>(['asConst', 'asPascalConst', 'literal', undefined] as const)
package/src/factory.ts CHANGED
@@ -15,6 +15,8 @@ export const modifiers = {
15
15
 
16
16
  export const syntaxKind = {
17
17
  union: SyntaxKind.UnionType as 192,
18
+ literalType: SyntaxKind.LiteralType,
19
+ stringLiteral: SyntaxKind.StringLiteral,
18
20
  } as const
19
21
 
20
22
  export function getUnknownType(unknownType: 'any' | 'unknown' | 'void' | undefined) {
@@ -660,43 +662,39 @@ export const keywordTypeNodes = {
660
662
  * Converts a path like '/pet/{petId}/uploadImage' to a template literal type
661
663
  * like `/pet/${string}/uploadImage`
662
664
  */
665
+ /**
666
+ * Converts an OAS-style path (e.g. `/pets/{petId}`) or an Express-style path
667
+ * (e.g. `/pets/:petId`) to a TypeScript template literal type
668
+ * like `` `/pets/${string}` ``.
669
+ */
663
670
  export function createUrlTemplateType(path: string): ts.TypeNode {
664
- // If no parameters, return literal string type
665
- if (!path.includes('{')) {
666
- return factory.createLiteralTypeNode(factory.createStringLiteral(path))
667
- }
671
+ // normalized Express `:param` OAS `{param}` so a single regex handles both.
672
+ const normalized = path.replace(/:([^/]+)/g, '{$1}')
668
673
 
669
- // Split path by parameter placeholders, e.g. '/pet/{petId}/upload' -> ['/pet/', 'petId', '/upload']
670
- const segments = path.split(/(\{[^}]+\})/)
674
+ if (!normalized.includes('{')) {
675
+ return factory.createLiteralTypeNode(factory.createStringLiteral(normalized))
676
+ }
671
677
 
672
- // Separate static parts from parameter placeholders
678
+ const segments = normalized.split(/(\{[^}]+\})/)
673
679
  const parts: string[] = []
674
680
  const parameterIndices: number[] = []
675
681
 
676
682
  segments.forEach((segment) => {
677
683
  if (segment.startsWith('{') && segment.endsWith('}')) {
678
- // This is a parameter placeholder
679
684
  parameterIndices.push(parts.length)
680
- parts.push(segment) // Will be replaced with ${string}
685
+ parts.push(segment)
681
686
  } else if (segment) {
682
- // This is a static part
683
687
  parts.push(segment)
684
688
  }
685
689
  })
686
690
 
687
- // Build template literal type
688
- // Template literal structure: head + templateSpans[]
689
- // For '/pet/{petId}/upload': head = '/pet/', spans = [{ type: string, literal: '/upload' }]
690
-
691
691
  const head = ts.factory.createTemplateHead(parts[0] || '')
692
692
  const templateSpans: ts.TemplateLiteralTypeSpan[] = []
693
693
 
694
694
  parameterIndices.forEach((paramIndex, i) => {
695
695
  const isLast = i === parameterIndices.length - 1
696
696
  const nextPart = parts[paramIndex + 1] || ''
697
-
698
697
  const literal = isLast ? ts.factory.createTemplateTail(nextPart) : ts.factory.createTemplateMiddle(nextPart)
699
-
700
698
  templateSpans.push(ts.factory.createTemplateLiteralTypeSpan(keywordTypeNodes.string, literal))
701
699
  })
702
700
 
@@ -1 +1,2 @@
1
1
  export { typeGenerator } from './typeGenerator.tsx'
2
+ export { typeGenerator as typeGeneratorV2 } from './v2/typeGenerator.tsx'
@@ -1,6 +1,6 @@
1
1
  import { pascalCase } from '@internals/utils'
2
- import type { PluginManager } from '@kubb/core'
3
- import { useMode, usePluginManager } from '@kubb/core/hooks'
2
+ import type { PluginDriver } from '@kubb/core'
3
+ import { useMode, usePluginDriver } from '@kubb/core/hooks'
4
4
  import { safePrint } from '@kubb/fabric-core/parsers/typescript'
5
5
  import type { Operation } from '@kubb/oas'
6
6
  import { isKeyword, type OperationSchemas, type OperationSchema as OperationSchemaType, SchemaGenerator, schemaKeywords } from '@kubb/plugin-oas'
@@ -15,15 +15,15 @@ import { createUrlTemplateType, getUnknownType, keywordTypeNodes } from '../fact
15
15
  import { pluginTsName } from '../plugin.ts'
16
16
  import type { PluginTs } from '../types'
17
17
 
18
- function printCombinedSchema({ name, schemas, pluginManager }: { name: string; schemas: OperationSchemas; pluginManager: PluginManager }): string {
18
+ function printCombinedSchema({ name, schemas, driver }: { name: string; schemas: OperationSchemas; driver: PluginDriver }): string {
19
19
  const properties: Record<string, ts.TypeNode> = {}
20
20
 
21
21
  if (schemas.response) {
22
22
  properties['response'] = factory.createUnionDeclaration({
23
23
  nodes: schemas.responses.map((res) => {
24
- const identifier = pluginManager.resolveName({
24
+ const identifier = driver.resolveName({
25
25
  name: res.name,
26
- pluginKey: [pluginTsName],
26
+ pluginName: pluginTsName,
27
27
  type: 'function',
28
28
  })
29
29
 
@@ -33,36 +33,36 @@ function printCombinedSchema({ name, schemas, pluginManager }: { name: string; s
33
33
  }
34
34
 
35
35
  if (schemas.request) {
36
- const identifier = pluginManager.resolveName({
36
+ const identifier = driver.resolveName({
37
37
  name: schemas.request.name,
38
- pluginKey: [pluginTsName],
38
+ pluginName: pluginTsName,
39
39
  type: 'function',
40
40
  })
41
41
  properties['request'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
42
42
  }
43
43
 
44
44
  if (schemas.pathParams) {
45
- const identifier = pluginManager.resolveName({
45
+ const identifier = driver.resolveName({
46
46
  name: schemas.pathParams.name,
47
- pluginKey: [pluginTsName],
47
+ pluginName: pluginTsName,
48
48
  type: 'function',
49
49
  })
50
50
  properties['pathParams'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
51
51
  }
52
52
 
53
53
  if (schemas.queryParams) {
54
- const identifier = pluginManager.resolveName({
54
+ const identifier = driver.resolveName({
55
55
  name: schemas.queryParams.name,
56
- pluginKey: [pluginTsName],
56
+ pluginName: pluginTsName,
57
57
  type: 'function',
58
58
  })
59
59
  properties['queryParams'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
60
60
  }
61
61
 
62
62
  if (schemas.headerParams) {
63
- const identifier = pluginManager.resolveName({
63
+ const identifier = driver.resolveName({
64
64
  name: schemas.headerParams.name,
65
- pluginKey: [pluginTsName],
65
+ pluginName: pluginTsName,
66
66
  type: 'function',
67
67
  })
68
68
  properties['headerParams'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
@@ -71,9 +71,9 @@ function printCombinedSchema({ name, schemas, pluginManager }: { name: string; s
71
71
  if (schemas.errors) {
72
72
  properties['errors'] = factory.createUnionDeclaration({
73
73
  nodes: schemas.errors.map((error) => {
74
- const identifier = pluginManager.resolveName({
74
+ const identifier = driver.resolveName({
75
75
  name: error.name,
76
- pluginKey: [pluginTsName],
76
+ pluginName: pluginTsName,
77
77
  type: 'function',
78
78
  })
79
79
 
@@ -109,16 +109,16 @@ function printRequestSchema({
109
109
  baseName,
110
110
  operation,
111
111
  schemas,
112
- pluginManager,
112
+ driver,
113
113
  }: {
114
114
  baseName: string
115
115
  operation: Operation
116
116
  schemas: OperationSchemas
117
- pluginManager: PluginManager
117
+ driver: PluginDriver
118
118
  }): string {
119
- const name = pluginManager.resolveName({
119
+ const name = driver.resolveName({
120
120
  name: `${baseName} Request`,
121
- pluginKey: [pluginTsName],
121
+ pluginName: pluginTsName,
122
122
  type: 'type',
123
123
  })
124
124
 
@@ -128,9 +128,9 @@ function printRequestSchema({
128
128
  const dataRequestProperties: ts.PropertySignature[] = []
129
129
 
130
130
  if (schemas.request) {
131
- const identifier = pluginManager.resolveName({
131
+ const identifier = driver.resolveName({
132
132
  name: schemas.request.name,
133
- pluginKey: [pluginTsName],
133
+ pluginName: pluginTsName,
134
134
  type: 'type',
135
135
  })
136
136
  dataRequestProperties.push(
@@ -152,9 +152,9 @@ function printRequestSchema({
152
152
 
153
153
  // Add pathParams property
154
154
  if (schemas.pathParams) {
155
- const identifier = pluginManager.resolveName({
155
+ const identifier = driver.resolveName({
156
156
  name: schemas.pathParams.name,
157
- pluginKey: [pluginTsName],
157
+ pluginName: pluginTsName,
158
158
  type: 'type',
159
159
  })
160
160
  dataRequestProperties.push(
@@ -175,9 +175,9 @@ function printRequestSchema({
175
175
 
176
176
  // Add queryParams property
177
177
  if (schemas.queryParams) {
178
- const identifier = pluginManager.resolveName({
178
+ const identifier = driver.resolveName({
179
179
  name: schemas.queryParams.name,
180
- pluginKey: [pluginTsName],
180
+ pluginName: pluginTsName,
181
181
  type: 'type',
182
182
  })
183
183
  dataRequestProperties.push(
@@ -199,9 +199,9 @@ function printRequestSchema({
199
199
 
200
200
  // Add headerParams property
201
201
  if (schemas.headerParams) {
202
- const identifier = pluginManager.resolveName({
202
+ const identifier = driver.resolveName({
203
203
  name: schemas.headerParams.name,
204
- pluginKey: [pluginTsName],
204
+ pluginName: pluginTsName,
205
205
  type: 'type',
206
206
  })
207
207
  dataRequestProperties.push(
@@ -243,28 +243,28 @@ function printRequestSchema({
243
243
  function printResponseSchema({
244
244
  baseName,
245
245
  schemas,
246
- pluginManager,
246
+ driver,
247
247
  unknownType,
248
248
  }: {
249
249
  baseName: string
250
250
  schemas: OperationSchemas
251
- pluginManager: PluginManager
251
+ driver: PluginDriver
252
252
  unknownType: PluginTs['resolvedOptions']['unknownType']
253
253
  }): string {
254
254
  const results: string[] = []
255
255
 
256
- const name = pluginManager.resolveName({
256
+ const name = driver.resolveName({
257
257
  name: `${baseName} ResponseData`,
258
- pluginKey: [pluginTsName],
258
+ pluginName: pluginTsName,
259
259
  type: 'type',
260
260
  })
261
261
 
262
262
  // Generate Responses type (mapping status codes to response types)
263
263
  if (schemas.responses && schemas.responses.length > 0) {
264
264
  const responsesProperties: ts.PropertySignature[] = schemas.responses.map((res) => {
265
- const identifier = pluginManager.resolveName({
265
+ const identifier = driver.resolveName({
266
266
  name: res.name,
267
- pluginKey: [pluginTsName],
267
+ pluginName: pluginTsName,
268
268
  type: 'type',
269
269
  })
270
270
 
@@ -309,23 +309,22 @@ function printResponseSchema({
309
309
  return results.join('\n\n')
310
310
  }
311
311
 
312
- export const typeGenerator = createReactGenerator<PluginTs, '1'>({
312
+ export const typeGenerator = createReactGenerator<PluginTs>({
313
313
  name: 'typescript',
314
- version: '1',
315
314
  Operation({ operation, generator, plugin }) {
316
315
  const {
317
316
  options,
318
- options: { mapper, enumType, enumKeyCasing, syntaxType, optionalType, arrayType, unknownType, paramsCasing },
317
+ options: { enumType, enumKeyCasing, syntaxType, optionalType, arrayType, unknownType, paramsCasing },
319
318
  } = plugin
320
319
 
321
320
  const mode = useMode()
322
- const pluginManager = usePluginManager()
321
+ const driver = usePluginDriver()
323
322
 
324
323
  const oas = useOas()
325
324
  const { getSchemas, getFile, getName, getGroup } = useOperationManager(generator)
326
325
  const schemaManager = useSchemaManager()
327
326
 
328
- const name = getName(operation, { type: 'type', pluginKey: [pluginTsName] })
327
+ const name = getName(operation, { type: 'type', pluginName: pluginTsName })
329
328
 
330
329
  const file = getFile(operation)
331
330
  const schemas = getSchemas(operation)
@@ -334,7 +333,7 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
334
333
  oas,
335
334
  events: generator.context.events,
336
335
  plugin,
337
- pluginManager,
336
+ driver,
338
337
  mode,
339
338
  override: options.override,
340
339
  })
@@ -370,7 +369,6 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
370
369
  description={description}
371
370
  tree={tree}
372
371
  schema={transformedSchema}
373
- mapper={mapper}
374
372
  enumType={enumType}
375
373
  enumKeyCasing={enumKeyCasing}
376
374
  optionalType={optionalType}
@@ -385,6 +383,7 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
385
383
  const responseName = schemaManager.getName(schemas.response.name, {
386
384
  type: 'type',
387
385
  })
386
+
388
387
  const combinedSchemaName = operation.method === 'get' ? `${name}Query` : `${name}Mutation`
389
388
 
390
389
  return (
@@ -392,7 +391,7 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
392
391
  baseName={file.baseName}
393
392
  path={file.path}
394
393
  meta={file.meta}
395
- banner={getBanner({ oas, output: plugin.options.output, config: pluginManager.config })}
394
+ banner={getBanner({ oas, output: plugin.options.output, config: driver.config })}
396
395
  footer={getFooter({ oas, output: plugin.options.output })}
397
396
  >
398
397
  {operationSchemas.map(mapOperationSchema)}
@@ -400,15 +399,15 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
400
399
  {generator.context.UNSTABLE_NAMING ? (
401
400
  <>
402
401
  <File.Source name={`${name}Request`} isExportable isIndexable isTypeOnly>
403
- {printRequestSchema({ baseName: name, operation, schemas, pluginManager })}
402
+ {printRequestSchema({ baseName: name, operation, schemas, driver })}
404
403
  </File.Source>
405
404
  <File.Source name={responseName} isExportable isIndexable isTypeOnly>
406
- {printResponseSchema({ baseName: name, schemas, pluginManager, unknownType })}
405
+ {printResponseSchema({ baseName: name, schemas, driver, unknownType })}
407
406
  </File.Source>
408
407
  </>
409
408
  ) : (
410
409
  <File.Source name={combinedSchemaName} isExportable isIndexable isTypeOnly>
411
- {printCombinedSchema({ name: combinedSchemaName, schemas, pluginManager })}
410
+ {printCombinedSchema({ name: combinedSchemaName, schemas, driver })}
412
411
  </File.Source>
413
412
  )}
414
413
  </File>
@@ -416,12 +415,12 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
416
415
  },
417
416
  Schema({ schema, plugin }) {
418
417
  const {
419
- options: { mapper, enumType, enumKeyCasing, syntaxType, optionalType, arrayType, output },
418
+ options: { enumType, enumKeyCasing, syntaxType, optionalType, arrayType, output },
420
419
  } = plugin
421
420
  const mode = useMode()
422
421
 
423
422
  const oas = useOas()
424
- const pluginManager = usePluginManager()
423
+ const driver = usePluginDriver()
425
424
 
426
425
  const { getName, getFile } = useSchemaManager()
427
426
  const imports = getImports(schema.tree)
@@ -444,7 +443,7 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
444
443
  baseName={type.file.baseName}
445
444
  path={type.file.path}
446
445
  meta={type.file.meta}
447
- banner={getBanner({ oas, output, config: pluginManager.config })}
446
+ banner={getBanner({ oas, output, config: driver.config })}
448
447
  footer={getFooter({ oas, output })}
449
448
  >
450
449
  {mode === 'split' &&
@@ -457,7 +456,6 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
457
456
  description={schema.value.description}
458
457
  tree={schema.tree}
459
458
  schema={schema.value}
460
- mapper={mapper}
461
459
  enumType={enumType}
462
460
  enumKeyCasing={enumKeyCasing}
463
461
  optionalType={optionalType}
@@ -0,0 +1,167 @@
1
+ import { applyParamsCasing } from '@kubb/ast'
2
+ import type { SchemaNode } from '@kubb/ast/types'
3
+ import { defineGenerator } from '@kubb/core'
4
+ import { useKubb } from '@kubb/core/hooks'
5
+ import { File } from '@kubb/react-fabric'
6
+ import { Type } from '../../components/v2/Type.tsx'
7
+ import { ENUM_TYPES_WITH_KEY_SUFFIX } from '../../constants.ts'
8
+ import { resolverTs } from '../../resolverTs.ts'
9
+ import type { PluginTs } from '../../types'
10
+ import { buildDataSchemaNode, buildResponsesSchemaNode, buildResponseUnionSchemaNode } from './utils.ts'
11
+
12
+ export const typeGenerator = defineGenerator<PluginTs>({
13
+ name: 'typescript',
14
+ type: 'react',
15
+ Operation({ node, adapter, options }) {
16
+ const { enumType, enumKeyCasing, optionalType, arrayType, syntaxType, paramsCasing, group } = options
17
+ const { mode, getFile, resolveName, resolveBanner, resolveFooter } = useKubb<PluginTs>()
18
+
19
+ const file = getFile({
20
+ name: node.operationId,
21
+ extname: '.ts',
22
+ mode,
23
+ options: {
24
+ group: group ? (group.type === 'tag' ? { tag: node.tags[0] } : { path: node.path }) : undefined,
25
+ },
26
+ })
27
+ const params = applyParamsCasing(node.parameters, paramsCasing)
28
+
29
+ function renderSchemaType({
30
+ node: schemaNode,
31
+ name,
32
+ typedName,
33
+ description,
34
+ }: {
35
+ node: SchemaNode | null
36
+ name: string
37
+ typedName: string
38
+ description?: string
39
+ }) {
40
+ if (!schemaNode) {
41
+ return null
42
+ }
43
+
44
+ const imports = adapter.getImports(schemaNode, (schemaName) => ({
45
+ name: resolveName({ name: schemaName, type: 'type' }),
46
+ path: getFile({ name: schemaName, extname: '.ts', mode }).path,
47
+ }))
48
+
49
+ return (
50
+ <>
51
+ {mode === 'split' &&
52
+ imports.map((imp) => <File.Import key={[name, imp.path, imp.isTypeOnly].join('-')} root={file.path} path={imp.path} name={imp.name} isTypeOnly />)}
53
+ <Type
54
+ name={name}
55
+ typedName={typedName}
56
+ node={schemaNode}
57
+ description={description}
58
+ enumType={enumType}
59
+ enumKeyCasing={enumKeyCasing}
60
+ optionalType={optionalType}
61
+ arrayType={arrayType}
62
+ syntaxType={syntaxType}
63
+ />
64
+ </>
65
+ )
66
+ }
67
+
68
+ const paramTypes = params.map((param) =>
69
+ renderSchemaType({
70
+ node: param.schema,
71
+ name: resolverTs.resolveParamName(node, param),
72
+ typedName: resolverTs.resolveParamTypedName(node, param),
73
+ }),
74
+ )
75
+
76
+ const responseTypes = node.responses.map((res) =>
77
+ renderSchemaType({
78
+ node: res.schema,
79
+ name: resolverTs.resolveResponseStatusName(node, res.statusCode),
80
+ typedName: resolverTs.resolveResponseStatusTypedName(node, res.statusCode),
81
+ description: res.description,
82
+ }),
83
+ )
84
+
85
+ const requestType = node.requestBody
86
+ ? renderSchemaType({
87
+ node: node.requestBody,
88
+ name: resolverTs.resolveDataName(node),
89
+ typedName: resolverTs.resolveDataTypedName(node),
90
+ description: node.requestBody.description,
91
+ })
92
+ : null
93
+
94
+ const dataType = renderSchemaType({
95
+ node: buildDataSchemaNode({ node: { ...node, parameters: params }, resolveName }),
96
+ name: resolverTs.resolveRequestConfigName(node),
97
+ typedName: resolverTs.resolveRequestConfigTypedName(node),
98
+ })
99
+
100
+ const responsesType = renderSchemaType({
101
+ node: buildResponsesSchemaNode({ node, resolveName }),
102
+ name: resolverTs.resolveResponsesName(node),
103
+ typedName: resolverTs.resolveResponsesTypedName(node),
104
+ })
105
+
106
+ const responseType = renderSchemaType({
107
+ node: buildResponseUnionSchemaNode({ node, resolveName }),
108
+ name: resolverTs.resolveResponseName(node),
109
+ typedName: resolverTs.resolveResponseTypedName(node),
110
+ description: 'Union of all possible responses',
111
+ })
112
+
113
+ return (
114
+ <File baseName={file.baseName} path={file.path} meta={file.meta} banner={resolveBanner()} footer={resolveFooter()}>
115
+ {paramTypes}
116
+ {responseTypes}
117
+ {requestType}
118
+ {dataType}
119
+ {responsesType}
120
+ {responseType}
121
+ </File>
122
+ )
123
+ },
124
+ Schema({ node, adapter, options }) {
125
+ const { enumType, enumKeyCasing, syntaxType, optionalType, arrayType } = options
126
+ const { mode, resolveName, getFile, resolveBanner, resolveFooter } = useKubb<PluginTs>()
127
+
128
+ if (!node.name) {
129
+ return
130
+ }
131
+
132
+ const imports = adapter.getImports(node, (schemaName) => ({
133
+ name: resolveName({ name: schemaName, type: 'type' }),
134
+ path: getFile({ name: schemaName, extname: '.ts', mode }).path,
135
+ }))
136
+
137
+ const isEnumSchema = node.type === 'enum'
138
+
139
+ const typedName =
140
+ ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && isEnumSchema ? resolverTs.resolveEnumKeyTypedName(node) : resolverTs.resolveTypedName(node.name)
141
+
142
+ const type = {
143
+ name: resolverTs.resolveName(node.name),
144
+ typedName,
145
+ file: getFile({ name: node.name, extname: '.ts', mode }),
146
+ } as const
147
+
148
+ return (
149
+ <File baseName={type.file.baseName} path={type.file.path} meta={type.file.meta} banner={resolveBanner()} footer={resolveFooter()}>
150
+ {mode === 'split' &&
151
+ imports.map((imp) => (
152
+ <File.Import key={[node.name, imp.path, imp.isTypeOnly].join('-')} root={type.file.path} path={imp.path} name={imp.name} isTypeOnly />
153
+ ))}
154
+ <Type
155
+ name={type.name}
156
+ typedName={type.typedName}
157
+ node={node}
158
+ enumType={enumType}
159
+ enumKeyCasing={enumKeyCasing}
160
+ optionalType={optionalType}
161
+ arrayType={arrayType}
162
+ syntaxType={syntaxType}
163
+ />
164
+ </File>
165
+ )
166
+ },
167
+ })