@kubb/plugin-ts 5.0.0-alpha.22 → 5.0.0-alpha.24

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 (66) hide show
  1. package/dist/index.cjs +1680 -49
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.ts +529 -4
  4. package/dist/index.js +1653 -52
  5. package/dist/index.js.map +1 -1
  6. package/package.json +3 -42
  7. package/src/components/Enum.tsx +2 -7
  8. package/src/components/Type.tsx +11 -5
  9. package/src/generators/typeGenerator.tsx +36 -24
  10. package/src/generators/typeGeneratorLegacy.tsx +28 -38
  11. package/src/index.ts +13 -1
  12. package/src/plugin.ts +42 -23
  13. package/src/presets.ts +16 -34
  14. package/src/printers/functionPrinter.ts +194 -0
  15. package/src/printers/printerTs.ts +23 -7
  16. package/src/resolvers/resolverTs.ts +10 -47
  17. package/src/resolvers/resolverTsLegacy.ts +4 -31
  18. package/src/types.ts +169 -254
  19. package/src/utils.ts +103 -0
  20. package/dist/Type-Bf8raoQX.cjs +0 -124
  21. package/dist/Type-Bf8raoQX.cjs.map +0 -1
  22. package/dist/Type-BpXxT4l_.js +0 -113
  23. package/dist/Type-BpXxT4l_.js.map +0 -1
  24. package/dist/builderTs-COUg3xtQ.cjs +0 -135
  25. package/dist/builderTs-COUg3xtQ.cjs.map +0 -1
  26. package/dist/builderTs-DPpkJKd1.js +0 -131
  27. package/dist/builderTs-DPpkJKd1.js.map +0 -1
  28. package/dist/builders.cjs +0 -3
  29. package/dist/builders.d.ts +0 -23
  30. package/dist/builders.js +0 -2
  31. package/dist/casing-BJHFg-zZ.js +0 -84
  32. package/dist/casing-BJHFg-zZ.js.map +0 -1
  33. package/dist/casing-DHfdqpLi.cjs +0 -107
  34. package/dist/casing-DHfdqpLi.cjs.map +0 -1
  35. package/dist/chunk-ByKO4r7w.cjs +0 -38
  36. package/dist/components.cjs +0 -4
  37. package/dist/components.d.ts +0 -71
  38. package/dist/components.js +0 -2
  39. package/dist/generators-DFDut8o-.js +0 -555
  40. package/dist/generators-DFDut8o-.js.map +0 -1
  41. package/dist/generators-DKd7MYbx.cjs +0 -567
  42. package/dist/generators-DKd7MYbx.cjs.map +0 -1
  43. package/dist/generators.cjs +0 -4
  44. package/dist/generators.d.ts +0 -12
  45. package/dist/generators.js +0 -2
  46. package/dist/printerTs-BcHudagv.cjs +0 -594
  47. package/dist/printerTs-BcHudagv.cjs.map +0 -1
  48. package/dist/printerTs-CMBCOuqd.js +0 -558
  49. package/dist/printerTs-CMBCOuqd.js.map +0 -1
  50. package/dist/printers.cjs +0 -3
  51. package/dist/printers.d.ts +0 -81
  52. package/dist/printers.js +0 -2
  53. package/dist/resolverTsLegacy-CPiqqsO6.js +0 -185
  54. package/dist/resolverTsLegacy-CPiqqsO6.js.map +0 -1
  55. package/dist/resolverTsLegacy-CuR9XbKk.cjs +0 -196
  56. package/dist/resolverTsLegacy-CuR9XbKk.cjs.map +0 -1
  57. package/dist/resolvers.cjs +0 -4
  58. package/dist/resolvers.d.ts +0 -52
  59. package/dist/resolvers.js +0 -2
  60. package/dist/types-CRtcZOCz.d.ts +0 -374
  61. package/src/builders/builderTs.ts +0 -107
  62. package/src/builders/index.ts +0 -1
  63. package/src/components/index.ts +0 -2
  64. package/src/generators/index.ts +0 -2
  65. package/src/printers/index.ts +0 -1
  66. package/src/resolvers/index.ts +0 -2
