@kubb/swagger-ts 2.0.0-beta.1 → 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/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 +3561 -289
- 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 +3563 -292
- 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 +21 -7
- package/src/OperationGenerator.tsx +62 -0
- package/src/TypeBuilder.ts +58 -0
- package/src/{generators/TypeGenerator.ts → TypeGenerator.ts} +78 -68
- 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 +52 -107
- package/src/types.ts +41 -13
- package/src/builders/TypeBuilder.ts +0 -94
- package/src/builders/index.ts +0 -1
- package/src/generators/OperationGenerator.ts +0 -213
- package/src/generators/index.ts +0 -2
@@ -1,30 +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'
|
5
|
+
import { keywordTypeNodes } from '@kubb/parser/factory'
|
4
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 { Oas, OasTypes, OpenAPIV3, OpenAPIV3_1, 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
|
17
|
+
type Context = {
|
16
18
|
oas: Oas
|
17
|
-
|
18
|
-
|
19
|
-
withJSDocs?: boolean
|
20
|
-
resolveName: PluginContext['resolveName']
|
21
|
-
enumType: 'enum' | 'asConst' | 'asPascalConst'
|
22
|
-
dateType: 'string' | 'date'
|
23
|
-
optionalType: 'questionToken' | 'undefined' | 'questionTokenAndUndefined'
|
19
|
+
pluginManager: PluginManager
|
24
20
|
}
|
25
21
|
|
26
|
-
export class TypeGenerator extends
|
22
|
+
export class TypeGenerator extends Generator<PluginOptions['resolvedOptions'], Context> {
|
27
23
|
refs: Refs = {}
|
24
|
+
imports: ImportMeta[] = []
|
28
25
|
|
29
26
|
extraNodes: ts.Node[] = []
|
30
27
|
|
@@ -33,19 +30,6 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
33
30
|
// Keep track of already used type aliases
|
34
31
|
#usedAliasNames: Record<string, number> = {}
|
35
32
|
|
36
|
-
#caseOptions: CaseOptions = {
|
37
|
-
delimiter: '',
|
38
|
-
stripRegexp: /[^A-Z0-9$]/gi,
|
39
|
-
}
|
40
|
-
|
41
|
-
constructor(
|
42
|
-
options: Options,
|
43
|
-
) {
|
44
|
-
super(options)
|
45
|
-
|
46
|
-
return this
|
47
|
-
}
|
48
|
-
|
49
33
|
build({
|
50
34
|
schema,
|
51
35
|
baseName,
|
@@ -58,7 +42,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
58
42
|
keysToOmit?: string[]
|
59
43
|
}): ts.Node[] {
|
60
44
|
const nodes: ts.Node[] = []
|
61
|
-
const type = this
|
45
|
+
const type = this.getTypeFromSchema(schema, baseName)
|
62
46
|
|
63
47
|
if (!type) {
|
64
48
|
return this.extraNodes
|
@@ -66,7 +50,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
66
50
|
|
67
51
|
const node = factory.createTypeAliasDeclaration({
|
68
52
|
modifiers: [factory.modifiers.export],
|
69
|
-
name: this.
|
53
|
+
name: this.context.pluginManager.resolveName({ name: baseName, pluginKey, type: 'type' }),
|
70
54
|
type: keysToOmit?.length ? factory.createOmitDeclaration({ keys: keysToOmit, type, nonNullable: true }) : type,
|
71
55
|
})
|
72
56
|
|
@@ -74,7 +58,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
74
58
|
nodes.push(
|
75
59
|
factory.appendJSDocToNode({
|
76
60
|
node,
|
77
|
-
comments: [`@description ${description}`],
|
61
|
+
comments: [`@description ${transformers.trim(description)}`],
|
78
62
|
}),
|
79
63
|
)
|
80
64
|
} else {
|
@@ -97,7 +81,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
97
81
|
* Delegates to getBaseTypeFromSchema internally and
|
98
82
|
* optionally adds a union with null.
|
99
83
|
*/
|
100
|
-
|
84
|
+
getTypeFromSchema(schema?: OasTypes.SchemaObject, name?: string): ts.TypeNode | null {
|
101
85
|
const type = this.#getBaseTypeFromSchema(schema, name)
|
102
86
|
|
103
87
|
if (!type) {
|
@@ -114,7 +98,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
114
98
|
/**
|
115
99
|
* Recursively creates a type literal with the given props.
|
116
100
|
*/
|
117
|
-
#getTypeFromProperties(baseSchema?: OasTypes.SchemaObject, baseName?: string) {
|
101
|
+
#getTypeFromProperties(baseSchema?: OasTypes.SchemaObject, baseName?: string): ts.TypeNode | null {
|
118
102
|
const { optionalType } = this.options
|
119
103
|
const properties = baseSchema?.properties || {}
|
120
104
|
const required = baseSchema?.required
|
@@ -124,39 +108,38 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
124
108
|
const schema = properties[name] as OasTypes.SchemaObject
|
125
109
|
|
126
110
|
const isRequired = Array.isArray(required) ? required.includes(name) : !!required
|
127
|
-
let type = this
|
111
|
+
let type = this.getTypeFromSchema(schema, this.context.pluginManager.resolveName({ name: `${baseName || ''} ${name}`, pluginKey, type: 'type' }))
|
128
112
|
|
129
113
|
if (!type) {
|
130
114
|
return null
|
131
115
|
}
|
132
116
|
|
133
|
-
if (!isRequired && ['undefined', 'questionTokenAndUndefined'].includes(optionalType)) {
|
117
|
+
if (!isRequired && ['undefined', 'questionTokenAndUndefined'].includes(optionalType as string)) {
|
134
118
|
type = factory.createUnionDeclaration({ nodes: [type, factory.keywordTypeNodes.undefined] })
|
135
119
|
}
|
136
120
|
const propertySignature = factory.createPropertySignature({
|
137
|
-
questionToken: ['questionToken', 'questionTokenAndUndefined'].includes(optionalType) && !isRequired,
|
121
|
+
questionToken: ['questionToken', 'questionTokenAndUndefined'].includes(optionalType as string) && !isRequired,
|
138
122
|
name,
|
139
123
|
type: type as ts.TypeNode,
|
140
124
|
readOnly: schema.readOnly,
|
141
125
|
})
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
}
|
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
|
+
})
|
155
138
|
|
156
139
|
return propertySignature
|
157
140
|
})
|
158
141
|
if (additionalProperties) {
|
159
|
-
const type = additionalProperties === true ? factory.keywordTypeNodes.any : this
|
142
|
+
const type = additionalProperties === true ? factory.keywordTypeNodes.any : this.getTypeFromSchema(additionalProperties as OasTypes.SchemaObject)
|
160
143
|
|
161
144
|
if (type) {
|
162
145
|
members.push(factory.createIndexSignature(type))
|
@@ -177,18 +160,26 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
177
160
|
}
|
178
161
|
|
179
162
|
const originalName = getUniqueName($ref.replace(/.+\//, ''), this.#usedAliasNames)
|
180
|
-
const propertyName = this.
|
163
|
+
const propertyName = this.context.pluginManager.resolveName({ name: originalName, pluginKey, type: 'type' })
|
181
164
|
|
182
165
|
ref = this.refs[$ref] = {
|
183
166
|
propertyName,
|
184
167
|
originalName,
|
185
168
|
}
|
186
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
|
+
|
187
178
|
return factory.createTypeReferenceNode(ref.propertyName, undefined)
|
188
179
|
}
|
189
180
|
|
190
181
|
#getParsedSchema(schema?: OasTypes.SchemaObject) {
|
191
|
-
const parsedSchema = getSchemaFactory(this.
|
182
|
+
const parsedSchema = getSchemaFactory(this.context.oas)(schema)
|
192
183
|
return parsedSchema
|
193
184
|
}
|
194
185
|
|
@@ -218,7 +209,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
218
209
|
withParentheses: true,
|
219
210
|
nodes: schema.oneOf
|
220
211
|
.map((item) => {
|
221
|
-
return item && this
|
212
|
+
return item && this.getTypeFromSchema(item as OasTypes.SchemaObject)
|
222
213
|
})
|
223
214
|
.filter((item) => {
|
224
215
|
return item && item !== factory.keywordTypeNodes.any
|
@@ -227,7 +218,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
227
218
|
|
228
219
|
if (schemaWithoutOneOf.properties) {
|
229
220
|
return factory.createIntersectionDeclaration({
|
230
|
-
nodes: [this
|
221
|
+
nodes: [this.getTypeFromSchema(schemaWithoutOneOf, baseName), union].filter(Boolean),
|
231
222
|
})
|
232
223
|
}
|
233
224
|
|
@@ -241,7 +232,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
241
232
|
withParentheses: true,
|
242
233
|
nodes: schema.anyOf
|
243
234
|
.map((item) => {
|
244
|
-
return item && this
|
235
|
+
return item && this.getTypeFromSchema(item as OasTypes.SchemaObject)
|
245
236
|
})
|
246
237
|
.filter((item) => {
|
247
238
|
return item && item !== factory.keywordTypeNodes.any
|
@@ -250,7 +241,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
250
241
|
|
251
242
|
if (schemaWithoutAnyOf.properties) {
|
252
243
|
return factory.createIntersectionDeclaration({
|
253
|
-
nodes: [this
|
244
|
+
nodes: [this.getTypeFromSchema(schemaWithoutAnyOf, baseName), union].filter(Boolean),
|
254
245
|
})
|
255
246
|
}
|
256
247
|
|
@@ -264,7 +255,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
264
255
|
withParentheses: true,
|
265
256
|
nodes: schema.allOf
|
266
257
|
.map((item) => {
|
267
|
-
return item && this
|
258
|
+
return item && this.getTypeFromSchema(item as OasTypes.SchemaObject)
|
268
259
|
})
|
269
260
|
.filter((item) => {
|
270
261
|
return item && item !== factory.keywordTypeNodes.any
|
@@ -273,7 +264,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
273
264
|
|
274
265
|
if (schemaWithoutAllOf.properties) {
|
275
266
|
return factory.createIntersectionDeclaration({
|
276
|
-
nodes: [this
|
267
|
+
nodes: [this.getTypeFromSchema(schemaWithoutAllOf, baseName), and].filter(Boolean),
|
277
268
|
})
|
278
269
|
}
|
279
270
|
|
@@ -296,13 +287,13 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
296
287
|
|
297
288
|
this.extraNodes.push(
|
298
289
|
...factory.createEnumDeclaration({
|
299
|
-
name: camelCase(enumName
|
300
|
-
typeName: this.
|
290
|
+
name: transformers.camelCase(enumName),
|
291
|
+
typeName: this.context.pluginManager.resolveName({ name: enumName, pluginKey, type: 'type' }),
|
301
292
|
enums,
|
302
293
|
type: this.options.enumType,
|
303
294
|
}),
|
304
295
|
)
|
305
|
-
return factory.createTypeReferenceNode(this.
|
296
|
+
return factory.createTypeReferenceNode(this.context.pluginManager.resolveName({ name: enumName, pluginKey, type: 'type' }), undefined)
|
306
297
|
}
|
307
298
|
|
308
299
|
if (schema.enum) {
|
@@ -315,7 +306,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
315
306
|
|
316
307
|
if ('items' in schema) {
|
317
308
|
// items -> array
|
318
|
-
const node = this
|
309
|
+
const node = this.getTypeFromSchema(schema.items as OasTypes.SchemaObject, baseName)
|
319
310
|
if (node) {
|
320
311
|
return factory.createArrayTypeNode(node)
|
321
312
|
}
|
@@ -332,7 +323,7 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
332
323
|
return factory.createTupleDeclaration({
|
333
324
|
nodes: prefixItems.map((item) => {
|
334
325
|
// no baseType so we can fall back on an union when using enum
|
335
|
-
return this
|
326
|
+
return this.getTypeFromSchema(item, undefined)
|
336
327
|
}) as Array<ts.TypeNode>,
|
337
328
|
})
|
338
329
|
}
|
@@ -342,14 +333,38 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
342
333
|
return this.#getTypeFromProperties(schema, baseName)
|
343
334
|
}
|
344
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
|
+
|
345
359
|
if (schema.type) {
|
346
360
|
if (Array.isArray(schema.type)) {
|
361
|
+
// TODO remove hardcoded first type, second nullable
|
347
362
|
// OPENAPI v3.1.0: https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0
|
348
363
|
const [type, nullable] = schema.type as Array<OpenAPIV3_1.NonArraySchemaObjectType>
|
349
364
|
|
350
365
|
return factory.createUnionDeclaration({
|
351
366
|
nodes: [
|
352
|
-
this
|
367
|
+
this.getTypeFromSchema(
|
353
368
|
{
|
354
369
|
...schema,
|
355
370
|
type,
|
@@ -375,11 +390,6 @@ export class TypeGenerator extends SchemaGenerator<Options, OasTypes.SchemaObjec
|
|
375
390
|
return factory.createTypeReferenceNode('Blob', [])
|
376
391
|
}
|
377
392
|
|
378
|
-
// detect assertion "const" and define the type property as a Literal
|
379
|
-
if (version === '3.1' && typeof schema['const'] === 'string') {
|
380
|
-
return factory.createLiteralTypeNode(factory.createStringLiteral(schema['const']))
|
381
|
-
}
|
382
|
-
|
383
393
|
return factory.keywordTypeNodes.any
|
384
394
|
}
|
385
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
|
@@ -0,0 +1,136 @@
|
|
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 Query({
|
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
|
+
Query.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.errors)
|
116
|
+
|
117
|
+
const { source, imports } = builder.build()
|
118
|
+
|
119
|
+
return (
|
120
|
+
<>
|
121
|
+
<File<FileMeta>
|
122
|
+
baseName={file.baseName}
|
123
|
+
path={file.path}
|
124
|
+
meta={file.meta}
|
125
|
+
>
|
126
|
+
{mode === 'directory' && imports.map((item, index) => {
|
127
|
+
return <File.Import key={index} root={file.path} {...item} />
|
128
|
+
})}
|
129
|
+
<File.Source>
|
130
|
+
{source}
|
131
|
+
{printCombinedSchema(factoryName, operation, schemas)}
|
132
|
+
</File.Source>
|
133
|
+
</File>
|
134
|
+
</>
|
135
|
+
)
|
136
|
+
}
|