@kubb/plugin-ts 5.0.0-alpha.23 → 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.
- package/dist/index.cjs +21 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +97 -34
- package/dist/index.js +21 -9
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/Enum.tsx +1 -6
- package/src/components/Type.tsx +8 -0
- package/src/generators/typeGenerator.tsx +26 -2
- package/src/printers/printerTs.ts +17 -1
- package/src/types.ts +88 -33
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/plugin-ts",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.24",
|
|
4
4
|
"description": "TypeScript code generation plugin for Kubb, transforming OpenAPI schemas into TypeScript interfaces, types, and utility functions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
"@kubb/react-fabric": "0.15.1",
|
|
54
54
|
"remeda": "^2.33.6",
|
|
55
55
|
"typescript": "5.9.3",
|
|
56
|
-
"@kubb/ast": "5.0.0-alpha.
|
|
57
|
-
"@kubb/core": "5.0.0-alpha.
|
|
56
|
+
"@kubb/ast": "5.0.0-alpha.24",
|
|
57
|
+
"@kubb/core": "5.0.0-alpha.24"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@kubb/react-fabric": "0.15.1"
|
package/src/components/Enum.tsx
CHANGED
|
@@ -35,17 +35,12 @@ export function getEnumNames({
|
|
|
35
35
|
}): {
|
|
36
36
|
enumName: string
|
|
37
37
|
typeName: string
|
|
38
|
-
/**
|
|
39
|
-
* The PascalCase name that `$ref` importers will use to reference this enum type.
|
|
40
|
-
* For `asConst`/`asPascalConst` this differs from `typeName` (which has a `Key` suffix).
|
|
41
|
-
*/
|
|
42
|
-
refName: string
|
|
43
38
|
} {
|
|
44
39
|
const resolved = resolver.default(node.name!, 'type')
|
|
45
40
|
const enumName = enumType === 'asPascalConst' ? resolved : camelCase(node.name!)
|
|
46
41
|
const typeName = ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) ? resolver.resolveEnumKeyName(node, enumTypeSuffix) : resolved
|
|
47
42
|
|
|
48
|
-
return { enumName, typeName
|
|
43
|
+
return { enumName, typeName }
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
/**
|
package/src/components/Type.tsx
CHANGED
|
@@ -18,6 +18,12 @@ type Props = {
|
|
|
18
18
|
resolver: PluginTs['resolver']
|
|
19
19
|
description?: string
|
|
20
20
|
keysToOmit?: string[]
|
|
21
|
+
/**
|
|
22
|
+
* Names of top-level schemas that are enums.
|
|
23
|
+
* Used so the printer's `ref` handler can use the suffixed type name (e.g. `StatusKey`)
|
|
24
|
+
* instead of the plain PascalCase name (e.g. `Status`) when resolving `$ref` enum targets.
|
|
25
|
+
*/
|
|
26
|
+
enumSchemaNames?: Set<string>
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
export function Type({
|
|
@@ -32,6 +38,7 @@ export function Type({
|
|
|
32
38
|
enumKeyCasing,
|
|
33
39
|
description,
|
|
34
40
|
resolver,
|
|
41
|
+
enumSchemaNames,
|
|
35
42
|
}: Props): FabricReactNode {
|
|
36
43
|
const resolvedDescription = description || node?.description
|
|
37
44
|
const enumSchemaNodes = collect<EnumSchemaNode>(node, {
|
|
@@ -51,6 +58,7 @@ export function Type({
|
|
|
51
58
|
description: resolvedDescription,
|
|
52
59
|
keysToOmit,
|
|
53
60
|
resolver,
|
|
61
|
+
enumSchemaNames,
|
|
54
62
|
})
|
|
55
63
|
const output = printer.print(node)
|
|
56
64
|
|
|
@@ -21,6 +21,17 @@ export const typeGenerator = defineGenerator<PluginTs>({
|
|
|
21
21
|
|
|
22
22
|
const params = caseParams(node.parameters, paramsCasing)
|
|
23
23
|
|
|
24
|
+
// Build a set of schema names that are enums so the ref handler and getImports
|
|
25
|
+
// callback can use the suffixed type name (e.g. `StatusKey`) for those refs.
|
|
26
|
+
const enumSchemaNames = new Set((adapter.rootNode?.schemas ?? []).filter((s) => narrowSchema(s, schemaTypes.enum) && s.name).map((s) => s.name!))
|
|
27
|
+
|
|
28
|
+
function resolveImportName(schemaName: string): string {
|
|
29
|
+
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && enumTypeSuffix && enumSchemaNames.has(schemaName)) {
|
|
30
|
+
return resolver.resolveEnumKeyName({ name: schemaName } as SchemaNode, enumTypeSuffix)
|
|
31
|
+
}
|
|
32
|
+
return resolver.default(schemaName, 'type')
|
|
33
|
+
}
|
|
34
|
+
|
|
24
35
|
function renderSchemaType({
|
|
25
36
|
node: schemaNode,
|
|
26
37
|
name,
|
|
@@ -39,7 +50,7 @@ export const typeGenerator = defineGenerator<PluginTs>({
|
|
|
39
50
|
const transformedNode = transform(schemaNode, composeTransformers(...transformers))
|
|
40
51
|
|
|
41
52
|
const imports = adapter.getImports(transformedNode, (schemaName) => ({
|
|
42
|
-
name:
|
|
53
|
+
name: resolveImportName(schemaName),
|
|
43
54
|
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
|
|
44
55
|
}))
|
|
45
56
|
|
|
@@ -59,6 +70,7 @@ export const typeGenerator = defineGenerator<PluginTs>({
|
|
|
59
70
|
syntaxType={syntaxType}
|
|
60
71
|
resolver={resolver}
|
|
61
72
|
keysToOmit={keysToOmit}
|
|
73
|
+
enumSchemaNames={enumSchemaNames}
|
|
62
74
|
/>
|
|
63
75
|
</>
|
|
64
76
|
)
|
|
@@ -134,8 +146,19 @@ export const typeGenerator = defineGenerator<PluginTs>({
|
|
|
134
146
|
|
|
135
147
|
const transformedNode = transform(node, composeTransformers(...transformers))
|
|
136
148
|
|
|
149
|
+
// Build a set of schema names that are enums so the ref handler and getImports
|
|
150
|
+
// callback can use the suffixed type name (e.g. `StatusKey`) for those refs.
|
|
151
|
+
const enumSchemaNames = new Set((adapter.rootNode?.schemas ?? []).filter((s) => narrowSchema(s, schemaTypes.enum) && s.name).map((s) => s.name!))
|
|
152
|
+
|
|
153
|
+
function resolveImportName(schemaName: string): string {
|
|
154
|
+
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && enumTypeSuffix && enumSchemaNames.has(schemaName)) {
|
|
155
|
+
return resolver.resolveEnumKeyName({ name: schemaName } as SchemaNode, enumTypeSuffix)
|
|
156
|
+
}
|
|
157
|
+
return resolver.default(schemaName, 'type')
|
|
158
|
+
}
|
|
159
|
+
|
|
137
160
|
const imports = adapter.getImports(transformedNode, (schemaName) => ({
|
|
138
|
-
name:
|
|
161
|
+
name: resolveImportName(schemaName),
|
|
139
162
|
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
|
|
140
163
|
}))
|
|
141
164
|
|
|
@@ -170,6 +193,7 @@ export const typeGenerator = defineGenerator<PluginTs>({
|
|
|
170
193
|
arrayType={arrayType}
|
|
171
194
|
syntaxType={syntaxType}
|
|
172
195
|
resolver={resolver}
|
|
196
|
+
enumSchemaNames={enumSchemaNames}
|
|
173
197
|
/>
|
|
174
198
|
</File>
|
|
175
199
|
)
|
|
@@ -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
|
-
|
|
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
|
},
|
package/src/types.ts
CHANGED
|
@@ -100,6 +100,92 @@ export type ResolverTs = Resolver &
|
|
|
100
100
|
resolveHeaderParamsName(node: OperationNode, param: ParameterNode): string
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
type EnumKeyCasing = 'screamingSnakeCase' | 'snakeCase' | 'pascalCase' | 'camelCase' | 'none'
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Discriminated union that ties `enumTypeSuffix` and `enumKeyCasing` to the enum types that actually use them.
|
|
107
|
+
*
|
|
108
|
+
* - `'asConst'` / `'asPascalConst'` — emit a `const` object; both `enumTypeSuffix` (type-alias suffix) and
|
|
109
|
+
* `enumKeyCasing` (key formatting) are meaningful.
|
|
110
|
+
* - `'enum'` / `'constEnum'` — emit a TypeScript enum; `enumKeyCasing` applies to member names,
|
|
111
|
+
* but there is no separate type alias so `enumTypeSuffix` is not used.
|
|
112
|
+
* - `'literal'` / `'inlineLiteral'` — emit only union literals; keys are discarded entirely,
|
|
113
|
+
* so neither `enumTypeSuffix` nor `enumKeyCasing` have any effect.
|
|
114
|
+
*/
|
|
115
|
+
type EnumTypeOptions =
|
|
116
|
+
| {
|
|
117
|
+
/**
|
|
118
|
+
* Choose to use enum, asConst, asPascalConst, constEnum, literal, or inlineLiteral for enums.
|
|
119
|
+
* - 'asConst' generates const objects with camelCase names and as const assertion.
|
|
120
|
+
* - 'asPascalConst' generates const objects with PascalCase names and as const assertion.
|
|
121
|
+
* @default 'asConst'
|
|
122
|
+
*/
|
|
123
|
+
enumType?: 'asConst' | 'asPascalConst'
|
|
124
|
+
/**
|
|
125
|
+
* Suffix appended to the generated type alias name.
|
|
126
|
+
*
|
|
127
|
+
* Only affects the type alias — the const object name is unchanged.
|
|
128
|
+
*
|
|
129
|
+
* @default 'Key'
|
|
130
|
+
* @example enumTypeSuffix: 'Value' → `export type PetStatusValue = …`
|
|
131
|
+
*/
|
|
132
|
+
enumTypeSuffix?: string
|
|
133
|
+
/**
|
|
134
|
+
* Choose the casing for enum key names.
|
|
135
|
+
* - 'screamingSnakeCase' generates keys in SCREAMING_SNAKE_CASE format.
|
|
136
|
+
* - 'snakeCase' generates keys in snake_case format.
|
|
137
|
+
* - 'pascalCase' generates keys in PascalCase format.
|
|
138
|
+
* - 'camelCase' generates keys in camelCase format.
|
|
139
|
+
* - 'none' uses the enum value as-is without transformation.
|
|
140
|
+
* @default 'none'
|
|
141
|
+
*/
|
|
142
|
+
enumKeyCasing?: EnumKeyCasing
|
|
143
|
+
}
|
|
144
|
+
| {
|
|
145
|
+
/**
|
|
146
|
+
* Choose to use enum, asConst, asPascalConst, constEnum, literal, or inlineLiteral for enums.
|
|
147
|
+
* - 'enum' generates TypeScript enum declarations.
|
|
148
|
+
* - 'constEnum' generates TypeScript const enum declarations.
|
|
149
|
+
* @default 'asConst'
|
|
150
|
+
*/
|
|
151
|
+
enumType?: 'enum' | 'constEnum'
|
|
152
|
+
/**
|
|
153
|
+
* `enumTypeSuffix` has no effect for this `enumType`.
|
|
154
|
+
* It is only used when `enumType` is `'asConst'` or `'asPascalConst'`.
|
|
155
|
+
*/
|
|
156
|
+
enumTypeSuffix?: never
|
|
157
|
+
/**
|
|
158
|
+
* Choose the casing for enum key names.
|
|
159
|
+
* - 'screamingSnakeCase' generates keys in SCREAMING_SNAKE_CASE format.
|
|
160
|
+
* - 'snakeCase' generates keys in snake_case format.
|
|
161
|
+
* - 'pascalCase' generates keys in PascalCase format.
|
|
162
|
+
* - 'camelCase' generates keys in camelCase format.
|
|
163
|
+
* - 'none' uses the enum value as-is without transformation.
|
|
164
|
+
* @default 'none'
|
|
165
|
+
*/
|
|
166
|
+
enumKeyCasing?: EnumKeyCasing
|
|
167
|
+
}
|
|
168
|
+
| {
|
|
169
|
+
/**
|
|
170
|
+
* Choose to use enum, asConst, asPascalConst, constEnum, literal, or inlineLiteral for enums.
|
|
171
|
+
* - 'literal' generates literal union types.
|
|
172
|
+
* - 'inlineLiteral' inlines enum values directly into the type (default in v5).
|
|
173
|
+
* @default 'asConst'
|
|
174
|
+
* @note In Kubb v5, 'inlineLiteral' becomes the default.
|
|
175
|
+
*/
|
|
176
|
+
enumType?: 'literal' | 'inlineLiteral'
|
|
177
|
+
/**
|
|
178
|
+
* `enumTypeSuffix` has no effect for this `enumType`.
|
|
179
|
+
* It is only used when `enumType` is `'asConst'` or `'asPascalConst'`.
|
|
180
|
+
*/
|
|
181
|
+
enumTypeSuffix?: never
|
|
182
|
+
/**
|
|
183
|
+
* `enumKeyCasing` has no effect for this `enumType`.
|
|
184
|
+
* Literal and inlineLiteral modes emit only values — keys are discarded entirely.
|
|
185
|
+
*/
|
|
186
|
+
enumKeyCasing?: never
|
|
187
|
+
}
|
|
188
|
+
|
|
103
189
|
export type Options = {
|
|
104
190
|
/**
|
|
105
191
|
* Specify the export location for the files and define the behavior of the output
|
|
@@ -127,37 +213,6 @@ export type Options = {
|
|
|
127
213
|
* Array containing override parameters to override `options` based on tags/operations/methods/paths.
|
|
128
214
|
*/
|
|
129
215
|
override?: Array<Override<ResolvedOptions>>
|
|
130
|
-
/**
|
|
131
|
-
* Choose to use enum, asConst, asPascalConst, constEnum, literal, or inlineLiteral for enums.
|
|
132
|
-
* - 'enum' generates TypeScript enum declarations.
|
|
133
|
-
* - 'asConst' generates const objects with camelCase names and as const assertion.
|
|
134
|
-
* - 'asPascalConst' generates const objects with PascalCase names and as const assertion.
|
|
135
|
-
* - 'constEnum' generates TypeScript const enum declarations.
|
|
136
|
-
* - 'literal' generates literal union types.
|
|
137
|
-
* - 'inlineLiteral' inline enum values directly into the type (default in v5).
|
|
138
|
-
* @default 'asConst'
|
|
139
|
-
* @note In Kubb v5, 'inlineLiteral' becomes the default.
|
|
140
|
-
*/
|
|
141
|
-
enumType?: 'enum' | 'asConst' | 'asPascalConst' | 'constEnum' | 'literal' | 'inlineLiteral'
|
|
142
|
-
/**
|
|
143
|
-
* Suffix appended to the generated type alias name when `enumType` is `asConst` or `asPascalConst`.
|
|
144
|
-
*
|
|
145
|
-
* Only affects the type alias — the const object name is unchanged.
|
|
146
|
-
*
|
|
147
|
-
* @default 'Key'
|
|
148
|
-
* @example enumTypeSuffix: 'Value' → `export type PetStatusValue = …`
|
|
149
|
-
*/
|
|
150
|
-
enumTypeSuffix?: string
|
|
151
|
-
/**
|
|
152
|
-
* Choose the casing for enum key names.
|
|
153
|
-
* - 'screamingSnakeCase' generates keys in SCREAMING_SNAKE_CASE format.
|
|
154
|
-
* - 'snakeCase' generates keys in snake_case format.
|
|
155
|
-
* - 'pascalCase' generates keys in PascalCase format.
|
|
156
|
-
* - 'camelCase' generates keys in camelCase format.
|
|
157
|
-
* - 'none' uses the enum value as-is without transformation.
|
|
158
|
-
* @default 'none'
|
|
159
|
-
*/
|
|
160
|
-
enumKeyCasing?: 'screamingSnakeCase' | 'snakeCase' | 'pascalCase' | 'camelCase' | 'none'
|
|
161
216
|
/**
|
|
162
217
|
* Switch between type or interface for creating TypeScript types.
|
|
163
218
|
* - 'type' generates type alias declarations.
|
|
@@ -228,14 +283,14 @@ export type Options = {
|
|
|
228
283
|
* ```
|
|
229
284
|
*/
|
|
230
285
|
transformers?: Array<Visitor>
|
|
231
|
-
}
|
|
286
|
+
} & EnumTypeOptions
|
|
232
287
|
|
|
233
288
|
type ResolvedOptions = {
|
|
234
289
|
output: Output
|
|
235
290
|
group: Group | undefined
|
|
236
291
|
enumType: NonNullable<Options['enumType']>
|
|
237
292
|
enumTypeSuffix: NonNullable<Options['enumTypeSuffix']>
|
|
238
|
-
enumKeyCasing:
|
|
293
|
+
enumKeyCasing: EnumKeyCasing
|
|
239
294
|
optionalType: NonNullable<Options['optionalType']>
|
|
240
295
|
arrayType: NonNullable<Options['arrayType']>
|
|
241
296
|
syntaxType: NonNullable<Options['syntaxType']>
|