@kubb/plugin-ts 5.0.0-alpha.1 → 5.0.0-alpha.10
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/{components-LmqJfxMv.js → components-CRu8IKY3.js} +19 -11
- package/dist/components-CRu8IKY3.js.map +1 -0
- package/dist/{components-9wydyqUx.cjs → components-DeNDKlzf.cjs} +144 -10
- package/dist/components-DeNDKlzf.cjs.map +1 -0
- package/dist/components.cjs +1 -1
- package/dist/components.d.ts +1 -3
- package/dist/components.js +1 -1
- package/dist/generators.cjs +3 -2
- package/dist/generators.d.ts +60 -48
- package/dist/generators.js +2 -2
- package/dist/index.cjs +2 -1
- package/dist/index.d.ts +41 -2
- package/dist/index.js +2 -2
- package/dist/plugin-BZkBwnEA.js +1269 -0
- package/dist/plugin-BZkBwnEA.js.map +1 -0
- package/dist/plugin-Bunz1oGa.cjs +1322 -0
- package/dist/plugin-Bunz1oGa.cjs.map +1 -0
- package/dist/types-mSXmB8WU.d.ts +298 -0
- package/package.json +8 -8
- package/src/components/Type.tsx +0 -3
- package/src/components/v2/Enum.tsx +67 -0
- package/src/components/v2/Type.tsx +59 -0
- package/src/constants.ts +29 -0
- package/src/factory.ts +14 -16
- package/src/generators/index.ts +1 -0
- package/src/generators/typeGenerator.tsx +46 -48
- package/src/generators/v2/typeGenerator.tsx +167 -0
- package/src/generators/v2/utils.ts +140 -0
- package/src/index.ts +1 -0
- package/src/parser.ts +1 -8
- package/src/plugin.ts +64 -17
- package/src/printer.ts +238 -91
- package/src/resolverTs.ts +77 -0
- package/src/types.ts +144 -15
- package/dist/components-9wydyqUx.cjs.map +0 -1
- package/dist/components-LmqJfxMv.js.map +0 -1
- package/dist/plugin-BHE4J4aP.cjs +0 -508
- package/dist/plugin-BHE4J4aP.cjs.map +0 -1
- package/dist/plugin-DnKRpgGK.js +0 -476
- package/dist/plugin-DnKRpgGK.js.map +0 -1
- package/dist/types-BpeKGgCn.d.ts +0 -170
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { collect } from '@kubb/ast'
|
|
2
|
+
import type { EnumSchemaNode, SchemaNode } from '@kubb/ast/types'
|
|
3
|
+
import { safePrint } from '@kubb/fabric-core/parsers/typescript'
|
|
4
|
+
import { File } from '@kubb/react-fabric'
|
|
5
|
+
import type { FabricReactNode } from '@kubb/react-fabric/types'
|
|
6
|
+
import { printerTs } from '../../printer.ts'
|
|
7
|
+
import type { PluginTs } from '../../types.ts'
|
|
8
|
+
import { Enum, getEnumNames } from './Enum.tsx'
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
name: string
|
|
12
|
+
typedName: string
|
|
13
|
+
node: SchemaNode
|
|
14
|
+
optionalType: PluginTs['resolvedOptions']['optionalType']
|
|
15
|
+
arrayType: PluginTs['resolvedOptions']['arrayType']
|
|
16
|
+
enumType: PluginTs['resolvedOptions']['enumType']
|
|
17
|
+
enumKeyCasing: PluginTs['resolvedOptions']['enumKeyCasing']
|
|
18
|
+
syntaxType: PluginTs['resolvedOptions']['syntaxType']
|
|
19
|
+
description?: string
|
|
20
|
+
keysToOmit?: string[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function Type({ name, typedName, node, keysToOmit, optionalType, arrayType, syntaxType, enumType, enumKeyCasing, description }: Props): FabricReactNode {
|
|
24
|
+
const resolvedDescription = description || node?.description
|
|
25
|
+
const enumSchemaNodes = collect<EnumSchemaNode>(node, {
|
|
26
|
+
schema(n): EnumSchemaNode | undefined {
|
|
27
|
+
if (n.type === 'enum' && n.name) return n as EnumSchemaNode
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const printer = printerTs({ optionalType, arrayType, enumType, typeName: name, syntaxType, description: resolvedDescription, keysToOmit })
|
|
32
|
+
const typeNode = printer.print(node)
|
|
33
|
+
|
|
34
|
+
if (!typeNode) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const enums = [...new Map(enumSchemaNodes.map((n) => [n.name, n])).values()].map((node) => {
|
|
39
|
+
return {
|
|
40
|
+
node,
|
|
41
|
+
...getEnumNames(node, enumType),
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// Skip enum exports when using inlineLiteral
|
|
46
|
+
const shouldExportEnums = enumType !== 'inlineLiteral'
|
|
47
|
+
const shouldExportType = enumType === 'inlineLiteral' || enums.every((item) => item.typeName !== name)
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
{shouldExportEnums && enums.map(({ node }) => <Enum node={node} enumType={enumType} enumKeyCasing={enumKeyCasing} />)}
|
|
52
|
+
{shouldExportType && (
|
|
53
|
+
<File.Source name={typedName} isTypeOnly isExportable isIndexable>
|
|
54
|
+
{safePrint(typeNode)}
|
|
55
|
+
</File.Source>
|
|
56
|
+
)}
|
|
57
|
+
</>
|
|
58
|
+
)
|
|
59
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PluginTs } from './types.ts'
|
|
2
|
+
|
|
3
|
+
type OptionalType = PluginTs['resolvedOptions']['optionalType']
|
|
4
|
+
type EnumType = PluginTs['resolvedOptions']['enumType']
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `optionalType` values that cause a property's type to include `| undefined`.
|
|
8
|
+
*/
|
|
9
|
+
export const OPTIONAL_ADDS_UNDEFINED = new Set<OptionalType>(['undefined', 'questionTokenAndUndefined'] as const)
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* `optionalType` values that render the property key with a `?` token.
|
|
13
|
+
*/
|
|
14
|
+
export const OPTIONAL_ADDS_QUESTION_TOKEN = new Set<OptionalType>(['questionToken', 'questionTokenAndUndefined'] as const)
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* `enumType` values that append a `Key` suffix to the generated enum type alias.
|
|
18
|
+
*/
|
|
19
|
+
export const ENUM_TYPES_WITH_KEY_SUFFIX = new Set<EnumType>(['asConst', 'asPascalConst'] as const)
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* `enumType` values that require a runtime value declaration (object, enum, or literal).
|
|
23
|
+
*/
|
|
24
|
+
export const ENUM_TYPES_WITH_RUNTIME_VALUE = new Set<EnumType | undefined>(['enum', 'asConst', 'asPascalConst', 'constEnum', 'literal', undefined] as const)
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* `enumType` values whose type declaration is type-only (no runtime value emitted for the type alias).
|
|
28
|
+
*/
|
|
29
|
+
export const ENUM_TYPES_WITH_TYPE_ONLY = new Set<EnumType | undefined>(['asConst', 'asPascalConst', 'literal', undefined] as const)
|
package/src/factory.ts
CHANGED
|
@@ -15,6 +15,8 @@ export const modifiers = {
|
|
|
15
15
|
|
|
16
16
|
export const syntaxKind = {
|
|
17
17
|
union: SyntaxKind.UnionType as 192,
|
|
18
|
+
literalType: SyntaxKind.LiteralType,
|
|
19
|
+
stringLiteral: SyntaxKind.StringLiteral,
|
|
18
20
|
} as const
|
|
19
21
|
|
|
20
22
|
export function getUnknownType(unknownType: 'any' | 'unknown' | 'void' | undefined) {
|
|
@@ -660,43 +662,39 @@ export const keywordTypeNodes = {
|
|
|
660
662
|
* Converts a path like '/pet/{petId}/uploadImage' to a template literal type
|
|
661
663
|
* like `/pet/${string}/uploadImage`
|
|
662
664
|
*/
|
|
665
|
+
/**
|
|
666
|
+
* Converts an OAS-style path (e.g. `/pets/{petId}`) or an Express-style path
|
|
667
|
+
* (e.g. `/pets/:petId`) to a TypeScript template literal type
|
|
668
|
+
* like `` `/pets/${string}` ``.
|
|
669
|
+
*/
|
|
663
670
|
export function createUrlTemplateType(path: string): ts.TypeNode {
|
|
664
|
-
//
|
|
665
|
-
|
|
666
|
-
return factory.createLiteralTypeNode(factory.createStringLiteral(path))
|
|
667
|
-
}
|
|
671
|
+
// normalized Express `:param` → OAS `{param}` so a single regex handles both.
|
|
672
|
+
const normalized = path.replace(/:([^/]+)/g, '{$1}')
|
|
668
673
|
|
|
669
|
-
|
|
670
|
-
|
|
674
|
+
if (!normalized.includes('{')) {
|
|
675
|
+
return factory.createLiteralTypeNode(factory.createStringLiteral(normalized))
|
|
676
|
+
}
|
|
671
677
|
|
|
672
|
-
|
|
678
|
+
const segments = normalized.split(/(\{[^}]+\})/)
|
|
673
679
|
const parts: string[] = []
|
|
674
680
|
const parameterIndices: number[] = []
|
|
675
681
|
|
|
676
682
|
segments.forEach((segment) => {
|
|
677
683
|
if (segment.startsWith('{') && segment.endsWith('}')) {
|
|
678
|
-
// This is a parameter placeholder
|
|
679
684
|
parameterIndices.push(parts.length)
|
|
680
|
-
parts.push(segment)
|
|
685
|
+
parts.push(segment)
|
|
681
686
|
} else if (segment) {
|
|
682
|
-
// This is a static part
|
|
683
687
|
parts.push(segment)
|
|
684
688
|
}
|
|
685
689
|
})
|
|
686
690
|
|
|
687
|
-
// Build template literal type
|
|
688
|
-
// Template literal structure: head + templateSpans[]
|
|
689
|
-
// For '/pet/{petId}/upload': head = '/pet/', spans = [{ type: string, literal: '/upload' }]
|
|
690
|
-
|
|
691
691
|
const head = ts.factory.createTemplateHead(parts[0] || '')
|
|
692
692
|
const templateSpans: ts.TemplateLiteralTypeSpan[] = []
|
|
693
693
|
|
|
694
694
|
parameterIndices.forEach((paramIndex, i) => {
|
|
695
695
|
const isLast = i === parameterIndices.length - 1
|
|
696
696
|
const nextPart = parts[paramIndex + 1] || ''
|
|
697
|
-
|
|
698
697
|
const literal = isLast ? ts.factory.createTemplateTail(nextPart) : ts.factory.createTemplateMiddle(nextPart)
|
|
699
|
-
|
|
700
698
|
templateSpans.push(ts.factory.createTemplateLiteralTypeSpan(keywordTypeNodes.string, literal))
|
|
701
699
|
})
|
|
702
700
|
|
package/src/generators/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { pascalCase } from '@internals/utils'
|
|
2
|
-
import type {
|
|
3
|
-
import { useMode,
|
|
2
|
+
import type { PluginDriver } from '@kubb/core'
|
|
3
|
+
import { useMode, usePluginDriver } from '@kubb/core/hooks'
|
|
4
4
|
import { safePrint } from '@kubb/fabric-core/parsers/typescript'
|
|
5
5
|
import type { Operation } from '@kubb/oas'
|
|
6
6
|
import { isKeyword, type OperationSchemas, type OperationSchema as OperationSchemaType, SchemaGenerator, schemaKeywords } from '@kubb/plugin-oas'
|
|
@@ -15,15 +15,15 @@ import { createUrlTemplateType, getUnknownType, keywordTypeNodes } from '../fact
|
|
|
15
15
|
import { pluginTsName } from '../plugin.ts'
|
|
16
16
|
import type { PluginTs } from '../types'
|
|
17
17
|
|
|
18
|
-
function printCombinedSchema({ name, schemas,
|
|
18
|
+
function printCombinedSchema({ name, schemas, driver }: { name: string; schemas: OperationSchemas; driver: PluginDriver }): string {
|
|
19
19
|
const properties: Record<string, ts.TypeNode> = {}
|
|
20
20
|
|
|
21
21
|
if (schemas.response) {
|
|
22
22
|
properties['response'] = factory.createUnionDeclaration({
|
|
23
23
|
nodes: schemas.responses.map((res) => {
|
|
24
|
-
const identifier =
|
|
24
|
+
const identifier = driver.resolveName({
|
|
25
25
|
name: res.name,
|
|
26
|
-
|
|
26
|
+
pluginName: pluginTsName,
|
|
27
27
|
type: 'function',
|
|
28
28
|
})
|
|
29
29
|
|
|
@@ -33,36 +33,36 @@ function printCombinedSchema({ name, schemas, pluginManager }: { name: string; s
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
if (schemas.request) {
|
|
36
|
-
const identifier =
|
|
36
|
+
const identifier = driver.resolveName({
|
|
37
37
|
name: schemas.request.name,
|
|
38
|
-
|
|
38
|
+
pluginName: pluginTsName,
|
|
39
39
|
type: 'function',
|
|
40
40
|
})
|
|
41
41
|
properties['request'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
if (schemas.pathParams) {
|
|
45
|
-
const identifier =
|
|
45
|
+
const identifier = driver.resolveName({
|
|
46
46
|
name: schemas.pathParams.name,
|
|
47
|
-
|
|
47
|
+
pluginName: pluginTsName,
|
|
48
48
|
type: 'function',
|
|
49
49
|
})
|
|
50
50
|
properties['pathParams'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
if (schemas.queryParams) {
|
|
54
|
-
const identifier =
|
|
54
|
+
const identifier = driver.resolveName({
|
|
55
55
|
name: schemas.queryParams.name,
|
|
56
|
-
|
|
56
|
+
pluginName: pluginTsName,
|
|
57
57
|
type: 'function',
|
|
58
58
|
})
|
|
59
59
|
properties['queryParams'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
if (schemas.headerParams) {
|
|
63
|
-
const identifier =
|
|
63
|
+
const identifier = driver.resolveName({
|
|
64
64
|
name: schemas.headerParams.name,
|
|
65
|
-
|
|
65
|
+
pluginName: pluginTsName,
|
|
66
66
|
type: 'function',
|
|
67
67
|
})
|
|
68
68
|
properties['headerParams'] = factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined)
|
|
@@ -71,9 +71,9 @@ function printCombinedSchema({ name, schemas, pluginManager }: { name: string; s
|
|
|
71
71
|
if (schemas.errors) {
|
|
72
72
|
properties['errors'] = factory.createUnionDeclaration({
|
|
73
73
|
nodes: schemas.errors.map((error) => {
|
|
74
|
-
const identifier =
|
|
74
|
+
const identifier = driver.resolveName({
|
|
75
75
|
name: error.name,
|
|
76
|
-
|
|
76
|
+
pluginName: pluginTsName,
|
|
77
77
|
type: 'function',
|
|
78
78
|
})
|
|
79
79
|
|
|
@@ -109,16 +109,16 @@ function printRequestSchema({
|
|
|
109
109
|
baseName,
|
|
110
110
|
operation,
|
|
111
111
|
schemas,
|
|
112
|
-
|
|
112
|
+
driver,
|
|
113
113
|
}: {
|
|
114
114
|
baseName: string
|
|
115
115
|
operation: Operation
|
|
116
116
|
schemas: OperationSchemas
|
|
117
|
-
|
|
117
|
+
driver: PluginDriver
|
|
118
118
|
}): string {
|
|
119
|
-
const name =
|
|
119
|
+
const name = driver.resolveName({
|
|
120
120
|
name: `${baseName} Request`,
|
|
121
|
-
|
|
121
|
+
pluginName: pluginTsName,
|
|
122
122
|
type: 'type',
|
|
123
123
|
})
|
|
124
124
|
|
|
@@ -128,9 +128,9 @@ function printRequestSchema({
|
|
|
128
128
|
const dataRequestProperties: ts.PropertySignature[] = []
|
|
129
129
|
|
|
130
130
|
if (schemas.request) {
|
|
131
|
-
const identifier =
|
|
131
|
+
const identifier = driver.resolveName({
|
|
132
132
|
name: schemas.request.name,
|
|
133
|
-
|
|
133
|
+
pluginName: pluginTsName,
|
|
134
134
|
type: 'type',
|
|
135
135
|
})
|
|
136
136
|
dataRequestProperties.push(
|
|
@@ -152,9 +152,9 @@ function printRequestSchema({
|
|
|
152
152
|
|
|
153
153
|
// Add pathParams property
|
|
154
154
|
if (schemas.pathParams) {
|
|
155
|
-
const identifier =
|
|
155
|
+
const identifier = driver.resolveName({
|
|
156
156
|
name: schemas.pathParams.name,
|
|
157
|
-
|
|
157
|
+
pluginName: pluginTsName,
|
|
158
158
|
type: 'type',
|
|
159
159
|
})
|
|
160
160
|
dataRequestProperties.push(
|
|
@@ -175,9 +175,9 @@ function printRequestSchema({
|
|
|
175
175
|
|
|
176
176
|
// Add queryParams property
|
|
177
177
|
if (schemas.queryParams) {
|
|
178
|
-
const identifier =
|
|
178
|
+
const identifier = driver.resolveName({
|
|
179
179
|
name: schemas.queryParams.name,
|
|
180
|
-
|
|
180
|
+
pluginName: pluginTsName,
|
|
181
181
|
type: 'type',
|
|
182
182
|
})
|
|
183
183
|
dataRequestProperties.push(
|
|
@@ -199,9 +199,9 @@ function printRequestSchema({
|
|
|
199
199
|
|
|
200
200
|
// Add headerParams property
|
|
201
201
|
if (schemas.headerParams) {
|
|
202
|
-
const identifier =
|
|
202
|
+
const identifier = driver.resolveName({
|
|
203
203
|
name: schemas.headerParams.name,
|
|
204
|
-
|
|
204
|
+
pluginName: pluginTsName,
|
|
205
205
|
type: 'type',
|
|
206
206
|
})
|
|
207
207
|
dataRequestProperties.push(
|
|
@@ -243,28 +243,28 @@ function printRequestSchema({
|
|
|
243
243
|
function printResponseSchema({
|
|
244
244
|
baseName,
|
|
245
245
|
schemas,
|
|
246
|
-
|
|
246
|
+
driver,
|
|
247
247
|
unknownType,
|
|
248
248
|
}: {
|
|
249
249
|
baseName: string
|
|
250
250
|
schemas: OperationSchemas
|
|
251
|
-
|
|
251
|
+
driver: PluginDriver
|
|
252
252
|
unknownType: PluginTs['resolvedOptions']['unknownType']
|
|
253
253
|
}): string {
|
|
254
254
|
const results: string[] = []
|
|
255
255
|
|
|
256
|
-
const name =
|
|
256
|
+
const name = driver.resolveName({
|
|
257
257
|
name: `${baseName} ResponseData`,
|
|
258
|
-
|
|
258
|
+
pluginName: pluginTsName,
|
|
259
259
|
type: 'type',
|
|
260
260
|
})
|
|
261
261
|
|
|
262
262
|
// Generate Responses type (mapping status codes to response types)
|
|
263
263
|
if (schemas.responses && schemas.responses.length > 0) {
|
|
264
264
|
const responsesProperties: ts.PropertySignature[] = schemas.responses.map((res) => {
|
|
265
|
-
const identifier =
|
|
265
|
+
const identifier = driver.resolveName({
|
|
266
266
|
name: res.name,
|
|
267
|
-
|
|
267
|
+
pluginName: pluginTsName,
|
|
268
268
|
type: 'type',
|
|
269
269
|
})
|
|
270
270
|
|
|
@@ -309,23 +309,22 @@ function printResponseSchema({
|
|
|
309
309
|
return results.join('\n\n')
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
export const typeGenerator = createReactGenerator<PluginTs
|
|
312
|
+
export const typeGenerator = createReactGenerator<PluginTs>({
|
|
313
313
|
name: 'typescript',
|
|
314
|
-
version: '1',
|
|
315
314
|
Operation({ operation, generator, plugin }) {
|
|
316
315
|
const {
|
|
317
316
|
options,
|
|
318
|
-
options: {
|
|
317
|
+
options: { enumType, enumKeyCasing, syntaxType, optionalType, arrayType, unknownType, paramsCasing },
|
|
319
318
|
} = plugin
|
|
320
319
|
|
|
321
320
|
const mode = useMode()
|
|
322
|
-
const
|
|
321
|
+
const driver = usePluginDriver()
|
|
323
322
|
|
|
324
323
|
const oas = useOas()
|
|
325
324
|
const { getSchemas, getFile, getName, getGroup } = useOperationManager(generator)
|
|
326
325
|
const schemaManager = useSchemaManager()
|
|
327
326
|
|
|
328
|
-
const name = getName(operation, { type: 'type',
|
|
327
|
+
const name = getName(operation, { type: 'type', pluginName: pluginTsName })
|
|
329
328
|
|
|
330
329
|
const file = getFile(operation)
|
|
331
330
|
const schemas = getSchemas(operation)
|
|
@@ -334,7 +333,7 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
|
|
|
334
333
|
oas,
|
|
335
334
|
events: generator.context.events,
|
|
336
335
|
plugin,
|
|
337
|
-
|
|
336
|
+
driver,
|
|
338
337
|
mode,
|
|
339
338
|
override: options.override,
|
|
340
339
|
})
|
|
@@ -370,7 +369,6 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
|
|
|
370
369
|
description={description}
|
|
371
370
|
tree={tree}
|
|
372
371
|
schema={transformedSchema}
|
|
373
|
-
mapper={mapper}
|
|
374
372
|
enumType={enumType}
|
|
375
373
|
enumKeyCasing={enumKeyCasing}
|
|
376
374
|
optionalType={optionalType}
|
|
@@ -385,6 +383,7 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
|
|
|
385
383
|
const responseName = schemaManager.getName(schemas.response.name, {
|
|
386
384
|
type: 'type',
|
|
387
385
|
})
|
|
386
|
+
|
|
388
387
|
const combinedSchemaName = operation.method === 'get' ? `${name}Query` : `${name}Mutation`
|
|
389
388
|
|
|
390
389
|
return (
|
|
@@ -392,7 +391,7 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
|
|
|
392
391
|
baseName={file.baseName}
|
|
393
392
|
path={file.path}
|
|
394
393
|
meta={file.meta}
|
|
395
|
-
banner={getBanner({ oas, output: plugin.options.output, config:
|
|
394
|
+
banner={getBanner({ oas, output: plugin.options.output, config: driver.config })}
|
|
396
395
|
footer={getFooter({ oas, output: plugin.options.output })}
|
|
397
396
|
>
|
|
398
397
|
{operationSchemas.map(mapOperationSchema)}
|
|
@@ -400,15 +399,15 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
|
|
|
400
399
|
{generator.context.UNSTABLE_NAMING ? (
|
|
401
400
|
<>
|
|
402
401
|
<File.Source name={`${name}Request`} isExportable isIndexable isTypeOnly>
|
|
403
|
-
{printRequestSchema({ baseName: name, operation, schemas,
|
|
402
|
+
{printRequestSchema({ baseName: name, operation, schemas, driver })}
|
|
404
403
|
</File.Source>
|
|
405
404
|
<File.Source name={responseName} isExportable isIndexable isTypeOnly>
|
|
406
|
-
{printResponseSchema({ baseName: name, schemas,
|
|
405
|
+
{printResponseSchema({ baseName: name, schemas, driver, unknownType })}
|
|
407
406
|
</File.Source>
|
|
408
407
|
</>
|
|
409
408
|
) : (
|
|
410
409
|
<File.Source name={combinedSchemaName} isExportable isIndexable isTypeOnly>
|
|
411
|
-
{printCombinedSchema({ name: combinedSchemaName, schemas,
|
|
410
|
+
{printCombinedSchema({ name: combinedSchemaName, schemas, driver })}
|
|
412
411
|
</File.Source>
|
|
413
412
|
)}
|
|
414
413
|
</File>
|
|
@@ -416,12 +415,12 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
|
|
|
416
415
|
},
|
|
417
416
|
Schema({ schema, plugin }) {
|
|
418
417
|
const {
|
|
419
|
-
options: {
|
|
418
|
+
options: { enumType, enumKeyCasing, syntaxType, optionalType, arrayType, output },
|
|
420
419
|
} = plugin
|
|
421
420
|
const mode = useMode()
|
|
422
421
|
|
|
423
422
|
const oas = useOas()
|
|
424
|
-
const
|
|
423
|
+
const driver = usePluginDriver()
|
|
425
424
|
|
|
426
425
|
const { getName, getFile } = useSchemaManager()
|
|
427
426
|
const imports = getImports(schema.tree)
|
|
@@ -444,7 +443,7 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
|
|
|
444
443
|
baseName={type.file.baseName}
|
|
445
444
|
path={type.file.path}
|
|
446
445
|
meta={type.file.meta}
|
|
447
|
-
banner={getBanner({ oas, output, config:
|
|
446
|
+
banner={getBanner({ oas, output, config: driver.config })}
|
|
448
447
|
footer={getFooter({ oas, output })}
|
|
449
448
|
>
|
|
450
449
|
{mode === 'split' &&
|
|
@@ -457,7 +456,6 @@ export const typeGenerator = createReactGenerator<PluginTs, '1'>({
|
|
|
457
456
|
description={schema.value.description}
|
|
458
457
|
tree={schema.tree}
|
|
459
458
|
schema={schema.value}
|
|
460
|
-
mapper={mapper}
|
|
461
459
|
enumType={enumType}
|
|
462
460
|
enumKeyCasing={enumKeyCasing}
|
|
463
461
|
optionalType={optionalType}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { applyParamsCasing } from '@kubb/ast'
|
|
2
|
+
import type { SchemaNode } from '@kubb/ast/types'
|
|
3
|
+
import { defineGenerator } from '@kubb/core'
|
|
4
|
+
import { useKubb } from '@kubb/core/hooks'
|
|
5
|
+
import { File } from '@kubb/react-fabric'
|
|
6
|
+
import { Type } from '../../components/v2/Type.tsx'
|
|
7
|
+
import { ENUM_TYPES_WITH_KEY_SUFFIX } from '../../constants.ts'
|
|
8
|
+
import { resolverTs } from '../../resolverTs.ts'
|
|
9
|
+
import type { PluginTs } from '../../types'
|
|
10
|
+
import { buildDataSchemaNode, buildResponsesSchemaNode, buildResponseUnionSchemaNode } from './utils.ts'
|
|
11
|
+
|
|
12
|
+
export const typeGenerator = defineGenerator<PluginTs>({
|
|
13
|
+
name: 'typescript',
|
|
14
|
+
type: 'react',
|
|
15
|
+
Operation({ node, adapter, options }) {
|
|
16
|
+
const { enumType, enumKeyCasing, optionalType, arrayType, syntaxType, paramsCasing, group } = options
|
|
17
|
+
const { mode, getFile, resolveName, resolveBanner, resolveFooter } = useKubb<PluginTs>()
|
|
18
|
+
|
|
19
|
+
const file = getFile({
|
|
20
|
+
name: node.operationId,
|
|
21
|
+
extname: '.ts',
|
|
22
|
+
mode,
|
|
23
|
+
options: {
|
|
24
|
+
group: group ? (group.type === 'tag' ? { tag: node.tags[0] } : { path: node.path }) : undefined,
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
const params = applyParamsCasing(node.parameters, paramsCasing)
|
|
28
|
+
|
|
29
|
+
function renderSchemaType({
|
|
30
|
+
node: schemaNode,
|
|
31
|
+
name,
|
|
32
|
+
typedName,
|
|
33
|
+
description,
|
|
34
|
+
}: {
|
|
35
|
+
node: SchemaNode | null
|
|
36
|
+
name: string
|
|
37
|
+
typedName: string
|
|
38
|
+
description?: string
|
|
39
|
+
}) {
|
|
40
|
+
if (!schemaNode) {
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const imports = adapter.getImports(schemaNode, (schemaName) => ({
|
|
45
|
+
name: resolveName({ name: schemaName, type: 'type' }),
|
|
46
|
+
path: getFile({ name: schemaName, extname: '.ts', mode }).path,
|
|
47
|
+
}))
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
{mode === 'split' &&
|
|
52
|
+
imports.map((imp) => <File.Import key={[name, imp.path, imp.isTypeOnly].join('-')} root={file.path} path={imp.path} name={imp.name} isTypeOnly />)}
|
|
53
|
+
<Type
|
|
54
|
+
name={name}
|
|
55
|
+
typedName={typedName}
|
|
56
|
+
node={schemaNode}
|
|
57
|
+
description={description}
|
|
58
|
+
enumType={enumType}
|
|
59
|
+
enumKeyCasing={enumKeyCasing}
|
|
60
|
+
optionalType={optionalType}
|
|
61
|
+
arrayType={arrayType}
|
|
62
|
+
syntaxType={syntaxType}
|
|
63
|
+
/>
|
|
64
|
+
</>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const paramTypes = params.map((param) =>
|
|
69
|
+
renderSchemaType({
|
|
70
|
+
node: param.schema,
|
|
71
|
+
name: resolverTs.resolveParamName(node, param),
|
|
72
|
+
typedName: resolverTs.resolveParamTypedName(node, param),
|
|
73
|
+
}),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
const responseTypes = node.responses.map((res) =>
|
|
77
|
+
renderSchemaType({
|
|
78
|
+
node: res.schema,
|
|
79
|
+
name: resolverTs.resolveResponseStatusName(node, res.statusCode),
|
|
80
|
+
typedName: resolverTs.resolveResponseStatusTypedName(node, res.statusCode),
|
|
81
|
+
description: res.description,
|
|
82
|
+
}),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
const requestType = node.requestBody
|
|
86
|
+
? renderSchemaType({
|
|
87
|
+
node: node.requestBody,
|
|
88
|
+
name: resolverTs.resolveDataName(node),
|
|
89
|
+
typedName: resolverTs.resolveDataTypedName(node),
|
|
90
|
+
description: node.requestBody.description,
|
|
91
|
+
})
|
|
92
|
+
: null
|
|
93
|
+
|
|
94
|
+
const dataType = renderSchemaType({
|
|
95
|
+
node: buildDataSchemaNode({ node: { ...node, parameters: params }, resolveName }),
|
|
96
|
+
name: resolverTs.resolveRequestConfigName(node),
|
|
97
|
+
typedName: resolverTs.resolveRequestConfigTypedName(node),
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const responsesType = renderSchemaType({
|
|
101
|
+
node: buildResponsesSchemaNode({ node, resolveName }),
|
|
102
|
+
name: resolverTs.resolveResponsesName(node),
|
|
103
|
+
typedName: resolverTs.resolveResponsesTypedName(node),
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const responseType = renderSchemaType({
|
|
107
|
+
node: buildResponseUnionSchemaNode({ node, resolveName }),
|
|
108
|
+
name: resolverTs.resolveResponseName(node),
|
|
109
|
+
typedName: resolverTs.resolveResponseTypedName(node),
|
|
110
|
+
description: 'Union of all possible responses',
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<File baseName={file.baseName} path={file.path} meta={file.meta} banner={resolveBanner()} footer={resolveFooter()}>
|
|
115
|
+
{paramTypes}
|
|
116
|
+
{responseTypes}
|
|
117
|
+
{requestType}
|
|
118
|
+
{dataType}
|
|
119
|
+
{responsesType}
|
|
120
|
+
{responseType}
|
|
121
|
+
</File>
|
|
122
|
+
)
|
|
123
|
+
},
|
|
124
|
+
Schema({ node, adapter, options }) {
|
|
125
|
+
const { enumType, enumKeyCasing, syntaxType, optionalType, arrayType } = options
|
|
126
|
+
const { mode, resolveName, getFile, resolveBanner, resolveFooter } = useKubb<PluginTs>()
|
|
127
|
+
|
|
128
|
+
if (!node.name) {
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const imports = adapter.getImports(node, (schemaName) => ({
|
|
133
|
+
name: resolveName({ name: schemaName, type: 'type' }),
|
|
134
|
+
path: getFile({ name: schemaName, extname: '.ts', mode }).path,
|
|
135
|
+
}))
|
|
136
|
+
|
|
137
|
+
const isEnumSchema = node.type === 'enum'
|
|
138
|
+
|
|
139
|
+
const typedName =
|
|
140
|
+
ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && isEnumSchema ? resolverTs.resolveEnumKeyTypedName(node) : resolverTs.resolveTypedName(node.name)
|
|
141
|
+
|
|
142
|
+
const type = {
|
|
143
|
+
name: resolverTs.resolveName(node.name),
|
|
144
|
+
typedName,
|
|
145
|
+
file: getFile({ name: node.name, extname: '.ts', mode }),
|
|
146
|
+
} as const
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<File baseName={type.file.baseName} path={type.file.path} meta={type.file.meta} banner={resolveBanner()} footer={resolveFooter()}>
|
|
150
|
+
{mode === 'split' &&
|
|
151
|
+
imports.map((imp) => (
|
|
152
|
+
<File.Import key={[node.name, imp.path, imp.isTypeOnly].join('-')} root={type.file.path} path={imp.path} name={imp.name} isTypeOnly />
|
|
153
|
+
))}
|
|
154
|
+
<Type
|
|
155
|
+
name={type.name}
|
|
156
|
+
typedName={type.typedName}
|
|
157
|
+
node={node}
|
|
158
|
+
enumType={enumType}
|
|
159
|
+
enumKeyCasing={enumKeyCasing}
|
|
160
|
+
optionalType={optionalType}
|
|
161
|
+
arrayType={arrayType}
|
|
162
|
+
syntaxType={syntaxType}
|
|
163
|
+
/>
|
|
164
|
+
</File>
|
|
165
|
+
)
|
|
166
|
+
},
|
|
167
|
+
})
|