@kubb/swagger-ts 2.10.0 → 2.11.1

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.
@@ -2,9 +2,8 @@ import { createRoot } from '@kubb/react'
2
2
  import { OperationGenerator as Generator } from '@kubb/swagger'
3
3
  import { Oas } from '@kubb/swagger/components'
4
4
 
5
- import { Mutation } from './components/Mutation.tsx'
6
5
  import { OasType } from './components/OasType.tsx'
7
- import { Query } from './components/Query.tsx'
6
+ import { OperationSchema } from './components/OperationSchema.tsx'
8
7
 
9
8
  import type { AppContextProps } from '@kubb/react'
10
9
  import type { OperationMethodResult } from '@kubb/swagger'
@@ -18,7 +17,7 @@ export class OperationGenerator extends Generator<PluginOptions['resolvedOptions
18
17
  const root = createRoot<AppContextProps<PluginOptions['appMeta']>>({ logger: pluginManager.logger })
19
18
 
20
19
  root.render(
21
- <Oas oas={oas} operations={operations} getSchemas={(...props) => this.getSchemas(...props)}>
20
+ <Oas oas={oas} operations={operations} getOperationSchemas={(...props) => this.getSchemas(...props)}>
22
21
  {plugin.options.oasType && <OasType.File name="oas" typeName="Oas" />}
23
22
  </Oas>,
24
23
  { meta: { pluginManager, plugin } },
@@ -27,14 +26,17 @@ export class OperationGenerator extends Generator<PluginOptions['resolvedOptions
27
26
  return root.files
28
27
  }
29
28
 
30
- async get(operation: Operation, options: PluginOptions['resolvedOptions']): OperationMethodResult<FileMeta> {
31
- const { oas, pluginManager, plugin, mode = 'directory' } = this.context
29
+ async operation(
30
+ operation: Operation,
31
+ options: PluginOptions['resolvedOptions'],
32
+ ): OperationMethodResult<FileMeta> {
33
+ const { oas, pluginManager, plugin, mode } = this.context
32
34
 
33
35
  const root = createRoot<AppContextProps<PluginOptions['appMeta']>>({ logger: pluginManager.logger })
34
36
  root.render(
35
- <Oas oas={oas} operations={[operation]} getSchemas={(...props) => this.getSchemas(...props)}>
37
+ <Oas oas={oas} operations={[operation]} getOperationSchemas={(...props) => this.getSchemas(...props)}>
36
38
  <Oas.Operation operation={operation}>
37
- <Query.File mode={mode} />
39
+ <OperationSchema.File mode={mode} />
38
40
  </Oas.Operation>
39
41
  </Oas>,
40
42
  { meta: { pluginManager, plugin: { ...plugin, options } } },
@@ -43,29 +45,21 @@ export class OperationGenerator extends Generator<PluginOptions['resolvedOptions
43
45
  return root.files
44
46
  }
45
47
 
46
- async post(operation: Operation, options: PluginOptions['resolvedOptions']): OperationMethodResult<FileMeta> {
47
- const { oas, pluginManager, plugin, mode = 'directory' } = this.context
48
-
49
- const root = createRoot<AppContextProps<PluginOptions['appMeta']>>({ logger: pluginManager.logger })
50
- root.render(
51
- <Oas oas={oas} operations={[operation]} getSchemas={(...props) => this.getSchemas(...props)}>
52
- <Oas.Operation operation={operation}>
53
- <Mutation.File mode={mode} />
54
- </Oas.Operation>
55
- </Oas>,
56
- { meta: { pluginManager, plugin: { ...plugin, options } } },
57
- )
48
+ async get(): OperationMethodResult<FileMeta> {
49
+ return null
50
+ }
58
51
 
59
- return root.files
52
+ async post(): OperationMethodResult<FileMeta> {
53
+ return null
60
54
  }
61
55
 
62
- async put(operation: Operation, options: PluginOptions['resolvedOptions']): OperationMethodResult<FileMeta> {
63
- return this.post(operation, options)
56
+ async put(): OperationMethodResult<FileMeta> {
57
+ return null
64
58
  }
65
- async patch(operation: Operation, options: PluginOptions['resolvedOptions']): OperationMethodResult<FileMeta> {
66
- return this.post(operation, options)
59
+ async patch(): OperationMethodResult<FileMeta> {
60
+ return null
67
61
  }
68
- async delete(operation: Operation, options: PluginOptions['resolvedOptions']): OperationMethodResult<FileMeta> {
69
- return this.post(operation, options)
62
+ async delete(): OperationMethodResult<FileMeta> {
63
+ return null
70
64
  }
71
65
  }
@@ -0,0 +1,63 @@
1
+ import { createRoot } from '@kubb/react'
2
+ import { SchemaGenerator as Generator } from '@kubb/swagger'
3
+ import { Oas, Schema } from '@kubb/swagger/components'
4
+ import { pluginKey as swaggerTypeScriptPluginKey } from '@kubb/swagger-ts'
5
+
6
+ import { pluginKey } from './plugin.ts'
7
+ import { typeParser } from './typeParser.ts'
8
+
9
+ import type { AppContextProps } from '@kubb/react'
10
+ import type { Schema as SchemaType, SchemaGeneratorBuildOptions, SchemaMethodResult } from '@kubb/swagger'
11
+ import type { SchemaObject } from '@kubb/swagger/oas'
12
+ import type { FileMeta, PluginOptions } from './types.ts'
13
+
14
+ export class SchemaGenerator extends Generator<PluginOptions['resolvedOptions'], PluginOptions> {
15
+ async schema(name: string, object: SchemaObject): SchemaMethodResult<FileMeta> {
16
+ const { oas, pluginManager, mode, plugin, output } = this.context
17
+
18
+ const root = createRoot<AppContextProps<PluginOptions['appMeta']>>({ logger: pluginManager.logger })
19
+
20
+ root.render(
21
+ <Oas oas={oas}>
22
+ <Oas.Schema generator={this} name={name} object={object}>
23
+ <Schema.File isTypeOnly output={output} mode={mode} />
24
+ </Oas.Schema>
25
+ </Oas>,
26
+ { meta: { pluginManager, plugin } },
27
+ )
28
+
29
+ return root.files
30
+ }
31
+ // TODO convert to a react component called `Schema.Parser` with props parser as part of the SchemaContext
32
+ getSource(name: string, schemas: SchemaType[], {
33
+ keysToOmit,
34
+ description,
35
+ }: SchemaGeneratorBuildOptions = {}): string[] {
36
+ const texts: string[] = []
37
+
38
+ const resolvedName = this.context.pluginManager.resolveName({ name, pluginKey, type: 'function' })
39
+ const resvoledTypeName = this.context.pluginManager.resolveName({ name, pluginKey: swaggerTypeScriptPluginKey, type: 'type' })
40
+
41
+ const typeOutput = typeParser(schemas, {
42
+ name: resolvedName,
43
+ typeName: resvoledTypeName,
44
+ description,
45
+ enumType: this.options.enumType || 'asConst',
46
+ optionalType: this.options.optionalType,
47
+ keysToOmit,
48
+ })
49
+
50
+ texts.push(typeOutput)
51
+
52
+ return texts
53
+ }
54
+ /**
55
+ * @deprecated only used for testing
56
+ */
57
+
58
+ buildSource(name: string, schema: SchemaObject, options: SchemaGeneratorBuildOptions = {}): string[] {
59
+ const schemas = this.buildSchemas(schema, name)
60
+
61
+ return this.getSource(name, schemas, options)
62
+ }
63
+ }
@@ -1,5 +1,5 @@
1
1
  import { Editor, File, Type, usePlugin } from '@kubb/react'
2
- import { useFile } from '@kubb/react'
2
+ import { useGetFile } from '@kubb/react'
3
3
  import { useOas } from '@kubb/swagger/hooks'
4
4
 
5
5
  import type { OasTypes } from '@kubb/swagger/oas'
@@ -63,7 +63,7 @@ type FileProps = {
63
63
 
64
64
  OasType.File = function({ name, typeName, templates = defaultTemplates }: FileProps): ReactNode {
65
65
  const { key: pluginKey } = usePlugin<PluginOptions>()
66
- const file = useFile({ name, extName: '.ts', pluginKey })
66
+ const file = useGetFile({ name, extName: '.ts', pluginKey })
67
67
 
68
68
  const Template = templates.default
69
69
 
@@ -1,21 +1,23 @@
1
+ /* eslint-disable no-empty-pattern */
2
+ /* eslint-disable @typescript-eslint/ban-types */
1
3
  import transformers from '@kubb/core/transformers'
2
4
  import { print } from '@kubb/parser'
3
5
  import * as factory from '@kubb/parser/factory'
4
6
  import { Editor, File, usePlugin, usePluginManager } from '@kubb/react'
5
- import { useOas, useOperation, useOperationFile, useOperationName, useSchemas } from '@kubb/swagger/hooks'
7
+ import { Oas, Schema } from '@kubb/swagger/components'
8
+ import { useGetOperationFile, useOas, useOperation, useOperationName, useOperationSchemas } from '@kubb/swagger/hooks'
6
9
 
7
- import { TypeBuilder } from '../TypeBuilder.ts'
10
+ import { SchemaGenerator } from '../SchemaGenerator.tsx'
8
11
 
9
12
  import type { KubbFile } from '@kubb/core'
10
13
  import type { ts } from '@kubb/parser'
14
+ import type { OperationSchema as OperationSchemaType } from '@kubb/swagger'
11
15
  import type { OperationSchemas } from '@kubb/swagger'
12
16
  import type { Operation } from '@kubb/swagger/oas'
13
17
  import type { ReactNode } from 'react'
14
18
  import type { FileMeta, PluginOptions } from '../types.ts'
15
19
 
16
- type Props = {
17
- builder: TypeBuilder
18
- }
20
+ type Props = {}
19
21
 
20
22
  function printCombinedSchema(name: string, operation: Operation, schemas: OperationSchemas): string {
21
23
  const properties: Record<string, ts.TypeNode> = {
@@ -87,40 +89,49 @@ function printCombinedSchema(name: string, operation: Operation, schemas: Operat
87
89
  return print(namespaceNode)
88
90
  }
89
91
 
90
- export function Query({
91
- builder,
92
- }: Props): ReactNode {
93
- const { source } = builder.build()
94
-
92
+ export function OperationSchema({}: Props): ReactNode {
95
93
  return (
96
94
  <>
97
- {source}
98
95
  </>
99
96
  )
100
97
  }
101
98
 
102
99
  type FileProps = {
103
- mode: KubbFile.Mode
100
+ mode: KubbFile.Mode | undefined
104
101
  }
105
102
 
106
- Query.File = function({ mode }: FileProps): ReactNode {
103
+ OperationSchema.File = function({ mode = 'directory' }: FileProps): ReactNode {
107
104
  const plugin = usePlugin<PluginOptions>()
108
105
 
109
- const schemas = useSchemas()
110
106
  const pluginManager = usePluginManager()
111
107
  const oas = useOas()
112
- const file = useOperationFile()
108
+ const schemas = useOperationSchemas()
109
+ const file = useGetOperationFile()
113
110
  const factoryName = useOperationName({ type: 'type' })
114
111
  const operation = useOperation()
115
112
 
116
- const builder = new TypeBuilder(plugin.options, { oas, plugin, pluginManager })
117
- .add(schemas.pathParams)
118
- .add(schemas.queryParams)
119
- .add(schemas.headerParams)
120
- .add(schemas.response)
121
- .add(schemas.statusCodes)
122
-
123
- const { source, imports } = builder.build()
113
+ const generator = new SchemaGenerator(plugin.options, { oas, plugin, pluginManager })
114
+
115
+ const items = [
116
+ schemas.pathParams,
117
+ schemas.queryParams,
118
+ schemas.headerParams,
119
+ schemas.statusCodes,
120
+ schemas.request,
121
+ schemas.response,
122
+ ].flat().filter(Boolean)
123
+
124
+ const mapItem = ({ name, schema: object, ...options }: OperationSchemaType, i: number) => {
125
+ return (
126
+ <Oas.Schema key={i} generator={generator} name={name} object={object}>
127
+ {mode === 'directory'
128
+ && <Schema.Imports isTypeOnly />}
129
+ <File.Source>
130
+ <Schema.Source options={options} />
131
+ </File.Source>
132
+ </Oas.Schema>
133
+ )
134
+ }
124
135
 
125
136
  return (
126
137
  <Editor language="typescript">
@@ -129,11 +140,9 @@ Query.File = function({ mode }: FileProps): ReactNode {
129
140
  path={file.path}
130
141
  meta={file.meta}
131
142
  >
132
- {mode === 'directory' && imports.map((item, index) => {
133
- return <File.Import key={index} root={file.path} {...item} />
134
- })}
143
+ {items.map(mapItem)}
144
+
135
145
  <File.Source>
136
- {source}
137
146
  {printCombinedSchema(factoryName, operation, schemas)}
138
147
  </File.Source>
139
148
  </File>
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @description Null response
3
+ */
4
+ export type CreatePets201 = any
5
+
6
+ /**
7
+ * @description unexpected error
8
+ */
9
+ export type CreatePetsError = Error
10
+
11
+ export type CreatePetsMutationRequest = {
12
+ /**
13
+ * @type string
14
+ */
15
+ name: string
16
+ /**
17
+ * @type string
18
+ */
19
+ tag: string
20
+ }
21
+
22
+ export type CreatePetsMutationResponse = any
23
+
24
+ export type CreatePetsMutation = {
25
+ Response: CreatePetsMutationResponse
26
+ Request: CreatePetsMutationRequest
27
+ }
@@ -0,0 +1,32 @@
1
+ export type ShowPetByIdPathParams = {
2
+ /**
3
+ * @description The id of the pet to retrieve
4
+ * @type string
5
+ */
6
+ petId: string
7
+ /**
8
+ * @description The id of the pet to retrieve
9
+ * @type string
10
+ */
11
+ testId: string
12
+ }
13
+
14
+ /**
15
+ * @description Expected response to a valid request
16
+ */
17
+ export type ShowPetById200 = Pet
18
+
19
+ /**
20
+ * @description unexpected error
21
+ */
22
+ export type ShowPetByIdError = Error
23
+
24
+ /**
25
+ * @description Expected response to a valid request
26
+ */
27
+ export type ShowPetByIdQueryResponse = Pet
28
+
29
+ export type ShowPetByIdQuery = {
30
+ Response: ShowPetByIdQueryResponse
31
+ PathParams: ShowPetByIdPathParams
32
+ }
@@ -1,3 +1,2 @@
1
- export { Mutation } from './Mutation.tsx'
2
1
  export { OasType } from './OasType.tsx'
3
- export { Query } from './Query.tsx'
2
+ export { OperationSchema } from './OperationSchema.tsx'
package/src/plugin.ts CHANGED
@@ -6,11 +6,10 @@ import { renderTemplate } from '@kubb/core/utils'
6
6
  import { pluginName as swaggerPluginName } from '@kubb/swagger'
7
7
 
8
8
  import { OperationGenerator } from './OperationGenerator.tsx'
9
- import { TypeBuilder } from './TypeBuilder.ts'
9
+ import { SchemaGenerator } from './SchemaGenerator.tsx'
10
10
 
11
- import type { KubbFile, Plugin } from '@kubb/core'
11
+ import type { Plugin } from '@kubb/core'
12
12
  import type { PluginOptions as SwaggerPluginOptions } from '@kubb/swagger'
13
- import type { OasTypes } from '@kubb/swagger/oas'
14
13
  import type { PluginOptions } from './types.ts'
15
14
  export const pluginName = 'swagger-ts' satisfies PluginOptions['name']
16
15
  export const pluginKey: PluginOptions['key'] = [pluginName] satisfies PluginOptions['key']
@@ -37,11 +36,11 @@ export const definePlugin = createPlugin<PluginOptions>((options) => {
37
36
  options: {
38
37
  transformers,
39
38
  dateType,
40
- enumType,
41
- enumSuffix,
42
39
  optionalType,
43
40
  oasType,
44
- // keep the used enumnames between TypeBuilder and OperationGenerator per plugin(pluginKey)
41
+ enumType,
42
+ enumSuffix,
43
+ // keep the used enumnames between SchemaGenerator and OperationGenerator per plugin(pluginKey)
45
44
  usedEnumNames: {},
46
45
  unknownType,
47
46
  },
@@ -86,60 +85,24 @@ export const definePlugin = createPlugin<PluginOptions>((options) => {
86
85
  const [swaggerPlugin]: [Plugin<SwaggerPluginOptions>] = PluginManager.getDependedPlugins<SwaggerPluginOptions>(this.plugins, [swaggerPluginName])
87
86
 
88
87
  const oas = await swaggerPlugin.api.getOas()
89
-
90
- const schemas = await swaggerPlugin.api.getSchemas()
91
88
  const root = path.resolve(this.config.root, this.config.output.path)
92
89
  const mode = FileManager.getMode(path.resolve(root, output.path))
93
- const builder = new TypeBuilder(this.plugin.options, { oas, plugin: this.plugin, pluginManager: this.pluginManager })
94
90
 
95
- builder.add(
96
- Object.entries(schemas).map(([name, schema]: [string, OasTypes.SchemaObject]) => ({ name, schema })),
91
+ const schemaGenerator = new SchemaGenerator(
92
+ this.plugin.options,
93
+ {
94
+ oas,
95
+ pluginManager: this.pluginManager,
96
+ plugin: this.plugin,
97
+ contentType: swaggerPlugin.api.contentType,
98
+ include: undefined,
99
+ mode,
100
+ output: output.path,
101
+ },
97
102
  )
98
103
 
99
- if (mode === 'directory') {
100
- const mapFolderSchema = async ([name]: [string, OasTypes.SchemaObject]) => {
101
- const baseName = `${this.resolveName({ name, pluginKey: this.plugin.key, type: 'file' })}.ts` as const
102
- const resolvedPath = this.resolvePath({ baseName, pluginKey: this.plugin.key })
103
- const { source, imports } = builder.build(name)
104
-
105
- if (!resolvedPath) {
106
- return null
107
- }
108
-
109
- return this.addFile({
110
- path: resolvedPath,
111
- baseName,
112
- source,
113
- imports: imports.map(item => ({ ...item, root: resolvedPath })),
114
- meta: {
115
- pluginKey: this.plugin.key,
116
- },
117
- })
118
- }
119
-
120
- const promises = Object.entries(schemas).map(mapFolderSchema)
121
-
122
- await Promise.all(promises)
123
- }
124
-
125
- if (mode === 'file') {
126
- const resolvedPath = this.resolvePath({ baseName: '', pluginKey: this.plugin.key })
127
- const { source } = builder.build()
128
-
129
- if (!resolvedPath) {
130
- return
131
- }
132
-
133
- await this.addFile({
134
- path: resolvedPath,
135
- baseName: output.path as KubbFile.BaseName,
136
- source,
137
- imports: [],
138
- meta: {
139
- pluginKey: this.plugin.key,
140
- },
141
- })
142
- }
104
+ const schemaFiles = await schemaGenerator.build()
105
+ await this.addFile(...schemaFiles)
143
106
 
144
107
  const operationGenerator = new OperationGenerator(
145
108
  this.plugin.options,
@@ -155,8 +118,8 @@ export const definePlugin = createPlugin<PluginOptions>((options) => {
155
118
  },
156
119
  )
157
120
 
158
- const files = await operationGenerator.build()
159
- await this.addFile(...files)
121
+ const operationFiles = await operationGenerator.build()
122
+ await this.addFile(...operationFiles)
160
123
  },
161
124
  async buildEnd() {
162
125
  if (this.config.output.write === false) {