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

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 (76) hide show
  1. package/dist/Type-B6fo0gSk.js +120 -0
  2. package/dist/Type-B6fo0gSk.js.map +1 -0
  3. package/dist/Type-oFwUfkZv.cjs +131 -0
  4. package/dist/Type-oFwUfkZv.cjs.map +1 -0
  5. package/dist/builderTs-Cd3juc2G.cjs +120 -0
  6. package/dist/builderTs-Cd3juc2G.cjs.map +1 -0
  7. package/dist/builderTs-DausqHpc.js +116 -0
  8. package/dist/builderTs-DausqHpc.js.map +1 -0
  9. package/dist/builders.cjs +3 -0
  10. package/dist/builders.d.ts +8 -0
  11. package/dist/builders.js +2 -0
  12. package/dist/casing-BJHFg-zZ.js +84 -0
  13. package/dist/casing-BJHFg-zZ.js.map +1 -0
  14. package/dist/casing-DHfdqpLi.cjs +107 -0
  15. package/dist/casing-DHfdqpLi.cjs.map +1 -0
  16. package/dist/chunk-ByKO4r7w.cjs +38 -0
  17. package/dist/components.cjs +3 -2
  18. package/dist/components.d.ts +40 -11
  19. package/dist/components.js +2 -2
  20. package/dist/generators-ByK18qUn.js +551 -0
  21. package/dist/generators-ByK18qUn.js.map +1 -0
  22. package/dist/generators-aSsiTfUO.cjs +563 -0
  23. package/dist/generators-aSsiTfUO.cjs.map +1 -0
  24. package/dist/generators.cjs +3 -2
  25. package/dist/generators.d.ts +7 -492
  26. package/dist/generators.js +2 -2
  27. package/dist/index.cjs +148 -3
  28. package/dist/index.cjs.map +1 -0
  29. package/dist/index.d.ts +1 -1
  30. package/dist/index.js +146 -1
  31. package/dist/index.js.map +1 -0
  32. package/dist/printerTs-BgZucv4T.js +559 -0
  33. package/dist/printerTs-BgZucv4T.js.map +1 -0
  34. package/dist/printerTs-CFXc_LpP.cjs +595 -0
  35. package/dist/printerTs-CFXc_LpP.cjs.map +1 -0
  36. package/dist/printers.cjs +3 -0
  37. package/dist/printers.d.ts +75 -0
  38. package/dist/printers.js +2 -0
  39. package/dist/resolverTsLegacy-DLl854-P.js +185 -0
  40. package/dist/resolverTsLegacy-DLl854-P.js.map +1 -0
  41. package/dist/resolverTsLegacy-sJ16Iqrl.cjs +196 -0
  42. package/dist/resolverTsLegacy-sJ16Iqrl.cjs.map +1 -0
  43. package/dist/resolvers.cjs +4 -0
  44. package/dist/resolvers.d.ts +52 -0
  45. package/dist/resolvers.js +2 -0
  46. package/dist/types-BcyuFDn9.d.ts +344 -0
  47. package/package.json +27 -8
  48. package/src/builders/builderTs.ts +92 -0
  49. package/src/builders/index.ts +1 -0
  50. package/src/components/Enum.tsx +83 -0
  51. package/src/components/Type.tsx +24 -145
  52. package/src/components/index.ts +1 -0
  53. package/src/constants.ts +29 -0
  54. package/src/factory.ts +14 -48
  55. package/src/generators/index.ts +1 -0
  56. package/src/generators/typeGenerator.tsx +119 -403
  57. package/src/generators/typeGeneratorLegacy.tsx +345 -0
  58. package/src/plugin.ts +80 -122
  59. package/src/presets.ts +26 -0
  60. package/src/printers/index.ts +1 -0
  61. package/src/printers/printerTs.ts +389 -0
  62. package/src/resolvers/index.ts +2 -0
  63. package/src/resolvers/resolverTs.ts +107 -0
  64. package/src/resolvers/resolverTsLegacy.ts +87 -0
  65. package/src/types.ts +261 -72
  66. package/dist/components-9wydyqUx.cjs +0 -848
  67. package/dist/components-9wydyqUx.cjs.map +0 -1
  68. package/dist/components-LmqJfxMv.js +0 -721
  69. package/dist/components-LmqJfxMv.js.map +0 -1
  70. package/dist/plugin-CNkzbtpl.cjs +0 -508
  71. package/dist/plugin-CNkzbtpl.cjs.map +0 -1
  72. package/dist/plugin-DoLrDl9P.js +0 -476
  73. package/dist/plugin-DoLrDl9P.js.map +0 -1
  74. package/dist/types-BpeKGgCn.d.ts +0 -170
  75. package/src/parser.ts +0 -396
  76. package/src/printer.ts +0 -221
