@kubb/plugin-ts 4.14.0 → 4.15.0
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-HKIi69kI.js → components-BE9rQGox.js} +60 -28
- package/dist/components-BE9rQGox.js.map +1 -0
- package/dist/{components-pzX1Kb4u.cjs → components-CGcs8968.cjs} +90 -28
- package/dist/components-CGcs8968.cjs.map +1 -0
- package/dist/components.cjs +1 -1
- package/dist/components.d.cts +3 -1
- package/dist/components.d.ts +3 -1
- package/dist/components.js +1 -1
- package/dist/generators.cjs +1 -1
- package/dist/generators.d.cts +1 -1
- package/dist/generators.d.ts +1 -1
- package/dist/generators.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{plugin-DljW3znk.cjs → plugin-B96TNDf4.cjs} +174 -21
- package/dist/plugin-B96TNDf4.cjs.map +1 -0
- package/dist/{plugin-BEfry-Dm.js → plugin-DXyNbr_u.js} +173 -21
- package/dist/plugin-DXyNbr_u.js.map +1 -0
- package/dist/{types-DcA3qMIF.d.ts → types-D59kq_S_.d.ts} +27 -1
- package/dist/{types-C51mhXW0.d.cts → types-njfY0PGo.d.cts} +27 -1
- package/package.json +4 -4
- package/src/components/Type.tsx +8 -2
- package/src/factory.ts +77 -3
- package/src/generators/__snapshots__/createPet.ts +1 -1
- package/src/generators/__snapshots__/createPetWithEmptySchemaTypeUnknown.ts +1 -1
- package/src/generators/__snapshots__/createPetWithEmptySchemaTypeVoid.ts +1 -1
- package/src/generators/__snapshots__/createPetWithUnknownTypeUnknown.ts +1 -1
- package/src/generators/__snapshots__/createPetWithUnknownTypeVoid.ts +1 -1
- package/src/generators/__snapshots__/deletePet.ts +1 -1
- package/src/generators/__snapshots__/getPets.ts +1 -1
- package/src/generators/__snapshots__/showPetById.ts +1 -1
- package/src/generators/__snapshots__/systemsWithExplodeForm.ts +1 -1
- package/src/generators/typeGenerator.tsx +232 -8
- package/src/parser.ts +9 -20
- package/src/plugin.ts +4 -0
- package/src/types.ts +12 -0
- package/dist/components-HKIi69kI.js.map +0 -1
- package/dist/components-pzX1Kb4u.cjs.map +0 -1
- package/dist/plugin-BEfry-Dm.js.map +0 -1
- package/dist/plugin-DljW3znk.cjs.map +0 -1
package/src/factory.ts
CHANGED
|
@@ -17,6 +17,16 @@ export const syntaxKind = {
|
|
|
17
17
|
union: SyntaxKind.UnionType as 192,
|
|
18
18
|
} as const
|
|
19
19
|
|
|
20
|
+
export function getUnknownType(unknownType: 'any' | 'unknown' | 'void' | undefined) {
|
|
21
|
+
if (unknownType === 'any') {
|
|
22
|
+
return keywordTypeNodes.any
|
|
23
|
+
}
|
|
24
|
+
if (unknownType === 'void') {
|
|
25
|
+
return keywordTypeNodes.void
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return keywordTypeNodes.unknown
|
|
29
|
+
}
|
|
20
30
|
function isValidIdentifier(str: string): boolean {
|
|
21
31
|
if (!str.length || str.trim() !== str) {
|
|
22
32
|
return false
|
|
@@ -86,16 +96,29 @@ export function createTupleDeclaration({ nodes, withParentheses }: { nodes: Arra
|
|
|
86
96
|
return node
|
|
87
97
|
}
|
|
88
98
|
|
|
89
|
-
export function createArrayDeclaration({ nodes }: { nodes: Array<ts.TypeNode
|
|
99
|
+
export function createArrayDeclaration({ nodes, arrayType = 'array' }: { nodes: Array<ts.TypeNode>; arrayType?: 'array' | 'generic' }): ts.TypeNode | null {
|
|
90
100
|
if (!nodes.length) {
|
|
91
101
|
return factory.createTupleTypeNode([])
|
|
92
102
|
}
|
|
93
103
|
|
|
94
104
|
if (nodes.length === 1) {
|
|
95
|
-
|
|
105
|
+
const node = nodes[0]
|
|
106
|
+
if (!node) {
|
|
107
|
+
return null
|
|
108
|
+
}
|
|
109
|
+
if (arrayType === 'generic') {
|
|
110
|
+
return factory.createTypeReferenceNode(factory.createIdentifier('Array'), [node])
|
|
111
|
+
}
|
|
112
|
+
return factory.createArrayTypeNode(node)
|
|
96
113
|
}
|
|
97
114
|
|
|
98
|
-
|
|
115
|
+
// For union types (multiple nodes), respect arrayType preference
|
|
116
|
+
const unionType = factory.createUnionTypeNode(nodes)
|
|
117
|
+
if (arrayType === 'generic') {
|
|
118
|
+
return factory.createTypeReferenceNode(factory.createIdentifier('Array'), [unionType])
|
|
119
|
+
}
|
|
120
|
+
// For array syntax with unions, we need parentheses: (string | number)[]
|
|
121
|
+
return factory.createArrayTypeNode(factory.createParenthesizedType(unionType))
|
|
99
122
|
}
|
|
100
123
|
|
|
101
124
|
/**
|
|
@@ -572,8 +595,56 @@ export const keywordTypeNodes = {
|
|
|
572
595
|
boolean: factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword),
|
|
573
596
|
undefined: factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
|
|
574
597
|
null: factory.createLiteralTypeNode(factory.createToken(ts.SyntaxKind.NullKeyword)),
|
|
598
|
+
never: factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword),
|
|
575
599
|
} as const
|
|
576
600
|
|
|
601
|
+
/**
|
|
602
|
+
* Converts a path like '/pet/{petId}/uploadImage' to a template literal type
|
|
603
|
+
* like `/pet/${string}/uploadImage`
|
|
604
|
+
*/
|
|
605
|
+
export function createUrlTemplateType(path: string): ts.TypeNode {
|
|
606
|
+
// If no parameters, return literal string type
|
|
607
|
+
if (!path.includes('{')) {
|
|
608
|
+
return factory.createLiteralTypeNode(factory.createStringLiteral(path))
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Split path by parameter placeholders, e.g. '/pet/{petId}/upload' -> ['/pet/', 'petId', '/upload']
|
|
612
|
+
const segments = path.split(/(\{[^}]+\})/)
|
|
613
|
+
|
|
614
|
+
// Separate static parts from parameter placeholders
|
|
615
|
+
const parts: string[] = []
|
|
616
|
+
const parameterIndices: number[] = []
|
|
617
|
+
|
|
618
|
+
segments.forEach((segment) => {
|
|
619
|
+
if (segment.startsWith('{') && segment.endsWith('}')) {
|
|
620
|
+
// This is a parameter placeholder
|
|
621
|
+
parameterIndices.push(parts.length)
|
|
622
|
+
parts.push(segment) // Will be replaced with ${string}
|
|
623
|
+
} else if (segment) {
|
|
624
|
+
// This is a static part
|
|
625
|
+
parts.push(segment)
|
|
626
|
+
}
|
|
627
|
+
})
|
|
628
|
+
|
|
629
|
+
// Build template literal type
|
|
630
|
+
// Template literal structure: head + templateSpans[]
|
|
631
|
+
// For '/pet/{petId}/upload': head = '/pet/', spans = [{ type: string, literal: '/upload' }]
|
|
632
|
+
|
|
633
|
+
const head = ts.factory.createTemplateHead(parts[0] || '')
|
|
634
|
+
const templateSpans: ts.TemplateLiteralTypeSpan[] = []
|
|
635
|
+
|
|
636
|
+
parameterIndices.forEach((paramIndex, i) => {
|
|
637
|
+
const isLast = i === parameterIndices.length - 1
|
|
638
|
+
const nextPart = parts[paramIndex + 1] || ''
|
|
639
|
+
|
|
640
|
+
const literal = isLast ? ts.factory.createTemplateTail(nextPart) : ts.factory.createTemplateMiddle(nextPart)
|
|
641
|
+
|
|
642
|
+
templateSpans.push(ts.factory.createTemplateLiteralTypeSpan(keywordTypeNodes.string, literal))
|
|
643
|
+
})
|
|
644
|
+
|
|
645
|
+
return ts.factory.createTemplateLiteralType(head, templateSpans)
|
|
646
|
+
}
|
|
647
|
+
|
|
577
648
|
export const createTypeLiteralNode = factory.createTypeLiteralNode
|
|
578
649
|
|
|
579
650
|
export const createTypeReferenceNode = factory.createTypeReferenceNode
|
|
@@ -581,6 +652,7 @@ export const createNumericLiteral = factory.createNumericLiteral
|
|
|
581
652
|
export const createStringLiteral = factory.createStringLiteral
|
|
582
653
|
|
|
583
654
|
export const createArrayTypeNode = factory.createArrayTypeNode
|
|
655
|
+
export const createParenthesizedType = factory.createParenthesizedType
|
|
584
656
|
|
|
585
657
|
export const createLiteralTypeNode = factory.createLiteralTypeNode
|
|
586
658
|
export const createNull = factory.createNull
|
|
@@ -591,3 +663,5 @@ export const createTupleTypeNode = factory.createTupleTypeNode
|
|
|
591
663
|
export const createRestTypeNode = factory.createRestTypeNode
|
|
592
664
|
export const createTrue = factory.createTrue
|
|
593
665
|
export const createFalse = factory.createFalse
|
|
666
|
+
export const createIndexedAccessTypeNode = factory.createIndexedAccessTypeNode
|
|
667
|
+
export const createTypeOperatorNode = factory.createTypeOperatorNode
|
|
@@ -40,7 +40,7 @@ export type CreatePetsMutationRequest = {
|
|
|
40
40
|
|
|
41
41
|
export type CreatePetsMutationResponse = createPets201 | createPets202
|
|
42
42
|
|
|
43
|
-
export type
|
|
43
|
+
export type CreatePetsMutation = {
|
|
44
44
|
Response: createPets201 | createPets202
|
|
45
45
|
Request: createPetsMutationRequest
|
|
46
46
|
Errors: any
|
|
@@ -40,7 +40,7 @@ export type CreatePetsMutationRequest = {
|
|
|
40
40
|
|
|
41
41
|
export type CreatePetsMutationResponse = createPets201 | createPets202
|
|
42
42
|
|
|
43
|
-
export type
|
|
43
|
+
export type CreatePetsMutation = {
|
|
44
44
|
Response: createPets201 | createPets202
|
|
45
45
|
Request: createPetsMutationRequest
|
|
46
46
|
Errors: any
|
|
@@ -40,7 +40,7 @@ export type CreatePetsMutationRequest = {
|
|
|
40
40
|
|
|
41
41
|
export type CreatePetsMutationResponse = createPets201 | createPets202
|
|
42
42
|
|
|
43
|
-
export type
|
|
43
|
+
export type CreatePetsMutation = {
|
|
44
44
|
Response: createPets201 | createPets202
|
|
45
45
|
Request: createPetsMutationRequest
|
|
46
46
|
Errors: any
|
|
@@ -40,7 +40,7 @@ export type CreatePetsMutationRequest = {
|
|
|
40
40
|
|
|
41
41
|
export type CreatePetsMutationResponse = createPets201 | createPets202
|
|
42
42
|
|
|
43
|
-
export type
|
|
43
|
+
export type CreatePetsMutation = {
|
|
44
44
|
Response: createPets201 | createPets202
|
|
45
45
|
Request: createPetsMutationRequest
|
|
46
46
|
Errors: any
|
|
@@ -40,7 +40,7 @@ export type CreatePetsMutationRequest = {
|
|
|
40
40
|
|
|
41
41
|
export type CreatePetsMutationResponse = createPets201 | createPets202
|
|
42
42
|
|
|
43
|
-
export type
|
|
43
|
+
export type CreatePetsMutation = {
|
|
44
44
|
Response: createPets201 | createPets202
|
|
45
45
|
Request: createPetsMutationRequest
|
|
46
46
|
Errors: any
|
|
@@ -2,14 +2,16 @@ import type { PluginManager } from '@kubb/core'
|
|
|
2
2
|
import { useMode, usePluginManager } from '@kubb/core/hooks'
|
|
3
3
|
import transformers from '@kubb/core/transformers'
|
|
4
4
|
import { safePrint } from '@kubb/fabric-core/parsers/typescript'
|
|
5
|
+
import type { Operation } from '@kubb/oas'
|
|
5
6
|
import { isKeyword, type OperationSchemas, type OperationSchema as OperationSchemaType, SchemaGenerator, schemaKeywords } from '@kubb/plugin-oas'
|
|
6
7
|
import { createReactGenerator } from '@kubb/plugin-oas/generators'
|
|
7
8
|
import { useOas, useOperationManager, useSchemaManager } from '@kubb/plugin-oas/hooks'
|
|
8
9
|
import { getBanner, getFooter } from '@kubb/plugin-oas/utils'
|
|
9
10
|
import { File } from '@kubb/react-fabric'
|
|
10
|
-
import
|
|
11
|
+
import ts from 'typescript'
|
|
11
12
|
import { Type } from '../components'
|
|
12
13
|
import * as factory from '../factory.ts'
|
|
14
|
+
import { createUrlTemplateType, getUnknownType, keywordTypeNodes } from '../factory.ts'
|
|
13
15
|
import { pluginTsName } from '../plugin.ts'
|
|
14
16
|
import type { PluginTs } from '../types'
|
|
15
17
|
|
|
@@ -103,12 +105,216 @@ function printCombinedSchema({ name, schemas, pluginManager }: { name: string; s
|
|
|
103
105
|
return safePrint(namespaceNode)
|
|
104
106
|
}
|
|
105
107
|
|
|
108
|
+
function printRequestSchema({
|
|
109
|
+
baseName,
|
|
110
|
+
operation,
|
|
111
|
+
schemas,
|
|
112
|
+
pluginManager,
|
|
113
|
+
}: {
|
|
114
|
+
baseName: string
|
|
115
|
+
operation: Operation
|
|
116
|
+
schemas: OperationSchemas
|
|
117
|
+
pluginManager: PluginManager
|
|
118
|
+
}): string {
|
|
119
|
+
const name = pluginManager.resolveName({
|
|
120
|
+
name: `${baseName} Request`,
|
|
121
|
+
pluginKey: [pluginTsName],
|
|
122
|
+
type: 'type',
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
const results: string[] = []
|
|
126
|
+
|
|
127
|
+
// Generate DataRequest type
|
|
128
|
+
const dataRequestProperties: ts.PropertySignature[] = []
|
|
129
|
+
|
|
130
|
+
if (schemas.request) {
|
|
131
|
+
const identifier = pluginManager.resolveName({
|
|
132
|
+
name: schemas.request.name,
|
|
133
|
+
pluginKey: [pluginTsName],
|
|
134
|
+
type: 'type',
|
|
135
|
+
})
|
|
136
|
+
dataRequestProperties.push(
|
|
137
|
+
factory.createPropertySignature({
|
|
138
|
+
name: 'data',
|
|
139
|
+
questionToken: true,
|
|
140
|
+
type: factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined),
|
|
141
|
+
}),
|
|
142
|
+
)
|
|
143
|
+
} else {
|
|
144
|
+
dataRequestProperties.push(
|
|
145
|
+
factory.createPropertySignature({
|
|
146
|
+
name: 'data',
|
|
147
|
+
questionToken: true,
|
|
148
|
+
type: keywordTypeNodes.never,
|
|
149
|
+
}),
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Add pathParams property
|
|
154
|
+
if (schemas.pathParams) {
|
|
155
|
+
const identifier = pluginManager.resolveName({
|
|
156
|
+
name: schemas.pathParams.name,
|
|
157
|
+
pluginKey: [pluginTsName],
|
|
158
|
+
type: 'type',
|
|
159
|
+
})
|
|
160
|
+
dataRequestProperties.push(
|
|
161
|
+
factory.createPropertySignature({
|
|
162
|
+
name: 'pathParams',
|
|
163
|
+
type: factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined),
|
|
164
|
+
}),
|
|
165
|
+
)
|
|
166
|
+
} else {
|
|
167
|
+
dataRequestProperties.push(
|
|
168
|
+
factory.createPropertySignature({
|
|
169
|
+
name: 'pathParams',
|
|
170
|
+
questionToken: true,
|
|
171
|
+
type: keywordTypeNodes.never,
|
|
172
|
+
}),
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Add queryParams property
|
|
177
|
+
if (schemas.queryParams) {
|
|
178
|
+
const identifier = pluginManager.resolveName({
|
|
179
|
+
name: schemas.queryParams.name,
|
|
180
|
+
pluginKey: [pluginTsName],
|
|
181
|
+
type: 'type',
|
|
182
|
+
})
|
|
183
|
+
dataRequestProperties.push(
|
|
184
|
+
factory.createPropertySignature({
|
|
185
|
+
name: 'queryParams',
|
|
186
|
+
questionToken: true,
|
|
187
|
+
type: factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined),
|
|
188
|
+
}),
|
|
189
|
+
)
|
|
190
|
+
} else {
|
|
191
|
+
dataRequestProperties.push(
|
|
192
|
+
factory.createPropertySignature({
|
|
193
|
+
name: 'queryParams',
|
|
194
|
+
questionToken: true,
|
|
195
|
+
type: keywordTypeNodes.never,
|
|
196
|
+
}),
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Add headerParams property
|
|
201
|
+
if (schemas.headerParams) {
|
|
202
|
+
const identifier = pluginManager.resolveName({
|
|
203
|
+
name: schemas.headerParams.name,
|
|
204
|
+
pluginKey: [pluginTsName],
|
|
205
|
+
type: 'type',
|
|
206
|
+
})
|
|
207
|
+
dataRequestProperties.push(
|
|
208
|
+
factory.createPropertySignature({
|
|
209
|
+
name: 'headerParams',
|
|
210
|
+
questionToken: true,
|
|
211
|
+
type: factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined),
|
|
212
|
+
}),
|
|
213
|
+
)
|
|
214
|
+
} else {
|
|
215
|
+
dataRequestProperties.push(
|
|
216
|
+
factory.createPropertySignature({
|
|
217
|
+
name: 'headerParams',
|
|
218
|
+
questionToken: true,
|
|
219
|
+
type: keywordTypeNodes.never,
|
|
220
|
+
}),
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Add url property with template literal type
|
|
225
|
+
dataRequestProperties.push(
|
|
226
|
+
factory.createPropertySignature({
|
|
227
|
+
name: 'url',
|
|
228
|
+
type: createUrlTemplateType(operation.path),
|
|
229
|
+
}),
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
const dataRequestNode = factory.createTypeAliasDeclaration({
|
|
233
|
+
name,
|
|
234
|
+
type: factory.createTypeLiteralNode(dataRequestProperties),
|
|
235
|
+
modifiers: [factory.modifiers.export],
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
results.push(safePrint(dataRequestNode))
|
|
239
|
+
|
|
240
|
+
return results.join('\n\n')
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function printResponseSchema({
|
|
244
|
+
baseName,
|
|
245
|
+
schemas,
|
|
246
|
+
pluginManager,
|
|
247
|
+
unknownType,
|
|
248
|
+
}: {
|
|
249
|
+
baseName: string
|
|
250
|
+
schemas: OperationSchemas
|
|
251
|
+
pluginManager: PluginManager
|
|
252
|
+
unknownType: PluginTs['resolvedOptions']['unknownType']
|
|
253
|
+
}): string {
|
|
254
|
+
const results: string[] = []
|
|
255
|
+
|
|
256
|
+
const name = pluginManager.resolveName({
|
|
257
|
+
name: `${baseName} ResponseData`,
|
|
258
|
+
pluginKey: [pluginTsName],
|
|
259
|
+
type: 'type',
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
// Generate Responses type (mapping status codes to response types)
|
|
263
|
+
if (schemas.responses && schemas.responses.length > 0) {
|
|
264
|
+
const responsesProperties: ts.PropertySignature[] = schemas.responses.map((res) => {
|
|
265
|
+
const identifier = pluginManager.resolveName({
|
|
266
|
+
name: res.name,
|
|
267
|
+
pluginKey: [pluginTsName],
|
|
268
|
+
type: 'type',
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
return factory.createPropertySignature({
|
|
272
|
+
name: res.statusCode?.toString() ?? 'default',
|
|
273
|
+
type: factory.createTypeReferenceNode(factory.createIdentifier(identifier), undefined),
|
|
274
|
+
})
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
const responsesNode = factory.createTypeAliasDeclaration({
|
|
278
|
+
name: `${baseName}Responses`,
|
|
279
|
+
type: factory.createTypeLiteralNode(responsesProperties),
|
|
280
|
+
modifiers: [factory.modifiers.export],
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
results.push(safePrint(responsesNode))
|
|
284
|
+
|
|
285
|
+
// Generate Response type (union via indexed access)
|
|
286
|
+
const responseNode = factory.createTypeAliasDeclaration({
|
|
287
|
+
name,
|
|
288
|
+
type: factory.createIndexedAccessTypeNode(
|
|
289
|
+
factory.createTypeReferenceNode(factory.createIdentifier(`${baseName}Responses`), undefined),
|
|
290
|
+
factory.createTypeOperatorNode(
|
|
291
|
+
ts.SyntaxKind.KeyOfKeyword,
|
|
292
|
+
factory.createTypeReferenceNode(factory.createIdentifier(`${baseName}Responses`), undefined),
|
|
293
|
+
),
|
|
294
|
+
),
|
|
295
|
+
modifiers: [factory.modifiers.export],
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
results.push(safePrint(responseNode))
|
|
299
|
+
} else {
|
|
300
|
+
const responseNode = factory.createTypeAliasDeclaration({
|
|
301
|
+
name,
|
|
302
|
+
modifiers: [factory.modifiers.export],
|
|
303
|
+
type: getUnknownType(unknownType),
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
results.push(safePrint(responseNode))
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return results.join('\n\n')
|
|
310
|
+
}
|
|
311
|
+
|
|
106
312
|
export const typeGenerator = createReactGenerator<PluginTs>({
|
|
107
313
|
name: 'typescript',
|
|
108
314
|
Operation({ operation, generator, plugin }) {
|
|
109
315
|
const {
|
|
110
316
|
options,
|
|
111
|
-
options: { mapper, enumType, syntaxType, optionalType },
|
|
317
|
+
options: { mapper, enumType, syntaxType, optionalType, arrayType, unknownType },
|
|
112
318
|
} = plugin
|
|
113
319
|
|
|
114
320
|
const mode = useMode()
|
|
@@ -118,10 +324,10 @@ export const typeGenerator = createReactGenerator<PluginTs>({
|
|
|
118
324
|
const { getSchemas, getFile, getName, getGroup } = useOperationManager(generator)
|
|
119
325
|
const schemaManager = useSchemaManager()
|
|
120
326
|
|
|
327
|
+
const name = getName(operation, { type: 'type', pluginKey: [pluginTsName] })
|
|
328
|
+
|
|
121
329
|
const file = getFile(operation)
|
|
122
330
|
const schemas = getSchemas(operation)
|
|
123
|
-
const type = getName(operation, { type: 'function', pluginKey: [pluginTsName] })
|
|
124
|
-
const combinedSchemaName = operation.method === 'get' ? `${type}Query` : `${type}Mutation`
|
|
125
331
|
const schemaGenerator = new SchemaGenerator(options, {
|
|
126
332
|
fabric: generator.context.fabric,
|
|
127
333
|
oas,
|
|
@@ -162,6 +368,7 @@ export const typeGenerator = createReactGenerator<PluginTs>({
|
|
|
162
368
|
mapper={mapper}
|
|
163
369
|
enumType={enumType}
|
|
164
370
|
optionalType={optionalType}
|
|
371
|
+
arrayType={arrayType}
|
|
165
372
|
keysToOmit={keysToOmit}
|
|
166
373
|
syntaxType={syntaxType}
|
|
167
374
|
/>
|
|
@@ -169,6 +376,11 @@ export const typeGenerator = createReactGenerator<PluginTs>({
|
|
|
169
376
|
)
|
|
170
377
|
}
|
|
171
378
|
|
|
379
|
+
const responseName = schemaManager.getName(schemas.response.name, {
|
|
380
|
+
type: 'type',
|
|
381
|
+
})
|
|
382
|
+
const combinedSchemaName = operation.method === 'get' ? `${name}Query` : `${name}Mutation`
|
|
383
|
+
|
|
172
384
|
return (
|
|
173
385
|
<File
|
|
174
386
|
baseName={file.baseName}
|
|
@@ -179,15 +391,26 @@ export const typeGenerator = createReactGenerator<PluginTs>({
|
|
|
179
391
|
>
|
|
180
392
|
{operationSchemas.map(mapOperationSchema)}
|
|
181
393
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
394
|
+
{generator.context.UNSTABLE_NAMING ? (
|
|
395
|
+
<>
|
|
396
|
+
<File.Source name={`${name}Request`} isExportable isIndexable isTypeOnly>
|
|
397
|
+
{printRequestSchema({ baseName: name, operation, schemas, pluginManager })}
|
|
398
|
+
</File.Source>
|
|
399
|
+
<File.Source name={responseName} isExportable isIndexable isTypeOnly>
|
|
400
|
+
{printResponseSchema({ baseName: name, schemas, pluginManager, unknownType })}
|
|
401
|
+
</File.Source>
|
|
402
|
+
</>
|
|
403
|
+
) : (
|
|
404
|
+
<File.Source name={combinedSchemaName} isExportable isIndexable isTypeOnly>
|
|
405
|
+
{printCombinedSchema({ name: combinedSchemaName, schemas, pluginManager })}
|
|
406
|
+
</File.Source>
|
|
407
|
+
)}
|
|
185
408
|
</File>
|
|
186
409
|
)
|
|
187
410
|
},
|
|
188
411
|
Schema({ schema, plugin }) {
|
|
189
412
|
const {
|
|
190
|
-
options: { mapper, enumType, syntaxType, optionalType, output },
|
|
413
|
+
options: { mapper, enumType, syntaxType, optionalType, arrayType, output },
|
|
191
414
|
} = plugin
|
|
192
415
|
const mode = useMode()
|
|
193
416
|
|
|
@@ -231,6 +454,7 @@ export const typeGenerator = createReactGenerator<PluginTs>({
|
|
|
231
454
|
mapper={mapper}
|
|
232
455
|
enumType={enumType}
|
|
233
456
|
optionalType={optionalType}
|
|
457
|
+
arrayType={arrayType}
|
|
234
458
|
syntaxType={syntaxType}
|
|
235
459
|
/>
|
|
236
460
|
</File>
|
package/src/parser.ts
CHANGED
|
@@ -23,12 +23,12 @@ export const typeKeywordMapper = {
|
|
|
23
23
|
nullable: undefined,
|
|
24
24
|
null: () => factory.keywordTypeNodes.null,
|
|
25
25
|
nullish: undefined,
|
|
26
|
-
array: (nodes?: ts.TypeNode[]) => {
|
|
26
|
+
array: (nodes?: ts.TypeNode[], arrayType?: 'array' | 'generic') => {
|
|
27
27
|
if (!nodes) {
|
|
28
28
|
return undefined
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
return factory.createArrayDeclaration({ nodes })
|
|
31
|
+
return factory.createArrayDeclaration({ nodes, arrayType })
|
|
32
32
|
},
|
|
33
33
|
tuple: (nodes?: ts.TypeNode[], rest?: ts.TypeNode, min?: number, max?: number) => {
|
|
34
34
|
if (!nodes) {
|
|
@@ -142,6 +142,10 @@ type ParserOptions = {
|
|
|
142
142
|
* @default `'questionToken'`
|
|
143
143
|
*/
|
|
144
144
|
optionalType: 'questionToken' | 'undefined' | 'questionTokenAndUndefined'
|
|
145
|
+
/**
|
|
146
|
+
* @default `'array'`
|
|
147
|
+
*/
|
|
148
|
+
arrayType: 'array' | 'generic'
|
|
145
149
|
/**
|
|
146
150
|
* Choose to use `enum`, `asConst`, `asPascalConst`, `constEnum`, `literal`, or `inlineLiteral` for enums.
|
|
147
151
|
* - `enum`: TypeScript enum
|
|
@@ -173,7 +177,6 @@ export const parse = createParser<ts.Node | null, ParserOptions>({
|
|
|
173
177
|
handlers: {
|
|
174
178
|
union(tree, options) {
|
|
175
179
|
const { current, schema, name } = tree
|
|
176
|
-
if (!isKeyword(current, schemaKeywords.union)) return undefined
|
|
177
180
|
|
|
178
181
|
return typeKeywordMapper.union(
|
|
179
182
|
current.args.map((it) => this.parse({ schema, parent: current, name, current: it, siblings: [] }, options)).filter(Boolean) as ts.TypeNode[],
|
|
@@ -181,7 +184,6 @@ export const parse = createParser<ts.Node | null, ParserOptions>({
|
|
|
181
184
|
},
|
|
182
185
|
and(tree, options) {
|
|
183
186
|
const { current, schema, name } = tree
|
|
184
|
-
if (!isKeyword(current, schemaKeywords.and)) return undefined
|
|
185
187
|
|
|
186
188
|
return typeKeywordMapper.and(
|
|
187
189
|
current.args.map((it) => this.parse({ schema, parent: current, name, current: it, siblings: [] }, options)).filter(Boolean) as ts.TypeNode[],
|
|
@@ -189,15 +191,14 @@ export const parse = createParser<ts.Node | null, ParserOptions>({
|
|
|
189
191
|
},
|
|
190
192
|
array(tree, options) {
|
|
191
193
|
const { current, schema, name } = tree
|
|
192
|
-
if (!isKeyword(current, schemaKeywords.array)) return undefined
|
|
193
194
|
|
|
194
195
|
return typeKeywordMapper.array(
|
|
195
196
|
current.args.items.map((it) => this.parse({ schema, parent: current, name, current: it, siblings: [] }, options)).filter(Boolean) as ts.TypeNode[],
|
|
197
|
+
options.arrayType,
|
|
196
198
|
)
|
|
197
199
|
},
|
|
198
200
|
enum(tree, options) {
|
|
199
201
|
const { current } = tree
|
|
200
|
-
if (!isKeyword(current, schemaKeywords.enum)) return undefined
|
|
201
202
|
|
|
202
203
|
// If enumType is 'inlineLiteral', generate the literal union inline instead of a type reference
|
|
203
204
|
if (options.enumType === 'inlineLiteral') {
|
|
@@ -218,19 +219,14 @@ export const parse = createParser<ts.Node | null, ParserOptions>({
|
|
|
218
219
|
},
|
|
219
220
|
ref(tree, _options) {
|
|
220
221
|
const { current } = tree
|
|
221
|
-
if (!isKeyword(current, schemaKeywords.ref)) return undefined
|
|
222
222
|
|
|
223
223
|
return typeKeywordMapper.ref(current.args.name)
|
|
224
224
|
},
|
|
225
|
-
blob(
|
|
226
|
-
const { current } = tree
|
|
227
|
-
if (!isKeyword(current, schemaKeywords.blob)) return undefined
|
|
228
|
-
|
|
225
|
+
blob() {
|
|
229
226
|
return typeKeywordMapper.blob()
|
|
230
227
|
},
|
|
231
228
|
tuple(tree, options) {
|
|
232
229
|
const { current, schema, name } = tree
|
|
233
|
-
if (!isKeyword(current, schemaKeywords.tuple)) return undefined
|
|
234
230
|
|
|
235
231
|
return typeKeywordMapper.tuple(
|
|
236
232
|
current.args.items.map((it) => this.parse({ schema, parent: current, name, current: it, siblings: [] }, options)).filter(Boolean) as ts.TypeNode[],
|
|
@@ -242,13 +238,11 @@ export const parse = createParser<ts.Node | null, ParserOptions>({
|
|
|
242
238
|
},
|
|
243
239
|
const(tree, _options) {
|
|
244
240
|
const { current } = tree
|
|
245
|
-
if (!isKeyword(current, schemaKeywords.const)) return undefined
|
|
246
241
|
|
|
247
242
|
return typeKeywordMapper.const(current.args.name, current.args.format)
|
|
248
243
|
},
|
|
249
244
|
object(tree, options) {
|
|
250
245
|
const { current, schema, name } = tree
|
|
251
|
-
if (!isKeyword(current, schemaKeywords.object)) return undefined
|
|
252
246
|
|
|
253
247
|
const properties = Object.entries(current.args?.properties || {})
|
|
254
248
|
.filter((item) => {
|
|
@@ -377,21 +371,16 @@ export const parse = createParser<ts.Node | null, ParserOptions>({
|
|
|
377
371
|
|
|
378
372
|
return typeKeywordMapper.object([...properties, additionalProperties, patternProperties].filter(Boolean))
|
|
379
373
|
},
|
|
380
|
-
datetime(
|
|
381
|
-
const { current } = tree
|
|
382
|
-
if (!isKeyword(current, schemaKeywords.datetime)) return undefined
|
|
383
|
-
|
|
374
|
+
datetime() {
|
|
384
375
|
return typeKeywordMapper.datetime()
|
|
385
376
|
},
|
|
386
377
|
date(tree) {
|
|
387
378
|
const { current } = tree
|
|
388
|
-
if (!isKeyword(current, schemaKeywords.date)) return undefined
|
|
389
379
|
|
|
390
380
|
return typeKeywordMapper.date(current.args.type)
|
|
391
381
|
},
|
|
392
382
|
time(tree) {
|
|
393
383
|
const { current } = tree
|
|
394
|
-
if (!isKeyword(current, schemaKeywords.time)) return undefined
|
|
395
384
|
|
|
396
385
|
return typeKeywordMapper.time(current.args.type)
|
|
397
386
|
},
|
package/src/plugin.ts
CHANGED
|
@@ -19,12 +19,14 @@ export const pluginTs = definePlugin<PluginTs>((options) => {
|
|
|
19
19
|
dateType = 'string',
|
|
20
20
|
unknownType = 'any',
|
|
21
21
|
optionalType = 'questionToken',
|
|
22
|
+
arrayType = 'array',
|
|
22
23
|
emptySchemaType = unknownType,
|
|
23
24
|
syntaxType = 'type',
|
|
24
25
|
transformers = {},
|
|
25
26
|
mapper = {},
|
|
26
27
|
generators = [typeGenerator].filter(Boolean),
|
|
27
28
|
contentType,
|
|
29
|
+
UNSTABLE_NAMING,
|
|
28
30
|
} = options
|
|
29
31
|
|
|
30
32
|
const usedEnumNames = {}
|
|
@@ -36,6 +38,7 @@ export const pluginTs = definePlugin<PluginTs>((options) => {
|
|
|
36
38
|
transformers,
|
|
37
39
|
dateType,
|
|
38
40
|
optionalType,
|
|
41
|
+
arrayType,
|
|
39
42
|
enumType,
|
|
40
43
|
enumSuffix,
|
|
41
44
|
unknownType,
|
|
@@ -122,6 +125,7 @@ export const pluginTs = definePlugin<PluginTs>((options) => {
|
|
|
122
125
|
include,
|
|
123
126
|
override,
|
|
124
127
|
mode,
|
|
128
|
+
UNSTABLE_NAMING,
|
|
125
129
|
})
|
|
126
130
|
|
|
127
131
|
const operationFiles = await operationGenerator.build(...generators)
|