@@ -0,0 +1,194 @@
1
+ import type { PrinterFactoryOptions } from '@kubb/ast'
2
+ import { createPrinterFactory } from '@kubb/ast'
3
+ import type { FunctionNode, FunctionNodeType, FunctionParameterNode, FunctionParametersNode, ParameterGroupNode, TypeNode } from '@kubb/ast/types'
4
+
5
+ /**
6
+ * Maps each function-printer handler key to its concrete node type.
7
+ */
8
+ export type FunctionNodeByType = {
9
+ functionParameter: FunctionParameterNode
10
+ parameterGroup: ParameterGroupNode
11
+ functionParameters: FunctionParametersNode
12
+ type: TypeNode
13
+ }
14
+
15
+ const kindToHandlerKey = {
16
+ FunctionParameter: 'functionParameter',
17
+ ParameterGroup: 'parameterGroup',
18
+ FunctionParameters: 'functionParameters',
19
+ Type: 'type',
20
+ } satisfies Record<string, FunctionNodeType>
21
+
22
+ /**
23
+ * Creates a function-parameter printer factory.
24
+ *
25
+ * Uses `createPrinterFactory` and dispatches handlers by `node.kind`
26
+ * (for function nodes) rather than by `node.type` (for schema nodes).
27
+ */
28
+ export const defineFunctionPrinter = createPrinterFactory<FunctionNode, FunctionNodeType, FunctionNodeByType>((node) => kindToHandlerKey[node.kind])
29
+
30
+ export type FunctionPrinterOptions = {
31
+ /**
32
+ * Rendering modes supported by `functionPrinter`.
33
+ *
34
+ * | Mode | Output example | Use case |
35
+ * |---------------|---------------------------------------------|---------------------------------|
36
+ * | `declaration` | `id: string, config: Config = {}` | Function parameter declaration |
37
+ * | `call` | `id, { method, url }` | Function call arguments |
38
+ * | `keys` | `{ id, config }` | Key names only (destructuring) |
39
+ * | `values` | `{ id: id, config: config }` | Key/value object entries |
40
+ */
41
+ mode: 'declaration' | 'call' | 'keys' | 'values'
42
+ /**
43
+ * Optional transformation applied to every parameter name before printing.
44
+ */
45
+ transformName?: (name: string) => string
46
+ /**
47
+ * Optional transformation applied to every type string before printing.
48
+ */
49
+ transformType?: (type: string) => string
50
+ }
51
+
52
+ type DefaultPrinter = PrinterFactoryOptions<'functionParameters', FunctionPrinterOptions, string>
53
+
54
+ function rank(param: FunctionParameterNode | ParameterGroupNode): number {
55
+ if (param.kind === 'ParameterGroup') {
56
+ if (param.default) return 2
57
+ const isOptional = param.optional ?? param.properties.every((p) => p.optional || p.default !== undefined)
58
+ return isOptional ? 1 : 0
59
+ }
60
+ if (param.rest) return 3
61
+ if (param.default) return 2
62
+ return param.optional ? 1 : 0
63
+ }
64
+
65
+ function sortParams(params: ReadonlyArray<FunctionParameterNode | ParameterGroupNode>): Array<FunctionParameterNode | ParameterGroupNode> {
66
+ return [...params].sort((a, b) => rank(a) - rank(b))
67
+ }
68
+
69
+ function sortChildParams(params: Array<FunctionParameterNode>): Array<FunctionParameterNode> {
70
+ return [...params].sort((a, b) => rank(a) - rank(b))
71
+ }
72
+
73
+ /**
74
+ * Default function-signature printer.
75
+ * Covers the four standard output modes used across Kubb plugins.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * const printer = functionPrinter({ mode: 'declaration' })
80
+ *
81
+ * const sig = createFunctionParameters({
82
+ * params: [
83
+ * createFunctionParameter({ name: 'petId', type: 'string', optional: false }),
84
+ * createFunctionParameter({ name: 'config', type: 'Config', optional: false, default: '{}' }),
85
+ * ],
86
+ * })
87
+ *
88
+ * printer.print(sig) // → "petId: string, config: Config = {}"
89
+ * ```
90
+ */
91
+ export const functionPrinter = defineFunctionPrinter<DefaultPrinter>((options) => ({
92
+ name: 'functionParameters',
93
+ options,
94
+ nodes: {
95
+ type(node) {
96
+ if (node.variant === 'member') {
97
+ return `${node.base}['${node.key}']`
98
+ }
99
+ if (node.variant === 'struct') {
100
+ const parts = node.properties.map((p) => {
101
+ const typeStr = this.transform(p.type)
102
+ return p.optional ? `${p.name}?: ${typeStr}` : `${p.name}: ${typeStr}`
103
+ })
104
+ return `{ ${parts.join('; ')} }`
105
+ }
106
+ if (node.variant === 'reference') {
107
+ return node.name
108
+ }
109
+ return null
110
+ },
111
+ functionParameter(node) {
112
+ const { mode, transformName, transformType } = this.options
113
+ const name = transformName ? transformName(node.name) : node.name
114
+
115
+ const rawType = node.type ? this.transform(node.type) : undefined
116
+ const type = rawType != null && transformType ? transformType(rawType) : rawType
117
+
118
+ if (mode === 'keys' || mode === 'values') {
119
+ return node.rest ? `...${name}` : name
120
+ }
121
+
122
+ if (mode === 'call') {
123
+ return node.rest ? `...${name}` : name
124
+ }
125
+
126
+ if (node.rest) {
127
+ return type ? `...${name}: ${type}` : `...${name}`
128
+ }
129
+ if (type) {
130
+ if (node.optional) return `${name}?: ${type}`
131
+ return node.default ? `${name}: ${type} = ${node.default}` : `${name}: ${type}`
132
+ }
133
+ return node.default ? `${name} = ${node.default}` : name
134
+ },
135
+ parameterGroup(node) {
136
+ const { mode, transformName, transformType } = this.options
137
+ const sorted = sortChildParams(node.properties)
138
+ const isOptional = node.optional ?? sorted.every((p) => p.optional || p.default !== undefined)
139
+
140
+ if (node.inline) {
141
+ return sorted
142
+ .map((p) => this.transform(p))
143
+ .filter(Boolean)
144
+ .join(', ')
145
+ }
146
+
147
+ if (mode === 'keys' || mode === 'values') {
148
+ const keys = sorted.map((p) => p.name).join(', ')
149
+ return `{ ${keys} }`
150
+ }
151
+
152
+ if (mode === 'call') {
153
+ const keys = sorted.map((p) => p.name).join(', ')
154
+ return `{ ${keys} }`
155
+ }
156
+
157
+ const names = sorted.map((p) => {
158
+ const n = transformName ? transformName(p.name) : p.name
159
+
160
+ return n
161
+ })
162
+
163
+ const nameStr = names.length ? `{ ${names.join(', ')} }` : undefined
164
+ if (!nameStr) return null
165
+
166
+ let typeAnnotation: string | undefined = node.type ? (this.transform(node.type) ?? undefined) : undefined
167
+ if (!typeAnnotation) {
168
+ const typeParts = sorted
169
+ .filter((p) => p.type)
170
+ .map((p) => {
171
+ const rawT = p.type ? this.transform(p.type) : undefined
172
+ const t = rawT != null && transformType ? transformType(rawT) : rawT
173
+ return p.optional || p.default !== undefined ? `${p.name}?: ${t}` : `${p.name}: ${t}`
174
+ })
175
+ typeAnnotation = typeParts.length ? `{ ${typeParts.join('; ')} }` : undefined
176
+ }
177
+
178
+ if (typeAnnotation) {
179
+ if (isOptional) return `${nameStr}: ${typeAnnotation} = ${node.default ?? '{}'}`
180
+ return node.default ? `${nameStr}: ${typeAnnotation} = ${node.default}` : `${nameStr}: ${typeAnnotation}`
181
+ }
182
+
183
+ return node.default ? `${nameStr} = ${node.default}` : nameStr
184
+ },
185
+ functionParameters(node) {
186
+ const sorted = sortParams(node.params)
187
+
188
+ return sorted
189
+ .map((p) => this.transform(p))
190
+ .filter(Boolean)
191
+ .join(', ')
192
+ },
193
+ },
194
+ }))
@@ -37,7 +37,7 @@ type TsOptions = {
37
37
  * When set, `printer.print(node)` produces a full `type Name = …` declaration.
38
38
  * When omitted, `printer.print(node)` returns the raw type node.
39
39
  */
40
- typeName?: string
40
+ name?: string
41
41
 
42
42
  /**
43
43
  * JSDoc `@description` comment added to the generated type or interface declaration.
@@ -52,6 +52,12 @@ type TsOptions = {
52
52
  * Resolver used to transform raw schema names into valid TypeScript identifiers.
53
53
  */
54
54
  resolver: ResolverTs
55
+ /**
56
+ * Names of top-level schemas that are enums.
57
+ * When set, the `ref` handler uses the suffixed type name (e.g. `StatusKey`) for enum refs
58
+ * instead of the plain PascalCase name, so imports align with what the enum file actually exports.
59
+ */
60
+ enumSchemaNames?: Set<string>
55
61
  }
