@kubb/swagger-ts 2.0.0-alpha.9 → 2.0.0-beta.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/README.md +1 -1
- package/dist/components.cjs +3993 -0
- package/dist/components.cjs.map +1 -0
- package/dist/components.d.cts +163 -0
- package/dist/components.d.ts +163 -0
- package/dist/components.js +3969 -0
- package/dist/components.js.map +1 -0
- package/dist/index.cjs +3569 -292
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +426 -13
- package/dist/index.d.ts +426 -13
- package/dist/index.js +3572 -296
- package/dist/index.js.map +1 -1
- package/dist/oas.d.ts +381 -0
- package/dist/oas.js +5 -0
- package/dist/oas.js.map +1 -0
- package/package.json +24 -11
- package/src/OperationGenerator.tsx +62 -0
- package/src/TypeBuilder.ts +58 -0
- package/src/{generators/TypeGenerator.ts → TypeGenerator.ts} +106 -89
- package/src/components/Mutation.tsx +137 -0
- package/src/components/Oas.tsx +84 -0
- package/src/components/Query.tsx +136 -0
- package/src/components/index.ts +3 -0
- package/src/oas/index.ts +7 -0
- package/src/oas/infer.ts +58 -0
- package/src/oas/mappers.ts +93 -0
- package/src/oas/model.ts +38 -0
- package/src/oas/requestParams.ts +170 -0
- package/src/oas/response.ts +39 -0
- package/src/oas/security.ts +158 -0
- package/src/plugin.ts +54 -107
- package/src/types.ts +41 -13
- package/src/builders/TypeBuilder.ts +0 -93
- package/src/builders/index.ts +0 -1
- package/src/generators/OperationGenerator.ts +0 -211
- package/src/generators/index.ts +0 -2
@@ -1,28 +1,27 @@
|
|
1
|
-
import {
|
1
|
+
import { Generator } from '@kubb/core'
|
2
|
+
import transformers from '@kubb/core/transformers'
|
2
3
|
import { getUniqueName } from '@kubb/core/utils'
|
3
4
|
import * as factory from '@kubb/parser/factory'
|
4
|
-
import {
|
5
|
+
import { keywordTypeNodes } from '@kubb/parser/factory'
|
6
|
+
import { getSchemaFactory, isReference } from '@kubb/swagger/utils'
|
5
7
|
|
6
|
-
import {
|
8
|
+
import { pluginKey } from './plugin.ts'
|
7
9
|
|
8
|
-
import type {
|
10
|
+
import type { PluginManager } from '@kubb/core'
|
9
11
|
import type { ts } from '@kubb/parser'
|
10
|
-
import type { OpenAPIV3, Refs } from '@kubb/swagger'
|
11
|
-
import type {
|
12
|
+
import type { ImportMeta, Oas, OasTypes, OpenAPIV3, OpenAPIV3_1, Refs } from '@kubb/swagger'
|
13
|
+
import type { PluginOptions } from './types.ts'
|
12
14
|
|
13
15
|
// based on https://github.com/cellular/oazapfts/blob/7ba226ebb15374e8483cc53e7532f1663179a22c/src/codegen/generate.ts#L398
|
14
16
|
|
15
|
-
type
|
16
|
-
|
17
|
-
|
18
|
-
withJSDocs?: boolean
|
19
|
-
resolveName: PluginContext['resolveName']
|
20
|
-
enumType: 'enum' | 'asConst' | 'asPascalConst'
|
21
|
-
dateType: 'string' | 'date'
|
22
|
-
optionalType: 'questionToken' | 'undefined' | 'questionTokenAndUndefined'
|
17
|
+
type Context = {
|
18
|
+
oas: Oas
|
19
|
+
pluginManager: PluginManager
|
23
20
|
}
|
24
|
-
|
21
|
+
|
22
|
+
export class TypeGenerator extends Generator<PluginOptions['resolvedOptions'], Context> {
|
25
23
|
refs: Refs = {}
|
24
|
+
imports: ImportMeta[] = []
|
26
25
|
|
27
26
|
extraNodes: ts.Node[] = []
|
28
27
|
|
@@ -31,39 +30,19 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
31
30
|
// Keep track of already used type aliases
|
32
31
|
#usedAliasNames: Record<string, number> = {}
|
33
32
|
|
34
|
-
#caseOptions: CaseOptions = {
|
35
|
-
delimiter: '',
|
36
|
-
stripRegexp: /[^A-Z0-9$]/gi,
|
37
|
-
}
|
38
|
-
|
39
|
-
constructor(
|
40
|
-
options: Options = {
|
41
|
-
usedEnumNames: {},
|
42
|
-
withJSDocs: true,
|
43
|
-
resolveName: ({ name }) => name,
|
44
|
-
enumType: 'asConst',
|
45
|
-
dateType: 'string',
|
46
|
-
optionalType: 'questionToken',
|
47
|
-
},
|
48
|
-
) {
|
49
|
-
super(options)
|
50
|
-
|
51
|
-
return this
|
52
|
-
}
|
53
|
-
|
54
33
|
build({
|
55
34
|
schema,
|
56
35
|
baseName,
|
57
36
|
description,
|
58
37
|
keysToOmit,
|
59
38
|
}: {
|
60
|
-
schema:
|
39
|
+
schema: OasTypes.SchemaObject
|
61
40
|
baseName: string
|
62
41
|
description?: string
|
63
42
|
keysToOmit?: string[]
|
64
43
|
}): ts.Node[] {
|
65
44
|
const nodes: ts.Node[] = []
|
66
|
-
const type = this
|
45
|
+
const type = this.getTypeFromSchema(schema, baseName)
|
67
46
|
|
68
47
|
if (!type) {
|
69
48
|
return this.extraNodes
|
@@ -71,7 +50,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
71
50
|
|
72
51
|
const node = factory.createTypeAliasDeclaration({
|
73
52
|
modifiers: [factory.modifiers.export],
|
74
|
-
name: this.
|
53
|
+
name: this.context.pluginManager.resolveName({ name: baseName, pluginKey, type: 'type' }),
|
75
54
|
type: keysToOmit?.length ? factory.createOmitDeclaration({ keys: keysToOmit, type, nonNullable: true }) : type,
|
76
55
|
})
|
77
56
|
|
@@ -79,7 +58,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
79
58
|
nodes.push(
|
80
59
|
factory.appendJSDocToNode({
|
81
60
|
node,
|
82
|
-
comments: [`@description ${description}`],
|
61
|
+
comments: [`@description ${transformers.trim(description)}`],
|
83
62
|
}),
|
84
63
|
)
|
85
64
|
} else {
|
@@ -102,7 +81,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
102
81
|
* Delegates to getBaseTypeFromSchema internally and
|
103
82
|
* optionally adds a union with null.
|
104
83
|
*/
|
105
|
-
|
84
|
+
getTypeFromSchema(schema?: OasTypes.SchemaObject, name?: string): ts.TypeNode | null {
|
106
85
|
const type = this.#getBaseTypeFromSchema(schema, name)
|
107
86
|
|
108
87
|
if (!type) {
|
@@ -119,49 +98,48 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
119
98
|
/**
|
120
99
|
* Recursively creates a type literal with the given props.
|
121
100
|
*/
|
122
|
-
#getTypeFromProperties(baseSchema?:
|
101
|
+
#getTypeFromProperties(baseSchema?: OasTypes.SchemaObject, baseName?: string): ts.TypeNode | null {
|
123
102
|
const { optionalType } = this.options
|
124
103
|
const properties = baseSchema?.properties || {}
|
125
104
|
const required = baseSchema?.required
|
126
105
|
const additionalProperties = baseSchema?.additionalProperties
|
127
106
|
|
128
107
|
const members: Array<ts.TypeElement | null> = Object.keys(properties).map((name) => {
|
129
|
-
const schema = properties[name] as
|
108
|
+
const schema = properties[name] as OasTypes.SchemaObject
|
130
109
|
|
131
|
-
const isRequired = required
|
132
|
-
let type = this
|
110
|
+
const isRequired = Array.isArray(required) ? required.includes(name) : !!required
|
111
|
+
let type = this.getTypeFromSchema(schema, this.context.pluginManager.resolveName({ name: `${baseName || ''} ${name}`, pluginKey, type: 'type' }))
|
133
112
|
|
134
113
|
if (!type) {
|
135
114
|
return null
|
136
115
|
}
|
137
116
|
|
138
|
-
if (!isRequired && ['undefined', 'questionTokenAndUndefined'].includes(optionalType)) {
|
117
|
+
if (!isRequired && ['undefined', 'questionTokenAndUndefined'].includes(optionalType as string)) {
|
139
118
|
type = factory.createUnionDeclaration({ nodes: [type, factory.keywordTypeNodes.undefined] })
|
140
119
|
}
|
141
120
|
const propertySignature = factory.createPropertySignature({
|
142
|
-
questionToken: ['questionToken', 'questionTokenAndUndefined'].includes(optionalType) && !isRequired,
|
121
|
+
questionToken: ['questionToken', 'questionTokenAndUndefined'].includes(optionalType as string) && !isRequired,
|
143
122
|
name,
|
144
123
|
type: type as ts.TypeNode,
|
145
124
|
readOnly: schema.readOnly,
|
146
125
|
})
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
}
|
126
|
+
|
127
|
+
return factory.appendJSDocToNode({
|
128
|
+
node: propertySignature,
|
129
|
+
comments: [
|
130
|
+
schema.description ? `@description ${schema.description}` : undefined,
|
131
|
+
schema.type ? `@type ${schema.type?.toString()}${isRequired ? '' : ' | undefined'} ${schema.format || ''}` : undefined,
|
132
|
+
schema.example ? `@example ${schema.example as string}` : undefined,
|
133
|
+
schema.deprecated ? `@deprecated` : undefined,
|
134
|
+
schema.default !== undefined && typeof schema.default === 'string' ? `@default '${schema.default}'` : undefined,
|
135
|
+
schema.default !== undefined && typeof schema.default !== 'string' ? `@default ${schema.default as string}` : undefined,
|
136
|
+
].filter(Boolean),
|
137
|
+
})
|
160
138
|
|
161
139
|
return propertySignature
|
162
140
|
})
|
163
141
|
if (additionalProperties) {
|
164
|
-
const type = additionalProperties === true ? factory.keywordTypeNodes.any : this
|
142
|
+
const type = additionalProperties === true ? factory.keywordTypeNodes.any : this.getTypeFromSchema(additionalProperties as OasTypes.SchemaObject)
|
165
143
|
|
166
144
|
if (type) {
|
167
145
|
members.push(factory.createIndexSignature(type))
|
@@ -182,21 +160,39 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
182
160
|
}
|
183
161
|
|
184
162
|
const originalName = getUniqueName($ref.replace(/.+\//, ''), this.#usedAliasNames)
|
185
|
-
const propertyName = this.
|
163
|
+
const propertyName = this.context.pluginManager.resolveName({ name: originalName, pluginKey, type: 'type' })
|
186
164
|
|
187
165
|
ref = this.refs[$ref] = {
|
188
166
|
propertyName,
|
189
167
|
originalName,
|
190
168
|
}
|
191
169
|
|
170
|
+
const path = this.context.pluginManager.resolvePath({ baseName: propertyName, pluginKey })
|
171
|
+
|
172
|
+
this.imports.push({
|
173
|
+
ref,
|
174
|
+
path: path || '',
|
175
|
+
isTypeOnly: true,
|
176
|
+
})
|
177
|
+
|
192
178
|
return factory.createTypeReferenceNode(ref.propertyName, undefined)
|
193
179
|
}
|
194
180
|
|
181
|
+
#getParsedSchema(schema?: OasTypes.SchemaObject) {
|
182
|
+
const parsedSchema = getSchemaFactory(this.context.oas)(schema)
|
183
|
+
return parsedSchema
|
184
|
+
}
|
185
|
+
|
195
186
|
/**
|
196
187
|
* This is the very core of the OpenAPI to TS conversion - it takes a
|
197
188
|
* schema and returns the appropriate type.
|
198
189
|
*/
|
199
|
-
#getBaseTypeFromSchema(
|
190
|
+
#getBaseTypeFromSchema(
|
191
|
+
_schema: OasTypes.SchemaObject | undefined,
|
192
|
+
baseName?: string,
|
193
|
+
): ts.TypeNode | null {
|
194
|
+
const { schema, version } = this.#getParsedSchema(_schema)
|
195
|
+
|
200
196
|
if (!schema) {
|
201
197
|
return factory.keywordTypeNodes.any
|
202
198
|
}
|
@@ -207,13 +203,13 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
207
203
|
|
208
204
|
if (schema.oneOf) {
|
209
205
|
// union
|
210
|
-
const schemaWithoutOneOf = { ...schema, oneOf: undefined }
|
206
|
+
const schemaWithoutOneOf = { ...schema, oneOf: undefined } as OasTypes.SchemaObject
|
211
207
|
|
212
208
|
const union = factory.createUnionDeclaration({
|
213
209
|
withParentheses: true,
|
214
210
|
nodes: schema.oneOf
|
215
|
-
.map((item
|
216
|
-
return this
|
211
|
+
.map((item) => {
|
212
|
+
return item && this.getTypeFromSchema(item as OasTypes.SchemaObject)
|
217
213
|
})
|
218
214
|
.filter((item) => {
|
219
215
|
return item && item !== factory.keywordTypeNodes.any
|
@@ -222,7 +218,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
222
218
|
|
223
219
|
if (schemaWithoutOneOf.properties) {
|
224
220
|
return factory.createIntersectionDeclaration({
|
225
|
-
nodes: [this
|
221
|
+
nodes: [this.getTypeFromSchema(schemaWithoutOneOf, baseName), union].filter(Boolean),
|
226
222
|
})
|
227
223
|
}
|
228
224
|
|
@@ -230,13 +226,13 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
230
226
|
}
|
231
227
|
|
232
228
|
if (schema.anyOf) {
|
233
|
-
const schemaWithoutAnyOf = { ...schema, anyOf: undefined }
|
229
|
+
const schemaWithoutAnyOf = { ...schema, anyOf: undefined } as OasTypes.SchemaObject
|
234
230
|
|
235
231
|
const union = factory.createUnionDeclaration({
|
236
232
|
withParentheses: true,
|
237
233
|
nodes: schema.anyOf
|
238
|
-
.map((item
|
239
|
-
return this
|
234
|
+
.map((item) => {
|
235
|
+
return item && this.getTypeFromSchema(item as OasTypes.SchemaObject)
|
240
236
|
})
|
241
237
|
.filter((item) => {
|
242
238
|
return item && item !== factory.keywordTypeNodes.any
|
@@ -245,7 +241,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
245
241
|
|
246
242
|
if (schemaWithoutAnyOf.properties) {
|
247
243
|
return factory.createIntersectionDeclaration({
|
248
|
-
nodes: [this
|
244
|
+
nodes: [this.getTypeFromSchema(schemaWithoutAnyOf, baseName), union].filter(Boolean),
|
249
245
|
})
|
250
246
|
}
|
251
247
|
|
@@ -253,13 +249,13 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
253
249
|
}
|
254
250
|
if (schema.allOf) {
|
255
251
|
// intersection/add
|
256
|
-
const schemaWithoutAllOf = { ...schema, allOf: undefined }
|
252
|
+
const schemaWithoutAllOf = { ...schema, allOf: undefined } as OasTypes.SchemaObject
|
257
253
|
|
258
254
|
const and = factory.createIntersectionDeclaration({
|
259
255
|
withParentheses: true,
|
260
256
|
nodes: schema.allOf
|
261
|
-
.map((item
|
262
|
-
return this
|
257
|
+
.map((item) => {
|
258
|
+
return item && this.getTypeFromSchema(item as OasTypes.SchemaObject)
|
263
259
|
})
|
264
260
|
.filter((item) => {
|
265
261
|
return item && item !== factory.keywordTypeNodes.any
|
@@ -268,7 +264,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
268
264
|
|
269
265
|
if (schemaWithoutAllOf.properties) {
|
270
266
|
return factory.createIntersectionDeclaration({
|
271
|
-
nodes: [this
|
267
|
+
nodes: [this.getTypeFromSchema(schemaWithoutAllOf, baseName), and].filter(Boolean),
|
272
268
|
})
|
273
269
|
}
|
274
270
|
|
@@ -285,24 +281,24 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
285
281
|
|
286
282
|
if ('x-enumNames' in schema) {
|
287
283
|
enums = [...new Set(schema['x-enumNames'] as string[])].map((key: string, index) => {
|
288
|
-
return [key, schema.enum?.[index]]
|
284
|
+
return [key, schema.enum?.[index] as string]
|
289
285
|
})
|
290
286
|
}
|
291
287
|
|
292
288
|
this.extraNodes.push(
|
293
289
|
...factory.createEnumDeclaration({
|
294
|
-
name: camelCase(enumName
|
295
|
-
typeName: this.
|
290
|
+
name: transformers.camelCase(enumName),
|
291
|
+
typeName: this.context.pluginManager.resolveName({ name: enumName, pluginKey, type: 'type' }),
|
296
292
|
enums,
|
297
293
|
type: this.options.enumType,
|
298
294
|
}),
|
299
295
|
)
|
300
|
-
return factory.createTypeReferenceNode(this.
|
296
|
+
return factory.createTypeReferenceNode(this.context.pluginManager.resolveName({ name: enumName, pluginKey, type: 'type' }), undefined)
|
301
297
|
}
|
302
298
|
|
303
299
|
if (schema.enum) {
|
304
300
|
return factory.createUnionDeclaration({
|
305
|
-
nodes: schema.enum.map((name
|
301
|
+
nodes: schema.enum.map((name) => {
|
306
302
|
return factory.createLiteralTypeNode(typeof name === 'number' ? factory.createNumericLiteral(name) : factory.createStringLiteral(`${name}`))
|
307
303
|
}) as unknown as Array<ts.TypeNode>,
|
308
304
|
})
|
@@ -310,22 +306,24 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
310
306
|
|
311
307
|
if ('items' in schema) {
|
312
308
|
// items -> array
|
313
|
-
const node = this
|
309
|
+
const node = this.getTypeFromSchema(schema.items as OasTypes.SchemaObject, baseName)
|
314
310
|
if (node) {
|
315
311
|
return factory.createArrayTypeNode(node)
|
316
312
|
}
|
317
313
|
}
|
314
|
+
|
318
315
|
/**
|
319
316
|
* OpenAPI 3.1
|
320
317
|
* @link https://json-schema.org/understanding-json-schema/reference/array.html#tuple-validation
|
321
318
|
*/
|
319
|
+
|
322
320
|
if ('prefixItems' in schema) {
|
323
|
-
const prefixItems = schema.prefixItems as
|
321
|
+
const prefixItems = schema.prefixItems as OasTypes.SchemaObject[]
|
324
322
|
|
325
323
|
return factory.createTupleDeclaration({
|
326
324
|
nodes: prefixItems.map((item) => {
|
327
325
|
// no baseType so we can fall back on an union when using enum
|
328
|
-
return this
|
326
|
+
return this.getTypeFromSchema(item, undefined)
|
329
327
|
}) as Array<ts.TypeNode>,
|
330
328
|
})
|
331
329
|
}
|
@@ -335,14 +333,38 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
335
333
|
return this.#getTypeFromProperties(schema, baseName)
|
336
334
|
}
|
337
335
|
|
336
|
+
/**
|
337
|
+
* validate "const" property as defined in JSON-Schema-Validation
|
338
|
+
*
|
339
|
+
* https://json-schema.org/draft/2020-12/json-schema-validation#name-const
|
340
|
+
*
|
341
|
+
* > 6.1.3. const
|
342
|
+
* > The value of this keyword MAY be of any type, including null.
|
343
|
+
* > Use of this keyword is functionally equivalent to an "enum" (Section 6.1.2) with a single value.
|
344
|
+
* > An instance validates successfully against this keyword if its value is equal to the value of the keyword.
|
345
|
+
*/
|
346
|
+
if (version === '3.1' && 'const' in schema) {
|
347
|
+
// const keyword takes precendence over the actual type.
|
348
|
+
if (schema['const']) {
|
349
|
+
if (typeof schema['const'] === 'string') {
|
350
|
+
return factory.createLiteralTypeNode(factory.createStringLiteral(schema['const']))
|
351
|
+
} else if (typeof schema['const'] === 'number') {
|
352
|
+
return factory.createLiteralTypeNode(factory.createNumericLiteral(schema['const']))
|
353
|
+
}
|
354
|
+
} else {
|
355
|
+
return keywordTypeNodes.null
|
356
|
+
}
|
357
|
+
}
|
358
|
+
|
338
359
|
if (schema.type) {
|
339
360
|
if (Array.isArray(schema.type)) {
|
361
|
+
// TODO remove hardcoded first type, second nullable
|
340
362
|
// OPENAPI v3.1.0: https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0
|
341
|
-
const [type, nullable] = schema.type as Array<
|
363
|
+
const [type, nullable] = schema.type as Array<OpenAPIV3_1.NonArraySchemaObjectType>
|
342
364
|
|
343
365
|
return factory.createUnionDeclaration({
|
344
366
|
nodes: [
|
345
|
-
this
|
367
|
+
this.getTypeFromSchema(
|
346
368
|
{
|
347
369
|
...schema,
|
348
370
|
type,
|
@@ -368,11 +390,6 @@ export class TypeGenerator extends SchemaGenerator<Options, OpenAPIV3.SchemaObje
|
|
368
390
|
return factory.createTypeReferenceNode('Blob', [])
|
369
391
|
}
|
370
392
|
|
371
|
-
// detect assertion "const" and define the type property as a Literal
|
372
|
-
if ('const' in schema && schema['const'] !== undefined && typeof schema['const'] === 'string') {
|
373
|
-
return factory.createLiteralTypeNode(factory.createStringLiteral(schema['const']))
|
374
|
-
}
|
375
|
-
|
376
393
|
return factory.keywordTypeNodes.any
|
377
394
|
}
|
378
395
|
}
|
@@ -0,0 +1,137 @@
|
|
1
|
+
import transformers from '@kubb/core/transformers'
|
2
|
+
import { print } from '@kubb/parser'
|
3
|
+
import * as factory from '@kubb/parser/factory'
|
4
|
+
import { File, usePlugin, usePluginManager } from '@kubb/react'
|
5
|
+
import { useOas, useOperation, useOperationFile, useOperationName, useSchemas } from '@kubb/swagger/hooks'
|
6
|
+
|
7
|
+
import { TypeBuilder } from '../TypeBuilder.ts'
|
8
|
+
|
9
|
+
import type { KubbFile } from '@kubb/core'
|
10
|
+
import type { ts } from '@kubb/parser'
|
11
|
+
import type { Operation, OperationSchemas } from '@kubb/swagger'
|
12
|
+
import type { ReactNode } from 'react'
|
13
|
+
import type { FileMeta, PluginOptions } from '../types.ts'
|
14
|
+
|
15
|
+
type Props = {
|
16
|
+
builder: TypeBuilder
|
17
|
+
}
|
18
|
+
|
19
|
+
function printCombinedSchema(name: string, operation: Operation, schemas: OperationSchemas): string {
|
20
|
+
const properties: Record<string, ts.TypeNode> = {
|
21
|
+
'response': factory.createTypeReferenceNode(
|
22
|
+
factory.createIdentifier(schemas.response.name),
|
23
|
+
undefined,
|
24
|
+
),
|
25
|
+
}
|
26
|
+
|
27
|
+
if (schemas.request) {
|
28
|
+
properties['request'] = factory.createTypeReferenceNode(
|
29
|
+
factory.createIdentifier(schemas.request.name),
|
30
|
+
undefined,
|
31
|
+
)
|
32
|
+
}
|
33
|
+
|
34
|
+
if (schemas.pathParams) {
|
35
|
+
properties['pathParams'] = factory.createTypeReferenceNode(
|
36
|
+
factory.createIdentifier(schemas.pathParams.name),
|
37
|
+
undefined,
|
38
|
+
)
|
39
|
+
}
|
40
|
+
|
41
|
+
if (schemas.queryParams) {
|
42
|
+
properties['queryParams'] = factory.createTypeReferenceNode(
|
43
|
+
factory.createIdentifier(schemas.queryParams.name),
|
44
|
+
undefined,
|
45
|
+
)
|
46
|
+
}
|
47
|
+
|
48
|
+
if (schemas.headerParams) {
|
49
|
+
properties['headerParams'] = factory.createTypeReferenceNode(
|
50
|
+
factory.createIdentifier(schemas.headerParams.name),
|
51
|
+
undefined,
|
52
|
+
)
|
53
|
+
}
|
54
|
+
|
55
|
+
if (schemas.errors) {
|
56
|
+
properties['errors'] = factory.createUnionDeclaration({
|
57
|
+
nodes: schemas.errors.map(error => {
|
58
|
+
return factory.createTypeReferenceNode(
|
59
|
+
factory.createIdentifier(error.name),
|
60
|
+
undefined,
|
61
|
+
)
|
62
|
+
}),
|
63
|
+
})!
|
64
|
+
}
|
65
|
+
|
66
|
+
const namespaceNode = factory.createNamespaceDeclaration({
|
67
|
+
name: operation.method === 'get' ? `${name}Query` : `${name}Mutation`,
|
68
|
+
statements: Object.keys(properties).map(key => {
|
69
|
+
const type = properties[key]
|
70
|
+
if (!type) {
|
71
|
+
return undefined
|
72
|
+
}
|
73
|
+
return factory.createTypeAliasDeclaration({
|
74
|
+
modifiers: [factory.modifiers.export],
|
75
|
+
name: transformers.pascalCase(key),
|
76
|
+
type,
|
77
|
+
})
|
78
|
+
}).filter(Boolean),
|
79
|
+
})
|
80
|
+
|
81
|
+
return print(namespaceNode)
|
82
|
+
}
|
83
|
+
|
84
|
+
export function Mutation({
|
85
|
+
builder,
|
86
|
+
}: Props): ReactNode {
|
87
|
+
const { source } = builder.build()
|
88
|
+
|
89
|
+
return (
|
90
|
+
<>
|
91
|
+
{source}
|
92
|
+
</>
|
93
|
+
)
|
94
|
+
}
|
95
|
+
|
96
|
+
type FileProps = {
|
97
|
+
mode: KubbFile.Mode
|
98
|
+
}
|
99
|
+
|
100
|
+
Mutation.File = function({ mode }: FileProps): ReactNode {
|
101
|
+
const { options } = usePlugin<PluginOptions>()
|
102
|
+
|
103
|
+
const schemas = useSchemas()
|
104
|
+
const pluginManager = usePluginManager()
|
105
|
+
const oas = useOas()
|
106
|
+
const file = useOperationFile()
|
107
|
+
const factoryName = useOperationName({ type: 'type' })
|
108
|
+
const operation = useOperation()
|
109
|
+
|
110
|
+
const builder = new TypeBuilder(options, { oas, pluginManager })
|
111
|
+
.add(schemas.pathParams)
|
112
|
+
.add(schemas.queryParams)
|
113
|
+
.add(schemas.headerParams)
|
114
|
+
.add(schemas.response)
|
115
|
+
.add(schemas.request)
|
116
|
+
.add(schemas.errors)
|
117
|
+
|
118
|
+
const { source, imports } = builder.build()
|
119
|
+
|
120
|
+
return (
|
121
|
+
<>
|
122
|
+
<File<FileMeta>
|
123
|
+
baseName={file.baseName}
|
124
|
+
path={file.path}
|
125
|
+
meta={file.meta}
|
126
|
+
>
|
127
|
+
{mode === 'directory' && imports.map((item, index) => {
|
128
|
+
return <File.Import key={index} root={file.path} {...item} />
|
129
|
+
})}
|
130
|
+
<File.Source>
|
131
|
+
{source}
|
132
|
+
{printCombinedSchema(factoryName, operation, schemas)}
|
133
|
+
</File.Source>
|
134
|
+
</File>
|
135
|
+
</>
|
136
|
+
)
|
137
|
+
}
|
@@ -0,0 +1,84 @@
|
|
1
|
+
import { File, Type, usePlugin } from '@kubb/react'
|
2
|
+
import { useFile } from '@kubb/react'
|
3
|
+
import { useOas } from '@kubb/swagger/hooks'
|
4
|
+
|
5
|
+
import type { OasTypes } from '@kubb/swagger'
|
6
|
+
import type { ReactNode } from 'react'
|
7
|
+
import type { FileMeta, PluginOptions } from '../types.ts'
|
8
|
+
|
9
|
+
type TemplateProps = {
|
10
|
+
/**
|
11
|
+
* Name of the function
|
12
|
+
*/
|
13
|
+
name: string
|
14
|
+
typeName: string
|
15
|
+
api: OasTypes.OASDocument
|
16
|
+
}
|
17
|
+
|
18
|
+
function Template({
|
19
|
+
name,
|
20
|
+
typeName,
|
21
|
+
api,
|
22
|
+
}: TemplateProps): ReactNode {
|
23
|
+
return (
|
24
|
+
<>
|
25
|
+
{`export const ${name} = ${JSON.stringify(api, undefined, 2)} as const`}
|
26
|
+
<br />
|
27
|
+
<Type name={typeName} export>
|
28
|
+
{`Infer<typeof ${name}>`}
|
29
|
+
</Type>
|
30
|
+
</>
|
31
|
+
)
|
32
|
+
}
|
33
|
+
|
34
|
+
const defaultTemplates = { default: Template } as const
|
35
|
+
|
36
|
+
type Props = {
|
37
|
+
name: string
|
38
|
+
typeName: string
|
39
|
+
/**
|
40
|
+
* This will make it possible to override the default behaviour.
|
41
|
+
*/
|
42
|
+
Template?: React.ComponentType<React.ComponentProps<typeof Template>>
|
43
|
+
}
|
44
|
+
|
45
|
+
export function Oas({
|
46
|
+
name,
|
47
|
+
typeName,
|
48
|
+
Template = defaultTemplates.default,
|
49
|
+
}: Props): ReactNode {
|
50
|
+
const oas = useOas()
|
51
|
+
|
52
|
+
return <Template name={name} typeName={typeName} api={oas.api} />
|
53
|
+
}
|
54
|
+
|
55
|
+
type FileProps = {
|
56
|
+
name: string
|
57
|
+
typeName: string
|
58
|
+
/**
|
59
|
+
* This will make it possible to override the default behaviour.
|
60
|
+
*/
|
61
|
+
templates?: typeof defaultTemplates
|
62
|
+
}
|
63
|
+
|
64
|
+
Oas.File = function({ name, typeName, templates = defaultTemplates }: FileProps): ReactNode {
|
65
|
+
const { key: pluginKey } = usePlugin<PluginOptions>()
|
66
|
+
const file = useFile({ name, pluginKey })
|
67
|
+
|
68
|
+
const Template = templates.default
|
69
|
+
|
70
|
+
return (
|
71
|
+
<File<FileMeta>
|
72
|
+
baseName={file.baseName}
|
73
|
+
path={file.path}
|
74
|
+
meta={file.meta}
|
75
|
+
>
|
76
|
+
<File.Import name={['Infer']} path="@kubb/swagger-ts/oas" isTypeOnly />
|
77
|
+
<File.Source>
|
78
|
+
<Oas Template={Template} name={name} typeName={typeName} />
|
79
|
+
</File.Source>
|
80
|
+
</File>
|
81
|
+
)
|
82
|
+
}
|
83
|
+
|
84
|
+
Oas.templates = defaultTemplates
|