@kubb/plugin-ts 5.0.0-alpha.12 → 5.0.0-alpha.14

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 (47) hide show
  1. package/dist/{Type-CX1HRooG.js → Type-C8EHVKjc.js} +6 -84
  2. package/dist/Type-C8EHVKjc.js.map +1 -0
  3. package/dist/{Type-Cat0_htq.cjs → Type-DrOq6-nh.cjs} +11 -139
  4. package/dist/Type-DrOq6-nh.cjs.map +1 -0
  5. package/dist/casing-Cp-jbC_k.js +84 -0
  6. package/dist/casing-Cp-jbC_k.js.map +1 -0
  7. package/dist/casing-D2uQKLWS.cjs +144 -0
  8. package/dist/casing-D2uQKLWS.cjs.map +1 -0
  9. package/dist/components.cjs +1 -1
  10. package/dist/components.d.ts +2 -1
  11. package/dist/components.js +1 -1
  12. package/dist/{generators-DWBU-MuW.cjs → generators-B6JGhHkV.cjs} +54 -33
  13. package/dist/generators-B6JGhHkV.cjs.map +1 -0
  14. package/dist/{generators-CLuCmfUz.js → generators-BTTcjgbY.js} +52 -31
  15. package/dist/generators-BTTcjgbY.js.map +1 -0
  16. package/dist/generators.cjs +1 -1
  17. package/dist/generators.d.ts +1 -1
  18. package/dist/generators.js +1 -1
  19. package/dist/index-B5pSjbZv.d.ts +51 -0
  20. package/dist/index.cjs +15 -191
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.ts +3 -46
  23. package/dist/index.js +11 -187
  24. package/dist/index.js.map +1 -1
  25. package/dist/resolvers-C_vYX56l.js +183 -0
  26. package/dist/resolvers-C_vYX56l.js.map +1 -0
  27. package/dist/resolvers-DDZC7d43.cjs +193 -0
  28. package/dist/resolvers-DDZC7d43.cjs.map +1 -0
  29. package/dist/resolvers.cjs +4 -0
  30. package/dist/resolvers.d.ts +2 -0
  31. package/dist/resolvers.js +2 -0
  32. package/dist/{types-BA1ZCQ5p.d.ts → types-D9zzvE0V.d.ts} +40 -16
  33. package/package.json +12 -5
  34. package/src/components/Type.tsx +1 -0
  35. package/src/generators/typeGenerator.tsx +33 -14
  36. package/src/generators/utils.ts +18 -9
  37. package/src/index.ts +2 -2
  38. package/src/plugin.ts +55 -69
  39. package/src/printer.ts +5 -2
  40. package/src/resolvers/index.ts +2 -0
  41. package/src/{resolverTs.ts → resolvers/resolverTs.ts} +6 -89
  42. package/src/resolvers/resolverTsLegacy.ts +86 -0
  43. package/src/types.ts +39 -15
  44. package/dist/Type-CX1HRooG.js.map +0 -1
  45. package/dist/Type-Cat0_htq.cjs.map +0 -1
  46. package/dist/generators-CLuCmfUz.js.map +0 -1
  47. package/dist/generators-DWBU-MuW.cjs.map +0 -1
package/src/plugin.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import path from 'node:path'
2
2
  import { camelCase } from '@internals/utils'
3
3
  import { walk } from '@kubb/ast'
4
- import { createPlugin, type Group, getBarrelFiles, getMode, renderOperation, renderSchema } from '@kubb/core'
5
- import { typeGenerator } from './generators'
6
- import { resolverTs, resolverTsLegacy } from './resolverTs.ts'
4
+ import { createPlugin, type Group, getBarrelFiles, getMode, mergeResolvers, renderOperation, renderSchema } from '@kubb/core'
5
+ import { typeGenerator } from './generators/index.ts'
6
+ import { resolverTs, resolverTsLegacy } from './resolvers/index.ts'
7
7
  import type { PluginTs } from './types.ts'
8
8
 
9
9
  export const pluginTsName = 'plugin-ts' satisfies PluginTs['name']