56
62
 
57
63
  /**
@@ -254,7 +260,17 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
254
260
  // (e.g. by single-member allOf flatten using the property-derived child name).
255
261
  // Inline refs (without $ref) from utils already carry resolved type names.
256
262
  const refName = node.ref ? (node.ref.split('/').at(-1) ?? node.name) : node.name
257
- const name = node.ref ? this.options.resolver.default(refName, 'type') : refName
263
+
264
+ // When a Key suffix is configured, enum refs must use the suffixed name (e.g. `StatusKey`)
265
+ // so the reference matches what the enum file actually exports.
266
+ const isEnumRef =
267
+ node.ref && ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enumType) && this.options.enumTypeSuffix && this.options.enumSchemaNames?.has(refName)
268
+
269
+ const name = isEnumRef
270
+ ? this.options.resolver.resolveEnumKeyName({ name: refName } as SchemaNode, this.options.enumTypeSuffix!)
271
+ : node.ref
272
+ ? this.options.resolver.default(refName, 'type')
273
+ : refName
258
274
 
259
275
  return factory.createTypeReferenceNode(name, undefined)
260
276
  },
@@ -272,7 +288,7 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
272
288
 
273
289
  const resolvedName =
274
290
  ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enumType) && this.options.enumTypeSuffix
275
- ? this.options.resolver.resolveEnumKeyTypedName(node as unknown as SchemaNode, this.options.enumTypeSuffix)
291
+ ? this.options.resolver.resolveEnumKeyName(node as unknown as SchemaNode, this.options.enumTypeSuffix)
276
292
  : this.options.resolver.default(node.name, 'type')
277
293
 
278
294
  return factory.createTypeReferenceNode(resolvedName, undefined)
@@ -360,16 +376,16 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
360
376
  type = factory.createUnionDeclaration({ nodes: [type, factory.keywordTypeNodes.undefined] })
361
377
  }
362
378
 
363
- // Without typeName, return the type node as-is (no declaration wrapping).
364
- const { typeName, syntaxType = 'type', description, keysToOmit } = this.options
365
- if (!typeName) {
379
+ // Without name, return the type node as-is (no declaration wrapping).
380
+ const { name, syntaxType = 'type', description, keysToOmit } = this.options
381
+ if (!name) {
366
382
  return safePrint(type)
367
383
  }
368
384
 
369
385
  const useTypeGeneration = syntaxType === 'type' || type.kind === factory.syntaxKind.union || !!keysToOmit?.length
370
386
 
371
387
  const typeNode = factory.createTypeDeclaration({
372
- name: typeName,
388
+ name,
373
389
  isExportable: true,
374
390
  type: keysToOmit?.length
375
391
  ? factory.createOmitDeclaration({
@@ -19,8 +19,7 @@ function resolveName(name: string, type?: 'file' | 'function' | 'type' | 'const'
19
19
  * import { resolver } from '@kubb/plugin-ts'
20
20
  *
21
21
  * resolver.default('list pets', 'type') // → 'ListPets'
22
- * resolver.resolveName('list pets status 200') // → 'listPetsStatus200'
23
- * resolver.resolveTypedName('list pets status 200') // → 'ListPetsStatus200'
22
+ * resolver.resolveName('list pets status 200') // → 'ListPetsStatus200'
24
23
  * resolver.resolvePathName('list pets', 'file') // → 'listPets'
25
24
  * ```
26
25
  */