@@ -0,0 +1,389 @@
1
+ import { jsStringEscape, stringify } from '@internals/utils'
2
+ import { isStringType, narrowSchema, schemaTypes } from '@kubb/ast'
3
+ import type { ArraySchemaNode, SchemaNode } from '@kubb/ast/types'
4
+ import type { PrinterFactoryOptions } from '@kubb/core'
5
+ import { definePrinter } from '@kubb/core'
6
+ import { safePrint } from '@kubb/fabric-core/parsers/typescript'
7
+ import type ts from 'typescript'
8
+ import { ENUM_TYPES_WITH_KEY_SUFFIX, OPTIONAL_ADDS_QUESTION_TOKEN, OPTIONAL_ADDS_UNDEFINED } from '../constants.ts'
9
+ import * as factory from '../factory.ts'
10
+ import type { PluginTs, ResolverTs } from '../types.ts'
11
+
12
+ type TsOptions = {
13
+ /**
14
+ * @default `'questionToken'`
15
+ */
16
+ optionalType: PluginTs['resolvedOptions']['optionalType']
17
+ /**
18
+ * @default `'array'`
19
+ */
20
+ arrayType: PluginTs['resolvedOptions']['arrayType']
21
+ /**
22
+ * @default `'inlineLiteral'`
23
+ */
24
+ enumType: PluginTs['resolvedOptions']['enumType']
25
+ /**
26
+ * Controls whether a `type` alias or `interface` declaration is emitted.
27
+ * @default `'type'`
28
+ */
29
+ syntaxType?: PluginTs['resolvedOptions']['syntaxType']
30
+ /**
31
+ * When set, `printer.print(node)` produces a full `type Name = …` declaration.
32
+ * When omitted, `printer.print(node)` returns the raw type node.
33
+ */
34
+ typeName?: string
35
+
36
+ /**
37
+ * JSDoc `@description` comment added to the generated type or interface declaration.
38
+ */
39
+ description?: string
40
+ /**
41
+ * Property keys to exclude from the generated type via `Omit<Type, Keys>`.
42
+ * Forces type-alias syntax even when `syntaxType` is `'interface'`.
43
+ */
44
+ keysToOmit?: Array<string>
45
+ /**
46
+ * Resolver used to transform raw schema names into valid TypeScript identifiers.
47
+ */
48
+ resolver: ResolverTs
49
+ }
50
+
51
+ /**
52
+ * TypeScript printer factory options: maps `SchemaNode` → `ts.TypeNode` (raw) or `ts.Node` (full declaration).
53
+ */
54
+ type TsPrinter = PrinterFactoryOptions<'typescript', TsOptions, ts.TypeNode, string>
55
+
56
+ /**
57
+ * Converts a primitive const value to a TypeScript literal type node.
58
+ * Handles negative numbers via a prefix unary expression.
59
+ */
60
+ function constToTypeNode(value: string | number | boolean, format: 'string' | 'number' | 'boolean'): ts.TypeNode | undefined {
61
+ if (format === 'boolean') {
62
+ return factory.createLiteralTypeNode(value === true ? factory.createTrue() : factory.createFalse())
63
+ }
64
+ if (format === 'number' && typeof value === 'number') {
65
+ if (value < 0) {
66
+ return factory.createLiteralTypeNode(factory.createPrefixUnaryExpression(factory.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value))))
67
+ }
68
+ return factory.createLiteralTypeNode(factory.createNumericLiteral(value))
69
+ }
70
+ return factory.createLiteralTypeNode(factory.createStringLiteral(String(value)))
71
+ }
72
+
73
+ /**
74
+ * Returns a `Date` reference type node when `representation` is `'date'`, otherwise falls back to `string`.
75
+ */
76
+ function dateOrStringNode(node: { representation?: string }): ts.TypeNode {
77
+ return node.representation === 'date' ? factory.createTypeReferenceNode(factory.createIdentifier('Date')) : factory.keywordTypeNodes.string
78
+ }
79
+
80
+ /**
81
+ * Maps an array of `SchemaNode`s through the printer, filtering out `null` and `undefined` results.
82
+ */
83
+ function buildMemberNodes(members: Array<SchemaNode> | undefined, print: (node: SchemaNode) => ts.TypeNode | null | undefined): Array<ts.TypeNode> {
84
+ return (members ?? []).map(print).filter(Boolean)
85
+ }
86
+
87
+ /**
88
+ * Builds a TypeScript tuple type node from an array schema's `items`,
89
+ * applying min/max slice and optional/rest element rules.
90
+ */
91
+ function buildTupleNode(node: ArraySchemaNode, print: (node: SchemaNode) => ts.TypeNode | null | undefined): ts.TypeNode | undefined {
92
+ let items = (node.items ?? []).map(print).filter(Boolean)
93
+
94
+ const restNode = node.rest ? (print(node.rest) ?? undefined) : undefined
95
+ const { min, max } = node
96
+
97
+ if (max !== undefined) {
98
+ items = items.slice(0, max)
99
+ if (items.length < max && restNode) {
100
+ items = [...items, ...Array(max - items.length).fill(restNode)]
101
+ }
102
+ }
103
+
104
+ if (min !== undefined) {
105
+ items = items.map((item, i) => (i >= min ? factory.createOptionalTypeNode(item) : item))
106
+ }
107
+
108
+ if (max === undefined && restNode) {
109
+ items.push(factory.createRestTypeNode(factory.createArrayTypeNode(restNode)))
110
+ }
111
+
112
+ return factory.createTupleTypeNode(items)
113
+ }
114
+
115
+ /**
116
+ * Applies `nullable` and optional/nullish `| undefined` union modifiers to a property's resolved base type.
117
+ */
118
+ function buildPropertyType(schema: SchemaNode, baseType: ts.TypeNode, optionalType: TsOptions['optionalType']): ts.TypeNode {
119
+ const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(optionalType)
120
+
121
+ let type = baseType
122
+
123
+ if (schema.nullable) {
124
+ type = factory.createUnionDeclaration({ nodes: [type, factory.keywordTypeNodes.null] })
125
+ }
126
+
127
+ if ((schema.nullish || schema.optional) && addsUndefined) {
128
+ type = factory.createUnionDeclaration({ nodes: [type, factory.keywordTypeNodes.undefined] })
129
+ }
130
+
131
+ return type
132
+ }
133
+
134
+ /**
135
+ * Collects JSDoc annotation strings (description, deprecated, min/max, pattern, default, example, type) for a schema node.
136
+ */
137
+ function buildPropertyJSDocComments(schema: SchemaNode): Array<string | undefined> {
138
+ const isArray = schema.type === 'array'
139
+
140
+ return [
141
+ 'description' in schema && schema.description ? `@description ${jsStringEscape(schema.description)}` : undefined,
142
+ 'deprecated' in schema && schema.deprecated ? '@deprecated' : undefined,
143
+ // minItems/maxItems on arrays should not be emitted as @minLength/@maxLength
144
+ !isArray && 'min' in schema && schema.min !== undefined ? `@minLength ${schema.min}` : undefined,
145
+ !isArray && 'max' in schema && schema.max !== undefined ? `@maxLength ${schema.max}` : undefined,
146
+ 'pattern' in schema && schema.pattern ? `@pattern ${schema.pattern}` : undefined,
147
+ 'default' in schema && schema.default !== undefined
148
+ ? `@default ${'primitive' in schema && schema.primitive === 'string' ? stringify(schema.default as string) : schema.default}`
149
+ : undefined,
150
+ 'example' in schema && schema.example !== undefined ? `@example ${schema.example}` : undefined,
151
+ 'primitive' in schema && schema.primitive
152
+ ? [`@type ${schema.primitive || 'unknown'}`, 'optional' in schema && schema.optional ? ' | undefined' : undefined].filter(Boolean).join('')
153
+ : undefined,
154
+ ]
155
+ }
156
+
157
+ /**
158
+ * Creates TypeScript index signatures for `additionalProperties` and `patternProperties` on an object schema node.
159
+ */
160
+ function buildIndexSignatures(
161
+ node: { additionalProperties?: SchemaNode | boolean; patternProperties?: Record<string, SchemaNode> },
162
+ propertyCount: number,
163
+ print: (node: SchemaNode) => ts.TypeNode | null | undefined,
164
+ ): Array<ts.TypeElement> {
165
+ const elements: Array<ts.TypeElement> = []
166
+
167
+ if (node.additionalProperties && node.additionalProperties !== true) {
168
+ const additionalType = print(node.additionalProperties) ?? factory.keywordTypeNodes.unknown
169
+
170
+ elements.push(factory.createIndexSignature(propertyCount > 0 ? factory.keywordTypeNodes.unknown : additionalType))
171
+ } else if (node.additionalProperties === true) {
172
+ elements.push(factory.createIndexSignature(factory.keywordTypeNodes.unknown))
173
+ }
174
+
175
+ if (node.patternProperties) {
176
+ const first = Object.values(node.patternProperties)[0]
177
+ if (first) {
178
+ let patternType = print(first) ?? factory.keywordTypeNodes.unknown
179
+
180
+ if (first.nullable) {
181
+ patternType = factory.createUnionDeclaration({ nodes: [patternType, factory.keywordTypeNodes.null] })
182
+ }
183
+ elements.push(factory.createIndexSignature(patternType))
184
+ }
185
+ }
186
+
187
+ return elements
188
+ }
189
+
190
+ /**
191
+ * TypeScript type printer built with `definePrinter`.
192
+ *
193
+ * Converts a `SchemaNode` AST node into a TypeScript AST node:
194
+ * - **`printer.print(node)`** — when `options.typeName` is set, returns a full
195
+ * `type Name = …` or `interface Name { … }` declaration (`ts.Node`).
196
+ * Without `typeName`, returns the raw `ts.TypeNode` for the schema.
197
+ *
198
+ * Dispatches on `node.type` to the appropriate handler in `nodes`. Options are closed
199
+ * over per printer instance, so each call to `printerTs(options)` produces an independent printer.
200
+ *
201
+ * @example Raw type node (no `typeName`)
202
+ * ```ts
203
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enumType: 'inlineLiteral' })
204
+ * const typeNode = printer.print(schemaNode) // ts.TypeNode
205
+ * ```
206
+ *
207
+ * @example Full declaration (with `typeName`)
208
+ * ```ts
209
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enumType: 'inlineLiteral', typeName: 'MyType' })
210
+ * const declaration = printer.print(schemaNode) // ts.TypeAliasDeclaration | ts.InterfaceDeclaration
211
+ * ```
212
+ */
213
+ export const printerTs = definePrinter<TsPrinter>((options) => {
214
+ const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(options.optionalType)
215
+
216
+ return {
217
+ name: 'typescript',
218
+ options,
219
+ nodes: {
220
+ any: () => factory.keywordTypeNodes.any,
221
+ unknown: () => factory.keywordTypeNodes.unknown,
222
+ void: () => factory.keywordTypeNodes.void,
223
+ never: () => factory.keywordTypeNodes.never,
224
+ boolean: () => factory.keywordTypeNodes.boolean,
225
+ null: () => factory.keywordTypeNodes.null,
226
+ blob: () => factory.createTypeReferenceNode('Blob', []),
227
+ string: () => factory.keywordTypeNodes.string,
228
+ uuid: () => factory.keywordTypeNodes.string,
229
+ email: () => factory.keywordTypeNodes.string,
230
+ url: (node) => {
231
+ if (node.path) {
232
+ return factory.createUrlTemplateType(node.path)
233
+ }
234
+ return factory.keywordTypeNodes.string
235
+ },
236
+ datetime: () => factory.keywordTypeNodes.string,
237
+ number: () => factory.keywordTypeNodes.number,
238
+ integer: () => factory.keywordTypeNodes.number,
239
+ bigint: () => factory.keywordTypeNodes.bigint,
240
+ date: dateOrStringNode,
241
+ time: dateOrStringNode,
242
+ ref(node) {
243
+ if (!node.name) {
244
+ return undefined
245
+ }
246
+ // Parser-generated refs (with $ref) carry raw schema names that need resolving.
247
+ // Use the canonical name from the $ref path — node.name may have been overridden
248
+ // (e.g. by single-member allOf flatten using the property-derived child name).
249
+ // Inline refs (without $ref) from utils already carry resolved type names.
250
+ const refName = node.ref ? (node.ref.split('/').at(-1) ?? node.name) : node.name
251
+ const name = node.ref ? this.options.resolver.default(refName, 'type') : refName
252
+
253
+ return factory.createTypeReferenceNode(name, undefined)
254
+ },
255
+ enum(node) {
256
+ const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []
257
+
258
+ if (this.options.enumType === 'inlineLiteral' || !node.name) {
259
+ const literalNodes = values
260
+ .filter((v): v is string | number | boolean => v !== null)
261
+ .map((value) => constToTypeNode(value, typeof value as 'string' | 'number' | 'boolean'))
262
+ .filter(Boolean)
263
+
264
+ return factory.createUnionDeclaration({ withParentheses: true, nodes: literalNodes }) ?? undefined
265
+ }
266
+
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
269
+
270
+ return factory.createTypeReferenceNode(typeName, undefined)
271
+ },
272
+ union(node) {
273
+ const members = node.members ?? []
274
+
275
+ const hasStringLiteral = members.some((m) => {
276
+ const enumNode = narrowSchema(m, schemaTypes.enum)
277
+ return enumNode?.primitive === 'string'
278
+ })
279
+ const hasPlainString = members.some((m) => isStringType(m))
280
+
281
+ if (hasStringLiteral && hasPlainString) {
282
+ const memberNodes = members
283
+ .map((m) => {
284
+ if (isStringType(m)) {
285
+ return factory.createIntersectionDeclaration({
286
+ nodes: [factory.keywordTypeNodes.string, factory.createTypeLiteralNode([])],
287
+ withParentheses: true,
288
+ })
289
+ }
290
+
291
+ return this.transform(m)
292
+ })
293
+ .filter(Boolean)
294
+
295
+ return factory.createUnionDeclaration({ withParentheses: true, nodes: memberNodes }) ?? undefined
296
+ }
297
+
298
+ return factory.createUnionDeclaration({ withParentheses: true, nodes: buildMemberNodes(members, this.transform) }) ?? undefined
299
+ },
300
+ intersection(node) {
301
+ return factory.createIntersectionDeclaration({ withParentheses: true, nodes: buildMemberNodes(node.members, this.transform) }) ?? undefined
302
+ },
303
+ array(node) {
304
+ const itemNodes = (node.items ?? []).map((item) => this.transform(item)).filter(Boolean)
305
+
306
+ return factory.createArrayDeclaration({ nodes: itemNodes, arrayType: this.options.arrayType }) ?? undefined
307
+ },
308
+ tuple(node) {
309
+ return buildTupleNode(node, this.transform)
310
+ },
311
+ object(node) {
312
+ const { transform, options } = this
313
+
314
+ const addsQuestionToken = OPTIONAL_ADDS_QUESTION_TOKEN.has(options.optionalType)
315
+
316
+ const propertyNodes: Array<ts.TypeElement> = node.properties.map((prop) => {
317
+ const baseType = transform(prop.schema) ?? factory.keywordTypeNodes.unknown
318
+ const type = buildPropertyType(prop.schema, baseType, options.optionalType)
319
+
320
+ const propertyNode = factory.createPropertySignature({
321
+ questionToken: prop.schema.optional || prop.schema.nullish ? addsQuestionToken : false,
322
+ name: prop.name,
323
+ type,
324
+ readOnly: prop.schema.readOnly,
325
+ })
326
+
327
+ return factory.appendJSDocToNode({ node: propertyNode, comments: buildPropertyJSDocComments(prop.schema) })
328
+ })
329
+
330
+ const allElements = [...propertyNodes, ...buildIndexSignatures(node, propertyNodes.length, transform)]
331
+
332
+ if (!allElements.length) {
333
+ return factory.keywordTypeNodes.object
334
+ }
335
+
336
+ return factory.createTypeLiteralNode(allElements)
337
+ },
338
+ },
339
+ print(node) {
340
+ let type = this.transform(node)
341
+
342
+ if (!type) {
343
+ return null
344
+ }
345
+
346
+ // Apply top-level nullable / optional union modifiers.
347
+ if (node.nullable) {
348
+ type = factory.createUnionDeclaration({ nodes: [type, factory.keywordTypeNodes.null] })
349
+ }
350
+
351
+ if ((node.nullish || node.optional) && addsUndefined) {
352
+ type = factory.createUnionDeclaration({ nodes: [type, factory.keywordTypeNodes.undefined] })
353
+ }
354
+
355
+ // Without typeName, return the type node as-is (no declaration wrapping).
356
+ const { typeName, syntaxType = 'type', description, keysToOmit } = this.options
357
+ if (!typeName) {
358
+ return safePrint(type)
359
+ }
360
+
361
+ const useTypeGeneration = syntaxType === 'type' || type.kind === factory.syntaxKind.union || !!keysToOmit?.length
362
+
363
+ const typeNode = factory.createTypeDeclaration({
364
+ name: typeName,
365
+ isExportable: true,
366
+ type: keysToOmit?.length
367
+ ? factory.createOmitDeclaration({
368
+ keys: keysToOmit,
369
+ type,
370
+ nonNullable: true,
371
+ })
372
+ : type,
373
+ syntax: useTypeGeneration ? 'type' : 'interface',
374
+ comments: [
375
+ node?.title ? jsStringEscape(node.title) : undefined,
376
+ description ? `@description ${jsStringEscape(description)}` : undefined,
377
+ node?.deprecated ? '@deprecated' : undefined,
378
+ node && 'min' in node && node.min !== undefined ? `@minLength ${node.min}` : undefined,
379
+ node && 'max' in node && node.max !== undefined ? `@maxLength ${node.max}` : undefined,
380
+ node && 'pattern' in node && node.pattern ? `@pattern ${node.pattern}` : undefined,
381
+ node?.default ? `@default ${node.default}` : undefined,
382
+ node?.example ? `@example ${node.example}` : undefined,
383
+ ],
384
+ })
385
+
386
+ return safePrint(typeNode)
387
+ },
388
+ }
389
+ })
@@ -0,0 +1,2 @@
1
+ export { resolverTs } from './resolverTs.ts'
2
+ export { resolverTsLegacy } from './resolverTsLegacy.ts'
@@ -0,0 +1,107 @@
1
+ import { pascalCase } from '@internals/utils'
2
+ import { defineResolver } from '@kubb/core'
3
+ import type { PluginTs } from '../types.ts'
4
+
5
+ function resolveName(name: string, type?: 'file' | 'function' | 'type' | 'const'): string {
6
+ return pascalCase(name, { isFile: type === 'file' })
7
+ }
8
+
9
+ /**
10
+ * Resolver for `@kubb/plugin-ts` that provides the default naming and path-resolution
11
+ * helpers used by the plugin. Import this in other plugins to resolve the exact names and
12
+ * paths that `plugin-ts` generates without hardcoding the conventions.
13
+ *
14
+ * The `default` method is automatically injected by `defineResolver` — it uses `camelCase`
15
+ * for identifiers/files and `pascalCase` for type names.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { resolver } from '@kubb/plugin-ts'
20
+ *
21
+ * resolver.default('list pets', 'type') // → 'ListPets'
22
+ * resolver.resolveName('list pets status 200') // → 'listPetsStatus200'
23
+ * resolver.resolveTypedName('list pets status 200') // → 'ListPetsStatus200'
24
+ * resolver.resolvePathName('list pets', 'file') // → 'listPets'
25
+ * ```
26
+ */
27
+ export const resolverTs = defineResolver<PluginTs>(() => {
28
+ return {
29
+ name: 'default',
30
+ pluginName: 'plugin-ts',
31
+ default(name, type) {
32
+ return resolveName(name, type)
33
+ },
34
+ resolveName(name) {
35
+ return this.default(name, 'function')
36
+ },
37
+ resolveTypedName(name) {
38
+ return this.default(name, 'type')
39
+ },
40
+ resolvePathName(name, type) {
41
+ return this.default(name, type)
42
+ },
43
+ 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}`)
48
+ },
49
+ resolveResponseStatusName(node, statusCode) {
50
+ return this.resolveName(`${node.operationId} Status ${statusCode}`)
51
+ },
52
+ resolveResponseStatusTypedName(node, statusCode) {
53
+ return this.resolveTypedName(`${node.operationId} Status ${statusCode}`)
54
+ },
55
+ resolveDataName(node) {
56
+ return this.resolveName(`${node.operationId} Data`)
57
+ },
58
+ resolveDataTypedName(node) {
59
+ return this.resolveTypedName(`${node.operationId} Data`)
60
+ },
61
+ resolveRequestConfigName(node) {
62
+ return this.resolveName(`${node.operationId} RequestConfig`)
63
+ },
64
+ resolveRequestConfigTypedName(node) {
65
+ return this.resolveTypedName(`${node.operationId} RequestConfig`)
66
+ },
67
+ resolveResponsesName(node) {
68
+ return this.resolveName(`${node.operationId} Responses`)
69
+ },
70
+ resolveResponsesTypedName(node) {
71
+ return this.resolveTypedName(`${node.operationId} Responses`)
72
+ },
73
+ resolveResponseName(node) {
74
+ return this.resolveName(`${node.operationId} Response`)
75
+ },
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.")
92
+ },
93
+ resolveQueryParamsTypedName(_node) {
94
+ throw new Error(
95
+ "resolveQueryParamsTypedName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamTypedName per individual parameter instead.",
96
+ )
97
+ },
98
+ resolveHeaderParamsName(_node) {
99
+ throw new Error("resolveHeaderParamsName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamName per individual parameter instead.")
100
+ },
101
+ resolveHeaderParamsTypedName(_node) {
102
+ throw new Error(
103
+ "resolveHeaderParamsTypedName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamTypedName per individual parameter instead.",
104
+ )
105
+ },
106
+ }
107
+ })
@@ -0,0 +1,87 @@
1
+ import { defineResolver } from '@kubb/core'
2
+ import type { PluginTs } from '../types.ts'
3
+ import { resolverTs } from './resolverTs.ts'
4
+
5
+ /**
6
+ * Legacy resolver for `@kubb/plugin-ts` that reproduces the naming conventions
7
+ * used before the v2 resolver refactor. Enable via `compatibilityPreset: 'kubbV4'`
8
+ * (or by composing this resolver manually).
9
+ *
10
+ * Key differences from the default resolver:
11
+ * - Response status types: `<OperationId><StatusCode>` (e.g. `CreatePets201`) instead of `<OperationId>Status201`
12
+ * - Default/error responses: `<OperationId>Error` instead of `<OperationId>StatusDefault`
13
+ * - Request body: `<OperationId>MutationRequest` (non-GET) / `<OperationId>QueryRequest` (GET)
14
+ * - Combined responses type: `<OperationId>Mutation` / `<OperationId>Query`
15
+ * - Response union: `<OperationId>MutationResponse` / `<OperationId>QueryResponse`
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { resolverTsLegacy } from '@kubb/plugin-ts'
20
+ *
21
+ * resolverTsLegacy.resolveResponseStatusTypedName(node, 201) // → 'CreatePets201'
22
+ * resolverTsLegacy.resolveResponseStatusTypedName(node, 'default') // → 'CreatePetsError'
23
+ * resolverTsLegacy.resolveDataTypedName(node) // → 'CreatePetsMutationRequest' (POST)
24
+ * resolverTsLegacy.resolveResponsesTypedName(node) // → 'CreatePetsMutation' (POST)
25
+ * resolverTsLegacy.resolveResponseTypedName(node) // → 'CreatePetsMutationResponse' (POST)
26
+ * ```
27
+ */
28
+ export const resolverTsLegacy = defineResolver<PluginTs>(() => {
29
+ return {
30
+ ...resolverTs,
31
+ pluginName: 'plugin-ts',
32
+ resolveResponseStatusName(node, statusCode) {
33
+ if (statusCode === 'default') {
34
+ return this.resolveName(`${node.operationId} Error`)
35
+ }
36
+ return this.resolveName(`${node.operationId} ${statusCode}`)
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
+ resolveDataName(node) {
45
+ const suffix = node.method === 'GET' ? 'QueryRequest' : 'MutationRequest'
46
+ return this.resolveName(`${node.operationId} ${suffix}`)
47
+ },
48
+ resolveDataTypedName(node) {
49
+ const suffix = node.method === 'GET' ? 'QueryRequest' : 'MutationRequest'
50
+ return this.resolveTypedName(`${node.operationId} ${suffix}`)
51
+ },
52
+ resolveResponsesName(node) {
53
+ 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}`
59
+ },
60
+ resolveResponseName(node) {
61
+ const suffix = node.method === 'GET' ? 'QueryResponse' : 'MutationResponse'
62
+ return this.resolveName(`${node.operationId} ${suffix}`)
63
+ },
64
+ resolveResponseTypedName(node) {
65
+ const suffix = node.method === 'GET' ? 'QueryResponse' : 'MutationResponse'
66
+ return this.resolveTypedName(`${node.operationId} ${suffix}`)
67
+ },
68
+ resolvePathParamsName(node) {
69
+ return this.resolveName(`${node.operationId} PathParams`)
70
+ },
71
+ resolvePathParamsTypedName(node) {
72
+ return this.resolveTypedName(`${node.operationId} PathParams`)
73
+ },
74
+ resolveQueryParamsName(node) {
75
+ return this.resolveName(`${node.operationId} QueryParams`)
76
+ },
77
+ resolveQueryParamsTypedName(node) {
78
+ return this.resolveTypedName(`${node.operationId} QueryParams`)
79
+ },
80
+ resolveHeaderParamsName(node) {
81
+ return this.resolveName(`${node.operationId} HeaderParams`)
82
+ },
83
+ resolveHeaderParamsTypedName(node) {
84
+ return this.resolveTypedName(`${node.operationId} HeaderParams`)
85
+ },
86
+ }
87
+ })