@kubb/plugin-ts 5.0.0-alpha.21 → 5.0.0-alpha.23

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 +1698 -42
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.ts +485 -4
  4. package/dist/index.js +1667 -41
  5. package/dist/index.js.map +1 -1
  6. package/package.json +3 -42
  7. package/src/components/Enum.tsx +15 -11
  8. package/src/components/Type.tsx +18 -7
  9. package/src/generators/typeGenerator.tsx +12 -21
  10. package/src/generators/typeGeneratorLegacy.tsx +30 -37
  11. package/src/index.ts +13 -1
  12. package/src/plugin.ts +62 -22
  13. package/src/presets.ts +22 -23
  14. package/src/printers/functionPrinter.ts +194 -0
  15. package/src/printers/printerTs.ts +16 -8
  16. package/src/resolvers/resolverTs.ts +10 -47
  17. package/src/resolvers/resolverTsLegacy.ts +4 -31
  18. package/src/types.ts +95 -205
  19. package/src/utils.ts +103 -0
  20. package/dist/Type-B6fo0gSk.js +0 -120
  21. package/dist/Type-B6fo0gSk.js.map +0 -1
  22. package/dist/Type-oFwUfkZv.cjs +0 -131
  23. package/dist/Type-oFwUfkZv.cjs.map +0 -1
  24. package/dist/builderTs-Cd3juc2G.cjs +0 -120
  25. package/dist/builderTs-Cd3juc2G.cjs.map +0 -1
  26. package/dist/builderTs-DausqHpc.js +0 -116
  27. package/dist/builderTs-DausqHpc.js.map +0 -1
  28. package/dist/builders.cjs +0 -3
  29. package/dist/builders.d.ts +0 -8
  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 -67
  38. package/dist/components.js +0 -2
  39. package/dist/generators-ByK18qUn.js +0 -551
  40. package/dist/generators-ByK18qUn.js.map +0 -1
  41. package/dist/generators-aSsiTfUO.cjs +0 -563
  42. package/dist/generators-aSsiTfUO.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-BgZucv4T.js +0 -559
  47. package/dist/printerTs-BgZucv4T.js.map +0 -1
  48. package/dist/printerTs-CFXc_LpP.cjs +0 -595
  49. package/dist/printerTs-CFXc_LpP.cjs.map +0 -1
  50. package/dist/printers.cjs +0 -3
  51. package/dist/printers.d.ts +0 -75
  52. package/dist/printers.js +0 -2
  53. package/dist/resolverTsLegacy-DLl854-P.js +0 -185
  54. package/dist/resolverTsLegacy-DLl854-P.js.map +0 -1
  55. package/dist/resolverTsLegacy-sJ16Iqrl.cjs +0 -196
  56. package/dist/resolverTsLegacy-sJ16Iqrl.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-BcyuFDn9.d.ts +0 -344
  61. package/src/builders/builderTs.ts +0 -92
  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
+ }))
@@ -22,6 +22,12 @@ type TsOptions = {
22
22
  * @default `'inlineLiteral'`
23
23
  */
24
24
  enumType: PluginTs['resolvedOptions']['enumType']
25
+ /**
26
+ * Suffix appended to the generated type alias name when `enumType` is `asConst` or `asPascalConst`.
27
+ *
28
+ * @default `'Key'`
29
+ */
30
+ enumTypeSuffix?: PluginTs['resolvedOptions']['enumTypeSuffix']
25
31
  /**
26
32
  * Controls whether a `type` alias or `interface` declaration is emitted.
27
33
  * @default `'type'`
@@ -31,7 +37,7 @@ type TsOptions = {
31
37
  * When set, `printer.print(node)` produces a full `type Name = …` declaration.
32
38
  * When omitted, `printer.print(node)` returns the raw type node.
33
39
  */
34
- typeName?: string
40
+ name?: string
35
41
 
36
42
  /**
37
43
  * JSDoc `@description` comment added to the generated type or interface declaration.
@@ -264,10 +270,12 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
264
270
  return factory.createUnionDeclaration({ withParentheses: true, nodes: literalNodes }) ?? undefined
265
271
  }
266
272
 
267
- const resolvedName = this.options.resolver.default(node.name, 'type')
268
- const typeName = ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enumType) ? `${resolvedName}Key` : resolvedName
273
+ const resolvedName =
274
+ ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enumType) && this.options.enumTypeSuffix
275
+ ? this.options.resolver.resolveEnumKeyName(node as unknown as SchemaNode, this.options.enumTypeSuffix)
276
+ : this.options.resolver.default(node.name, 'type')
269
277
 
270
- return factory.createTypeReferenceNode(typeName, undefined)
278
+ return factory.createTypeReferenceNode(resolvedName, undefined)
271
279
  },
272
280
  union(node) {
273
281
  const members = node.members ?? []
@@ -352,16 +360,16 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
352
360
  type = factory.createUnionDeclaration({ nodes: [type, factory.keywordTypeNodes.undefined] })
353
361
  }
354
362
 
355
- // Without typeName, return the type node as-is (no declaration wrapping).
356
- const { typeName, syntaxType = 'type', description, keysToOmit } = this.options
357
- if (!typeName) {
363
+ // Without name, return the type node as-is (no declaration wrapping).
364
+ const { name, syntaxType = 'type', description, keysToOmit } = this.options
365
+ if (!name) {
358
366
  return safePrint(type)
359
367
  }
360
368
 
361
369
  const useTypeGeneration = syntaxType === 'type' || type.kind === factory.syntaxKind.union || !!keysToOmit?.length
362
370
 
363
371
  const typeNode = factory.createTypeDeclaration({
364
- name: typeName,
372
+ name,
365
373
  isExportable: true,
366
374
  type: keysToOmit?.length
367
375
  ? 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) {
80
- return `${this.resolveTypedName(node.name ?? '')}Key`
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
  })