@@ -34,74 +33,38 @@ export const resolverTs = defineResolver<PluginTs>(() => {
34
33
  resolveName(name) {
35
34
  return this.default(name, 'function')
36
35
  },
37
- resolveTypedName(name) {
38
- return this.default(name, 'type')
39
- },
40
36
  resolvePathName(name, type) {
41
37
  return this.default(name, type)
42
38
  },
43
39
  resolveParamName(node, param) {
44
- return this.resolveName(`${node.operationId} ${this.default(param.in)} ${param.name}`)
45
- },
46
- resolveParamTypedName(node, param) {
47
- return this.resolveTypedName(`${node.operationId} ${this.default(param.in)} ${param.name}`)
40
+ return this.resolveName(`${node.operationId} ${param.in} ${param.name}`)
48
41
  },
49
42
  resolveResponseStatusName(node, statusCode) {
50
43
  return this.resolveName(`${node.operationId} Status ${statusCode}`)
51
44
  },
52
- resolveResponseStatusTypedName(node, statusCode) {
53
- return this.resolveTypedName(`${node.operationId} Status ${statusCode}`)
54
- },
55
45
  resolveDataName(node) {
56
46
  return this.resolveName(`${node.operationId} Data`)
57
47
  },
58
- resolveDataTypedName(node) {
59
- return this.resolveTypedName(`${node.operationId} Data`)
60
- },
61
48
  resolveRequestConfigName(node) {
62
49
  return this.resolveName(`${node.operationId} RequestConfig`)
63
50
  },
64
- resolveRequestConfigTypedName(node) {
65
- return this.resolveTypedName(`${node.operationId} RequestConfig`)
66
- },
67
51
  resolveResponsesName(node) {
68
52
  return this.resolveName(`${node.operationId} Responses`)
69
53
  },
70
- resolveResponsesTypedName(node) {
71
- return this.resolveTypedName(`${node.operationId} Responses`)
72
- },
73
54
  resolveResponseName(node) {
74
55
  return this.resolveName(`${node.operationId} Response`)
75
56
  },
76
- resolveResponseTypedName(node) {
77
- return this.resolveTypedName(`${node.operationId} Response`)
78
- },
79
- resolveEnumKeyTypedName(node, enumTypeSuffix = 'key') {
80
- return `${this.resolveTypedName(node.name ?? '')}${enumTypeSuffix}`
81
- },
82
- resolvePathParamsName(_node) {
83
- throw new Error("resolvePathParamsName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamName per individual parameter instead.")
84
- },
85
- resolvePathParamsTypedName(_node) {
86
- throw new Error(
87
- "resolvePathParamsTypedName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamTypedName per individual parameter instead.",
88
- )
89
- },
90
- resolveQueryParamsName(_node) {
91
- throw new Error("resolveQueryParamsName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamName per individual parameter instead.")
57
+ resolveEnumKeyName(node, enumTypeSuffix = 'key') {
58
+ return `${this.resolveName(node.name ?? '')}${enumTypeSuffix}`
92
59
  },
93
- resolveQueryParamsTypedName(_node) {
94
- throw new Error(
95
- "resolveQueryParamsTypedName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamTypedName per individual parameter instead.",
96
- )
60
+ resolvePathParamsName(node, param) {
61
+ return this.resolveParamName(node, param)
97
62
  },
98
- resolveHeaderParamsName(_node) {
99
- throw new Error("resolveHeaderParamsName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamName per individual parameter instead.")
63
+ resolveQueryParamsName(node, param) {
64
+ return this.resolveParamName(node, param)
100
65
  },
101
- resolveHeaderParamsTypedName(_node) {
102
- throw new Error(
103
- "resolveHeaderParamsTypedName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamTypedName per individual parameter instead.",
104
- )
66
+ resolveHeaderParamsName(node, param) {
67
+ return this.resolveParamName(node, param)
105
68
  },
106
69
  }
107
70
  })
@@ -35,53 +35,26 @@ export const resolverTsLegacy = defineResolver<PluginTs>(() => {
35
35
  }
36
36
  return this.resolveName(`${node.operationId} ${statusCode}`)
37
37
  },
38
- resolveResponseStatusTypedName(node, statusCode) {
39
- if (statusCode === 'default') {
40
- return this.resolveTypedName(`${node.operationId} Error`)
41
- }
42
- return this.resolveTypedName(`${node.operationId} ${statusCode}`)
43
- },
44
38
  resolveDataName(node) {
45
39
  const suffix = node.method === 'GET' ? 'QueryRequest' : 'MutationRequest'
46
40
  return this.resolveName(`${node.operationId} ${suffix}`)
47
41
  },
48
- resolveDataTypedName(node) {
49
- const suffix = node.method === 'GET' ? 'QueryRequest' : 'MutationRequest'
50
- return this.resolveTypedName(`${node.operationId} ${suffix}`)
51
- },
52
42
  resolveResponsesName(node) {
53
43
  const suffix = node.method === 'GET' ? 'Query' : 'Mutation'
54
- return `${this.default(node.operationId, 'function')}${suffix}`
55
- },
56
- resolveResponsesTypedName(node) {
57
- const suffix = node.method === 'GET' ? 'Query' : 'Mutation'
58
- return `${this.default(node.operationId, 'type')}${suffix}`
44
+ return this.resolveName(`${node.operationId} ${suffix}`)
59
45
  },
60
46
  resolveResponseName(node) {
61
47
  const suffix = node.method === 'GET' ? 'QueryResponse' : 'MutationResponse'
62
48
  return this.resolveName(`${node.operationId} ${suffix}`)
63
49
  },
64
- resolveResponseTypedName(node) {
65
- const suffix = node.method === 'GET' ? 'QueryResponse' : 'MutationResponse'
66
- return this.resolveTypedName(`${node.operationId} ${suffix}`)
67
- },
68
- resolvePathParamsName(node) {
50
+ resolvePathParamsName(node, _param) {
69
51
  return this.resolveName(`${node.operationId} PathParams`)
70
52
  },
71
- resolvePathParamsTypedName(node) {
72
- return this.resolveTypedName(`${node.operationId} PathParams`)
73
- },
74
- resolveQueryParamsName(node) {
53
+ resolveQueryParamsName(node, _param) {
75
54
  return this.resolveName(`${node.operationId} QueryParams`)
76
55
  },
77
- resolveQueryParamsTypedName(node) {
78
- return this.resolveTypedName(`${node.operationId} QueryParams`)
79
- },
80
- resolveHeaderParamsName(node) {
56
+ resolveHeaderParamsName(node, _param) {
81
57
  return this.resolveName(`${node.operationId} HeaderParams`)
82
58
  },
83
- resolveHeaderParamsTypedName(node) {
84
- return this.resolveTypedName(`${node.operationId} HeaderParams`)
85
- },
86
59
  }
87
60
  })