@@ -20,27 +20,15 @@ export const pluginTs = createPlugin<PluginTs>((options) => {
20
20
  optionalType = 'questionToken',
21
21
  arrayType = 'array',
22
22
  syntaxType = 'type',
23
- transformers = {},
24
23
  paramsCasing,
25
24
  generators = [typeGenerator].filter(Boolean),
26
25
  legacy = false,
26
+ resolvers: userResolvers,
27
+ transformers = [],
27
28
  } = options
28
29
 
29
30
  const baseResolver = legacy ? resolverTsLegacy : resolverTs
30
-
31
- // When a `transformers.name` callback is provided, wrap the resolver so that
32
- // every name produced by `default()` (and therefore by every helper that calls
33
- // `this.default(...)`) flows through the user's transformer.
34
- const resolver: typeof baseResolver = transformers?.name
35
- ? {
36
- ...baseResolver,
37
- default(name, type) {
38
- const resolved = baseResolver.default(name, type)
39
-
40
- return transformers.name!(resolved, type) || resolved
41
- },
42
- }
43
- : baseResolver
31
+ const resolver = mergeResolvers(...(userResolvers ?? [baseResolver]))
44
32
 
45
33
  let resolveNameWarning = false
46
34
 
@@ -48,7 +36,6 @@ export const pluginTs = createPlugin<PluginTs>((options) => {
48
36
  name: pluginTsName,
49
37
  options: {
50
38
  output,
51
- transformers,
52
39
  optionalType,
53
40
  arrayType,
54
41
  enumType,
@@ -59,6 +46,8 @@ export const pluginTs = createPlugin<PluginTs>((options) => {
59
46
  paramsCasing,
60
47
  legacy,
61
48
  resolver,
49
+ baseResolver,
50
+ transformers,
62
51
  },
63
52
  resolvePath(baseName, pathMode, options) {
64
53
  const root = path.resolve(this.config.root, this.config.output.path)
@@ -114,60 +103,57 @@ export const pluginTs = createPlugin<PluginTs>((options) => {
114
103
 
115
104
  await openInStudio({ ast: true })
116
105
 
117
- await walk(
118
- rootNode,
119
- {
120
- async schema(schemaNode) {
121
- const writeTasks = generators.map(async (generator) => {
122
- if (generator.type === 'react' && generator.version === '2') {
123
- const options = resolver.resolveOptions(schemaNode, { options: plugin.options, exclude, include, override })
124
-
125
- if (options === null) {
126
- return
127
- }
128
-
129
- await renderSchema(schemaNode, {
130
- options,
131
- adapter,
132
- config,
133
- fabric,
134
- Component: generator.Schema,
135
- plugin,
136
- driver,
137
- mode,
138
- })
106
+ await walk(rootNode, {
107
+ depth: 'shallow',
108
+ async schema(schemaNode) {
109
+ const writeTasks = generators.map(async (generator) => {
110
+ if (generator.type === 'react' && generator.version === '2') {
111
+ const options = resolver.resolveOptions(schemaNode, { options: plugin.options, exclude, include, override })
112
+
113
+ if (options === null) {
114
+ return
139
115
  }
140
- })
141
-
142
- await Promise.all(writeTasks)
143
- },
144
- async operation(operationNode) {
145
- const writeTasks = generators.map(async (generator) => {
146
- if (generator.type === 'react' && generator.version === '2') {
147
- const options = resolver.resolveOptions(operationNode, { options: plugin.options, exclude, include, override })
148
-
149
- if (options === null) {
150
- return
151
- }
152
-
153
- await renderOperation(operationNode, {
154
- options,
155
- adapter,
156
- config,
157
- fabric,
158
- Component: generator.Operation,
159
- plugin,
160
- driver,
161
- mode,
162
- })
116
+
117
+ await renderSchema(schemaNode, {
118
+ options,
119
+ adapter,
120
+ config,
121
+ fabric,
122
+ Component: generator.Schema,
123
+ plugin,
124
+ driver,
125
+ mode,
126
+ })
127
+ }
128
+ })
129
+
130
+ await Promise.all(writeTasks)
131
+ },
132
+ async operation(operationNode) {
133
+ const writeTasks = generators.map(async (generator) => {
134
+ if (generator.type === 'react' && generator.version === '2') {
135
+ const options = resolver.resolveOptions(operationNode, { options: plugin.options, exclude, include, override })
136
+
137
+ if (options === null) {
138
+ return
163
139
  }
164
- })
165
140
 
166
- await Promise.all(writeTasks)
167
- },
141
+ await renderOperation(operationNode, {
142
+ options,
143
+ adapter,
144
+ config,
145
+ fabric,
146
+ Component: generator.Operation,
147
+ plugin,
148
+ driver,
149
+ mode,
150
+ })
151
+ }
152
+ })
153
+
154
+ await Promise.all(writeTasks)
168
155
  },
169
- { depth: 'shallow' },
170
- )
156
+ })
171
157
 
172
158
  const barrelFiles = await getBarrelFiles(this.fabric.files, {
173
159
  type: output.barrelType ?? 'named',
package/src/printer.ts CHANGED
@@ -134,11 +134,14 @@ function buildPropertyType(schema: SchemaNode, baseType: ts.TypeNode, optionalTy
134
134
  * Collects JSDoc annotation strings (description, deprecated, min/max, pattern, default, example, type) for a schema node.
135
135
  */
136
136
  function buildPropertyJSDocComments(schema: SchemaNode): Array<string | undefined> {
137
+ const isArray = schema.type === 'array'
138
+
137
139
  return [
138
140
  'description' in schema && schema.description ? `@description ${jsStringEscape(schema.description)}` : undefined,
139
141
  'deprecated' in schema && schema.deprecated ? '@deprecated' : undefined,
140
- 'min' in schema && schema.min !== undefined ? `@minLength ${schema.min}` : undefined,
141
- 'max' in schema && schema.max !== undefined ? `@maxLength ${schema.max}` : undefined,
142
+ // minItems/maxItems on arrays should not be emitted as @minLength/@maxLength
143
+ !isArray && 'min' in schema && schema.min !== undefined ? `@minLength ${schema.min}` : undefined,
144
+ !isArray && 'max' in schema && schema.max !== undefined ? `@maxLength ${schema.max}` : undefined,
142
145
  'pattern' in schema && schema.pattern ? `@pattern ${schema.pattern}` : undefined,
143
146
  'default' in schema && schema.default !== undefined
144
147
  ? `@default ${'primitive' in schema && schema.primitive === 'string' ? stringify(schema.default as string) : schema.default}`
@@ -0,0 +1,2 @@
1
+ export { resolverTs } from './resolverTs.ts'
2
+ export { resolverTsLegacy } from './resolverTsLegacy.ts'
@@ -1,6 +1,6 @@
1
1
  import { pascalCase } from '@internals/utils'
2
2
  import { defineResolver } from '@kubb/core'
3
- import type { PluginTs } from './types.ts'
3
+ import type { PluginTs } from '../types.ts'
4
4
 
5
5
  function resolveName(name: string, type?: 'file' | 'function' | 'type' | 'const'): string {
6
6
  return pascalCase(name, { isFile: type === 'file' })
@@ -26,6 +26,7 @@ function resolveName(name: string, type?: 'file' | 'function' | 'type' | 'const'
26
26
  */
27
27
  export const resolverTs = defineResolver<PluginTs>(() => {
28
28
  return {
29
+ name: 'default',
29
30
  default(name, type) {
30
31
  return resolveName(name, type)
31
32
  },
@@ -83,13 +84,11 @@ export const resolverTs = defineResolver<PluginTs>(() => {
83
84
  resolvePathParamsTypedName(_node) {
84
85
  throw new Error('resolvePathParamsTypedName is only available in legacy mode (legacy: true). Use resolveParamTypedName per individual parameter instead.')
85
86
  },
86
- resolveQueryParamsName(_node) {
87
- throw new Error('resolveQueryParamsName is only available in legacy mode (legacy: true). Use resolveParamName per individual parameter instead.')
87
+ resolveQueryParamsName(node) {
88
+ return this.resolveName(`${node.operationId} QueryParams`)
88
89
  },
89
- resolveQueryParamsTypedName(_node) {
90
- throw new Error(
91
- 'resolveQueryParamsTypedName is only available in legacy mode (legacy: true). Use resolveParamTypedName per individual parameter instead.',
92
- )
90
+ resolveQueryParamsTypedName(node) {
91
+ return this.resolveTypedName(`${node.operationId} QueryParams`)
93
92
  },
94
93
  resolveHeaderParamsName(_node) {
95
94
  throw new Error('resolveHeaderParamsName is only available in legacy mode (legacy: true). Use resolveParamName per individual parameter instead.')
@@ -101,85 +100,3 @@ export const resolverTs = defineResolver<PluginTs>(() => {
101
100
  },
102
101
  }
103
102
  })
104
-
105
- /**
106
- * Legacy resolver for `@kubb/plugin-ts` that reproduces the naming conventions
107
- * used before the v2 resolver refactor. Enable via `legacy: true` in plugin options.
108
- *
109
- * Key differences from the default resolver:
110
- * - Response status types: `<OperationId><StatusCode>` (e.g. `CreatePets201`) instead of `<OperationId>Status201`
111
- * - Default/error responses: `<OperationId>Error` instead of `<OperationId>StatusDefault`
112
- * - Request body: `<OperationId>MutationRequest` (non-GET) / `<OperationId>QueryRequest` (GET)
113
- * - Combined responses type: `<OperationId>Mutation` / `<OperationId>Query`
114
- * - Response union: `<OperationId>MutationResponse` / `<OperationId>QueryResponse`
115
- *
116
- * @example
117
- * ```ts
118
- * import { resolverTsLegacy } from '@kubb/plugin-ts'
119
- *
120
- * resolverTsLegacy.resolveResponseStatusTypedName(node, 201) // → 'CreatePets201'
121
- * resolverTsLegacy.resolveResponseStatusTypedName(node, 'default') // → 'CreatePetsError'
122
- * resolverTsLegacy.resolveDataTypedName(node) // → 'CreatePetsMutationRequest' (POST)
123
- * resolverTsLegacy.resolveResponsesTypedName(node) // → 'CreatePetsMutation' (POST)
124
- * resolverTsLegacy.resolveResponseTypedName(node) // → 'CreatePetsMutationResponse' (POST)
125
- * ```
126
- */
127
- export const resolverTsLegacy = defineResolver<PluginTs>(() => {
128
- return {
129
- ...resolverTs,
130
- resolveResponseStatusName(node, statusCode) {
131
- if (statusCode === 'default') {
132
- return this.resolveName(`${node.operationId} Error`)
133
- }
134
- return this.resolveName(`${node.operationId} ${statusCode}`)
135
- },
136
- resolveResponseStatusTypedName(node, statusCode) {
137
- if (statusCode === 'default') {
138
- return this.resolveTypedName(`${node.operationId} Error`)
139
- }
140
- return this.resolveTypedName(`${node.operationId} ${statusCode}`)
141
- },
142
- resolveDataName(node) {
143
- const suffix = node.method === 'GET' ? 'QueryRequest' : 'MutationRequest'
144
- return this.resolveName(`${node.operationId} ${suffix}`)
145
- },
146
- resolveDataTypedName(node) {
147
- const suffix = node.method === 'GET' ? 'QueryRequest' : 'MutationRequest'
148
- return this.resolveTypedName(`${node.operationId} ${suffix}`)
149
- },
150
- resolveResponsesName(node) {
151
- const suffix = node.method === 'GET' ? 'Query' : 'Mutation'
152
- return this.resolveName(`${node.operationId} ${suffix}`)
153
- },
154
- resolveResponsesTypedName(node) {
155
- const suffix = node.method === 'GET' ? 'Query' : 'Mutation'
156
- return this.resolveTypedName(`${node.operationId} ${suffix}`)
157
- },
158
- resolveResponseName(node) {
159
- const suffix = node.method === 'GET' ? 'QueryResponse' : 'MutationResponse'
160
- return this.resolveName(`${node.operationId} ${suffix}`)
161
- },
162
- resolveResponseTypedName(node) {
163
- const suffix = node.method === 'GET' ? 'QueryResponse' : 'MutationResponse'
164
- return this.resolveTypedName(`${node.operationId} ${suffix}`)
165
- },
166
- resolvePathParamsName(node) {
167
- return this.resolveName(`${node.operationId} PathParams`)
168
- },
169
- resolvePathParamsTypedName(node) {
170
- return this.resolveTypedName(`${node.operationId} PathParams`)
171
- },
172
- resolveQueryParamsName(node) {
173
- return this.resolveName(`${node.operationId} QueryParams`)
174
- },
175
- resolveQueryParamsTypedName(node) {
176
- return this.resolveTypedName(`${node.operationId} QueryParams`)
177
- },
178
- resolveHeaderParamsName(node) {
179
- return this.resolveName(`${node.operationId} HeaderParams`)
180
- },
181
- resolveHeaderParamsTypedName(node) {
182
- return this.resolveTypedName(`${node.operationId} HeaderParams`)
183
- },
184
- }
185
- })
@@ -0,0 +1,86 @@
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 `legacy: true` in plugin options.
8
+ *
9
+ * Key differences from the default resolver:
10
+ * - Response status types: `<OperationId><StatusCode>` (e.g. `CreatePets201`) instead of `<OperationId>Status201`
11
+ * - Default/error responses: `<OperationId>Error` instead of `<OperationId>StatusDefault`
12
+ * - Request body: `<OperationId>MutationRequest` (non-GET) / `<OperationId>QueryRequest` (GET)
13
+ * - Combined responses type: `<OperationId>Mutation` / `<OperationId>Query`
14
+ * - Response union: `<OperationId>MutationResponse` / `<OperationId>QueryResponse`
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { resolverTsLegacy } from '@kubb/plugin-ts'
19
+ *
20
+ * resolverTsLegacy.resolveResponseStatusTypedName(node, 201) // → 'CreatePets201'
21
+ * resolverTsLegacy.resolveResponseStatusTypedName(node, 'default') // → 'CreatePetsError'
22
+ * resolverTsLegacy.resolveDataTypedName(node) // → 'CreatePetsMutationRequest' (POST)
23
+ * resolverTsLegacy.resolveResponsesTypedName(node) // → 'CreatePetsMutation' (POST)
24
+ * resolverTsLegacy.resolveResponseTypedName(node) // → 'CreatePetsMutationResponse' (POST)
25
+ * ```
26
+ */
27
+ export const resolverTsLegacy = defineResolver<PluginTs>(() => {
28
+ return {
29
+ ...resolverTs,
30
+ name: 'legacy',
31
+ resolveResponseStatusName(node, statusCode) {
32
+ if (statusCode === 'default') {
33
+ return this.resolveName(`${node.operationId} Error`)
34
+ }
35
+ return this.resolveName(`${node.operationId} ${statusCode}`)
36
+ },
37
+ resolveResponseStatusTypedName(node, statusCode) {
38
+ if (statusCode === 'default') {
39
+ return this.resolveTypedName(`${node.operationId} Error`)
40
+ }
41
+ return this.resolveTypedName(`${node.operationId} ${statusCode}`)
42
+ },
43
+ resolveDataName(node) {
44
+ const suffix = node.method === 'GET' ? 'QueryRequest' : 'MutationRequest'
45
+ return this.resolveName(`${node.operationId} ${suffix}`)
46
+ },
47
+ resolveDataTypedName(node) {
48
+ const suffix = node.method === 'GET' ? 'QueryRequest' : 'MutationRequest'
49
+ return this.resolveTypedName(`${node.operationId} ${suffix}`)
50
+ },
51
+ resolveResponsesName(node) {
52
+ const suffix = node.method === 'GET' ? 'Query' : 'Mutation'
53
+ return `${this.default(node.operationId, 'function')}${suffix}`
54
+ },
55
+ resolveResponsesTypedName(node) {
56
+ const suffix = node.method === 'GET' ? 'Query' : 'Mutation'
57
+ return `${this.default(node.operationId, 'type')}${suffix}`
58
+ },
59
+ resolveResponseName(node) {
60
+ const suffix = node.method === 'GET' ? 'QueryResponse' : 'MutationResponse'
61
+ return this.resolveName(`${node.operationId} ${suffix}`)
62
+ },
63
+ resolveResponseTypedName(node) {
64
+ const suffix = node.method === 'GET' ? 'QueryResponse' : 'MutationResponse'
65
+ return this.resolveTypedName(`${node.operationId} ${suffix}`)
66
+ },
67
+ resolvePathParamsName(node) {
68
+ return this.resolveName(`${node.operationId} PathParams`)
69
+ },
70
+ resolvePathParamsTypedName(node) {
71
+ return this.resolveTypedName(`${node.operationId} PathParams`)
72
+ },
73
+ resolveQueryParamsName(node) {
74
+ return this.resolveName(`${node.operationId} QueryParams`)
75
+ },
76
+ resolveQueryParamsTypedName(node) {
77
+ return this.resolveTypedName(`${node.operationId} QueryParams`)
78
+ },
79
+ resolveHeaderParamsName(node) {
80
+ return this.resolveName(`${node.operationId} HeaderParams`)
81
+ },
82
+ resolveHeaderParamsTypedName(node) {
83
+ return this.resolveTypedName(`${node.operationId} HeaderParams`)
84
+ },
85
+ }
86
+ })
package/src/types.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { OperationNode, ParameterNode, SchemaNode, StatusCode } from '@kubb/ast/types'
2
- import type { Group, Output, PluginFactoryOptions, ResolveNameParams, Resolver } from '@kubb/core'
1
+ import type { OperationNode, ParameterNode, SchemaNode, StatusCode, Visitor } from '@kubb/ast/types'
2
+ import type { Group, Output, PluginFactoryOptions, Resolver } from '@kubb/core'
3
3
  import type { contentType, Oas } from '@kubb/oas'
4
4
  import type { Exclude, Include, Override, ResolvePathOptions } from '@kubb/plugin-oas'
5
5
  import type { Generator } from '@kubb/plugin-oas/generators'
@@ -260,12 +260,6 @@ export type Options = {
260
260
  * @default 'array'
261
261
  */
262
262
  arrayType?: 'generic' | 'array'
263
- transformers?: {
264
- /**
265
- * Customize the names based on the type that is provided by the plugin.
266
- */
267
- name?: (name: ResolveNameParams['name'], type?: ResolveNameParams['type']) => string
268
- }
269
263
  /**
270
264
  * How to style your params, by default no casing is applied
271
265
  * - 'camelcase' uses camelCase for pathParams, queryParams and headerParams property names
@@ -283,15 +277,39 @@ export type Options = {
283
277
  UNSTABLE_NAMING?: true
284
278
  /**
285
279
  * Enable legacy naming conventions for backwards compatibility.
286
- * When enabled, operation-level types use the old naming scheme:
287
- * - GET responses → `<OperationId>QueryResponse`, `<OperationId>Query`
288
- * - Non-GET responses → `<OperationId>MutationResponse`, `<OperationId>Mutation`
289
- * - Request body → `<OperationId>QueryRequest` / `<OperationId>MutationRequest`
290
- * - Response status codes → `<OperationId><StatusCode>` (e.g. `CreatePets201`)
291
- * - Default/error response → `<OperationId>Error`
292
280
  * @default false
293
281
  */
294
282
  legacy?: boolean
283
+ /**
284
+ * Array of named resolvers that control naming conventions.
285
+ * Later entries override earlier ones (last wins).
286
+ * Built-in: `resolverTs` (default), `resolverTsLegacy`.
287
+ * @default [resolverTs]
288
+ */
289
+ resolvers?: Array<ResolverTs>
290
+ /**
291
+ * Array of AST visitors applied to each SchemaNode/OperationNode before printing.
292
+ * Uses `transform()` from `@kubb/ast` — visitors can modify, replace, or annotate nodes.
293
+ *
294
+ * @example Remove writeOnly properties from response types
295
+ * ```ts
296
+ * transformers: [{
297
+ * property(node) {
298
+ * if (node.schema.writeOnly) return undefined
299
+ * }
300
+ * }]
301
+ * ```
302
+ *
303
+ * @example Force all dates to plain strings
304
+ * ```ts
305
+ * transformers: [{
306
+ * schema(node) {
307
+ * if (node.type === 'date') return { ...node, type: 'string' }
308
+ * }
309
+ * }]
310
+ * ```
311
+ */
312
+ transformers?: Array<Visitor>
295
313
  }
296
314
 
297
315
  type ResolvedOptions = {
@@ -302,11 +320,17 @@ type ResolvedOptions = {
302
320
  enumKeyCasing: NonNullable<Options['enumKeyCasing']>
303
321
  optionalType: NonNullable<Options['optionalType']>
304
322
  arrayType: NonNullable<Options['arrayType']>
305
- transformers: NonNullable<Options['transformers']>
306
323
  syntaxType: NonNullable<Options['syntaxType']>
307
324
  paramsCasing: Options['paramsCasing']
308
325
  legacy: NonNullable<Options['legacy']>
309
326
  resolver: ResolverTs
327
+ /**
328
+ * The resolver without user naming overrides applied.
329
+ * Used internally to derive stable names for unnamed enums and grouped params
330
+ * so that the schema tree stays consistent regardless of `transformers.name` / custom resolvers.
331
+ */
332
+ baseResolver: ResolverTs
333
+ transformers: Array<Visitor>
310
334
  }
311
335
 
312
336
  export type PluginTs = PluginFactoryOptions<'plugin-ts', Options, ResolvedOptions, never, ResolvePathOptions, ResolverTs>