@kubb/plugin-oas 3.0.0-alpha.9 → 3.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.
Files changed (99) hide show
  1. package/README.md +14 -5
  2. package/dist/OperationGenerator-Dko8Xtd7.d.cts +561 -0
  3. package/dist/OperationGenerator-Dko8Xtd7.d.ts +561 -0
  4. package/dist/{Schema-B1vcPGiK.d.ts → Schema-C2cbPYX1.d.cts} +1 -12
  5. package/dist/{Schema-DoSFh7Qd.d.cts → Schema-CbtIvprh.d.ts} +1 -12
  6. package/dist/chunk-2TGWPVZN.cjs +92 -0
  7. package/dist/chunk-2TGWPVZN.cjs.map +1 -0
  8. package/dist/chunk-A3ROGKLW.cjs +752 -0
  9. package/dist/chunk-A3ROGKLW.cjs.map +1 -0
  10. package/dist/chunk-ABOQ73FL.cjs +36 -0
  11. package/dist/chunk-ABOQ73FL.cjs.map +1 -0
  12. package/dist/chunk-BG77DP54.js +30 -0
  13. package/dist/chunk-BG77DP54.js.map +1 -0
  14. package/dist/chunk-GF26SDHQ.js +28 -0
  15. package/dist/chunk-GF26SDHQ.js.map +1 -0
  16. package/dist/chunk-JA75IPYU.js +744 -0
  17. package/dist/chunk-JA75IPYU.js.map +1 -0
  18. package/dist/chunk-PADR76WZ.cjs +4 -0
  19. package/dist/chunk-PADR76WZ.cjs.map +1 -0
  20. package/dist/chunk-QAFBZLJA.cjs +48 -0
  21. package/dist/{chunk-SZDO532A.js.map → chunk-QAFBZLJA.cjs.map} +1 -1
  22. package/dist/chunk-R47XMJ32.js +3 -0
  23. package/dist/chunk-R47XMJ32.js.map +1 -0
  24. package/dist/chunk-TNWNNVQW.js +88 -0
  25. package/dist/chunk-TNWNNVQW.js.map +1 -0
  26. package/dist/chunk-XNCEFOE6.js +45 -0
  27. package/dist/chunk-XNCEFOE6.js.map +1 -0
  28. package/dist/chunk-ZWHQ54JM.cjs +32 -0
  29. package/dist/chunk-ZWHQ54JM.cjs.map +1 -0
  30. package/dist/components.cjs +20 -12
  31. package/dist/components.cjs.map +1 -1
  32. package/dist/components.d.cts +3 -6
  33. package/dist/components.d.ts +3 -6
  34. package/dist/components.js +3 -12
  35. package/dist/components.js.map +1 -1
  36. package/dist/generators.cjs +14 -0
  37. package/dist/generators.cjs.map +1 -0
  38. package/dist/generators.d.cts +9 -0
  39. package/dist/generators.d.ts +9 -0
  40. package/dist/generators.js +5 -0
  41. package/dist/generators.js.map +1 -0
  42. package/dist/hooks.cjs +90 -57
  43. package/dist/hooks.cjs.map +1 -1
  44. package/dist/hooks.d.cts +37 -10
  45. package/dist/hooks.d.ts +37 -10
  46. package/dist/hooks.js +79 -53
  47. package/dist/hooks.js.map +1 -1
  48. package/dist/index.cjs +142 -189
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.d.cts +2 -5
  51. package/dist/index.d.ts +2 -5
  52. package/dist/index.js +82 -156
  53. package/dist/index.js.map +1 -1
  54. package/dist/utils.cjs +32 -45
  55. package/dist/utils.cjs.map +1 -1
  56. package/dist/utils.d.cts +4 -13
  57. package/dist/utils.d.ts +4 -13
  58. package/dist/utils.js +8 -44
  59. package/dist/utils.js.map +1 -1
  60. package/package.json +20 -14
  61. package/src/OperationGenerator.ts +30 -39
  62. package/src/SchemaGenerator.ts +70 -11
  63. package/src/SchemaMapper.ts +24 -5
  64. package/src/components/Schema.tsx +1 -99
  65. package/src/generator.tsx +22 -18
  66. package/src/generators/index.ts +1 -0
  67. package/src/generators/jsonGenerator.ts +32 -0
  68. package/src/hooks/index.ts +2 -0
  69. package/src/hooks/useOperationManager.ts +56 -31
  70. package/src/hooks/useSchemaManager.ts +77 -0
  71. package/src/index.ts +2 -4
  72. package/src/plugin.ts +69 -56
  73. package/src/types.ts +29 -22
  74. package/src/utils/getParams.ts +1 -1
  75. package/src/utils/getSchemaFactory.ts +1 -1
  76. package/src/utils/index.ts +0 -1
  77. package/src/utils/parseFromConfig.ts +7 -7
  78. package/dist/OperationGenerator-By5WOmWB.d.ts +0 -165
  79. package/dist/OperationGenerator-Gd1X7wUz.d.cts +0 -165
  80. package/dist/SchemaMapper-sGcY1xL5.d.cts +0 -247
  81. package/dist/SchemaMapper-sGcY1xL5.d.ts +0 -247
  82. package/dist/chunk-75BIOXB7.cjs +0 -7
  83. package/dist/chunk-75BIOXB7.cjs.map +0 -1
  84. package/dist/chunk-IAUV3UKH.cjs +0 -3965
  85. package/dist/chunk-IAUV3UKH.cjs.map +0 -1
  86. package/dist/chunk-M347763D.js +0 -3965
  87. package/dist/chunk-M347763D.js.map +0 -1
  88. package/dist/chunk-N7EEVJA6.js +0 -35
  89. package/dist/chunk-N7EEVJA6.js.map +0 -1
  90. package/dist/chunk-NU4F7G47.cjs +0 -89
  91. package/dist/chunk-NU4F7G47.cjs.map +0 -1
  92. package/dist/chunk-O76YQFZB.cjs +0 -35
  93. package/dist/chunk-O76YQFZB.cjs.map +0 -1
  94. package/dist/chunk-SQ64ESS4.js +0 -7
  95. package/dist/chunk-SQ64ESS4.js.map +0 -1
  96. package/dist/chunk-SZDO532A.js +0 -89
  97. package/dist/types-CZTUCaE5.d.cts +0 -145
  98. package/dist/types-CZTUCaE5.d.ts +0 -145
  99. package/src/utils/refSorter.ts +0 -13
@@ -5,15 +5,10 @@ import type { PluginFactoryOptions, PluginManager } from '@kubb/core'
5
5
  import type * as KubbFile from '@kubb/fs/types'
6
6
 
7
7
  import type { Plugin } from '@kubb/core'
8
- import type { HttpMethod, Oas, OasTypes, Operation, contentType } from '@kubb/oas'
8
+ import type { HttpMethod, Oas, OasTypes, Operation, SchemaObject, contentType } from '@kubb/oas'
9
9
  import type { Generator } from './generator.tsx'
10
10
  import type { Exclude, Include, OperationSchemas, OperationsByMethod, Override } from './types.ts'
11
11
 
12
- /**
13
- * @deprecated
14
- */
15
- export type GetOperationGeneratorOptions<T extends OperationGenerator<any, any, any>> = T extends OperationGenerator<infer Options, any, any> ? Options : never
16
-
17
12
  export type OperationMethodResult<TFileMeta extends FileMetaBase> = Promise<KubbFile.File<TFileMeta> | Array<KubbFile.File<TFileMeta>> | null>
18
13
 
19
14
  type Context<TOptions, TPluginOptions extends PluginFactoryOptions> = {
@@ -31,10 +26,9 @@ type Context<TOptions, TPluginOptions extends PluginFactoryOptions> = {
31
26
  }
32
27
 
33
28
  export class OperationGenerator<
34
- TOptions = unknown,
35
29
  TPluginOptions extends PluginFactoryOptions = PluginFactoryOptions,
36
30
  TFileMeta extends FileMetaBase = FileMetaBase,
37
- > extends BaseGenerator<TOptions, Context<TOptions, TPluginOptions>> {
31
+ > extends BaseGenerator<TPluginOptions['resolvedOptions'], Context<TPluginOptions['resolvedOptions'], TPluginOptions>> {
38
32
  #operationsByMethod: OperationsByMethod = {}
39
33
  get operationsByMethod(): OperationsByMethod {
40
34
  return this.#operationsByMethod
@@ -44,7 +38,7 @@ export class OperationGenerator<
44
38
  this.#operationsByMethod = paths
45
39
  }
46
40
 
47
- #getOptions(operation: Operation, method: HttpMethod): Partial<TOptions> {
41
+ #getOptions(operation: Operation, method: HttpMethod): Partial<TPluginOptions['resolvedOptions']> {
48
42
  const { override = [] } = this.context
49
43
 
50
44
  return (
@@ -70,10 +64,6 @@ export class OperationGenerator<
70
64
  )
71
65
  }
72
66
 
73
- /**
74
- *
75
- * @deprecated
76
- */
77
67
  #isExcluded(operation: Operation, method: HttpMethod): boolean {
78
68
  const { exclude = [] } = this.context
79
69
  let matched = false
@@ -99,10 +89,6 @@ export class OperationGenerator<
99
89
  return matched
100
90
  }
101
91
 
102
- /**
103
- *
104
- * @deprecated
105
- */
106
92
  #isIncluded(operation: Operation, method: HttpMethod): boolean {
107
93
  const { include = [] } = this.context
108
94
  let matched = false
@@ -131,10 +117,8 @@ export class OperationGenerator<
131
117
  getSchemas(
132
118
  operation: Operation,
133
119
  {
134
- forStatusCode,
135
120
  resolveName = (name) => name,
136
121
  }: {
137
- forStatusCode?: string | number
138
122
  resolveName?: (name: string) => string
139
123
  } = {},
140
124
  ): OperationSchemas {
@@ -142,9 +126,6 @@ export class OperationGenerator<
142
126
  const queryParamsSchema = this.context.oas.getParametersSchema(operation, 'query')
143
127
  const headerParamsSchema = this.context.oas.getParametersSchema(operation, 'header')
144
128
  const requestSchema = this.context.oas.getRequestSchema(operation)
145
- const responseStatusCode =
146
- forStatusCode || (operation.schema.responses && Object.keys(operation.schema.responses).find((key) => key.startsWith('2'))) || 200
147
- const responseSchema = this.context.oas.getResponseSchema(operation, responseStatusCode)
148
129
  const statusCodes = operation.getResponseStatusCodes().map((statusCode) => {
149
130
  let name = statusCode
150
131
  if (name === 'default') {
@@ -161,8 +142,15 @@ export class OperationGenerator<
161
142
  operationName: transformers.pascalCase(`${operation.getOperationId()}`),
162
143
  statusCode: name === 'error' ? undefined : Number(statusCode),
163
144
  keys: schema?.properties ? Object.keys(schema.properties) : undefined,
145
+ keysToOmit: schema?.properties
146
+ ? Object.keys(schema.properties).filter((key) => {
147
+ const item = schema.properties?.[key] as OasTypes.SchemaObject
148
+ return item?.writeOnly
149
+ })
150
+ : undefined,
164
151
  }
165
152
  })
153
+ const hasResponses = statusCodes.some((item) => item.statusCode?.toString().startsWith('2'))
166
154
 
167
155
  return {
168
156
  pathParams: pathParamsSchema
@@ -211,19 +199,22 @@ export class OperationGenerator<
211
199
  : undefined,
212
200
  response: {
213
201
  name: resolveName(transformers.pascalCase(`${operation.getOperationId()} ${operation.method === 'get' ? 'queryResponse' : 'mutationResponse'}`)),
214
- description: operation.getResponseAsJSONSchema(responseStatusCode)?.at(0)?.description,
215
202
  operation,
216
203
  operationName: transformers.pascalCase(`${operation.getOperationId()}`),
217
- schema: responseSchema,
218
- statusCode: Number(responseStatusCode),
219
- keys: responseSchema?.properties ? Object.keys(responseSchema.properties) : undefined,
220
- keysToOmit: responseSchema?.properties
221
- ? Object.keys(responseSchema.properties).filter((key) => {
222
- const item = responseSchema.properties?.[key] as OasTypes.SchemaObject
223
- return item?.writeOnly
224
- })
225
- : undefined,
204
+ schema: {
205
+ oneOf: hasResponses
206
+ ? statusCodes
207
+ .filter((item) => item.statusCode?.toString().startsWith('2'))
208
+ .map((item) => {
209
+ return {
210
+ ...item.schema,
211
+ $ref: resolveName(transformers.pascalCase(`${operation.getOperationId()} ${item.statusCode}`)),
212
+ }
213
+ })
214
+ : undefined,
215
+ } as SchemaObject,
226
216
  },
217
+ responses: statusCodes.filter((item) => item.statusCode?.toString().startsWith('2')),
227
218
  errors: statusCodes.filter((item) => item.statusCode?.toString().startsWith('4') || item.statusCode?.toString().startsWith('5')),
228
219
  statusCodes,
229
220
  }
@@ -231,7 +222,7 @@ export class OperationGenerator<
231
222
 
232
223
  #methods = ['get', 'post', 'patch', 'put', 'delete']
233
224
 
234
- async build(...generators: Array<Generator<Extract<TOptions, PluginFactoryOptions>>>): Promise<Array<KubbFile.File<TFileMeta>>> {
225
+ async build(...generators: Array<Generator<TPluginOptions>>): Promise<Array<KubbFile.File<TFileMeta>>> {
235
226
  const { oas } = this.context
236
227
 
237
228
  const paths = oas.getPaths()
@@ -336,41 +327,41 @@ export class OperationGenerator<
336
327
  /**
337
328
  * Operation
338
329
  */
339
- async operation(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta> {
330
+ async operation(operation: Operation, options: TPluginOptions['resolvedOptions']): OperationMethodResult<TFileMeta> {
340
331
  return []
341
332
  }
342
333
 
343
334
  /**
344
335
  * GET
345
336
  */
346
- async get(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta> {
337
+ async get(operation: Operation, options: TPluginOptions['resolvedOptions']): OperationMethodResult<TFileMeta> {
347
338
  return []
348
339
  }
349
340
 
350
341
  /**
351
342
  * POST
352
343
  */
353
- async post(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta> {
344
+ async post(operation: Operation, options: TPluginOptions['resolvedOptions']): OperationMethodResult<TFileMeta> {
354
345
  return []
355
346
  }
356
347
  /**
357
348
  * PATCH
358
349
  */
359
- async patch(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta> {
350
+ async patch(operation: Operation, options: TPluginOptions['resolvedOptions']): OperationMethodResult<TFileMeta> {
360
351
  return []
361
352
  }
362
353
 
363
354
  /**
364
355
  * PUT
365
356
  */
366
- async put(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta> {
357
+ async put(operation: Operation, options: TPluginOptions['resolvedOptions']): OperationMethodResult<TFileMeta> {
367
358
  return []
368
359
  }
369
360
 
370
361
  /**
371
362
  * DELETE
372
363
  */
373
- async delete(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta> {
364
+ async delete(operation: Operation, options: TPluginOptions['resolvedOptions']): OperationMethodResult<TFileMeta> {
374
365
  return []
375
366
  }
376
367
 
@@ -302,7 +302,7 @@ export class SchemaGenerator<
302
302
 
303
303
  if (additionalProperties) {
304
304
  additionalPropertiesSchemas =
305
- additionalProperties === true
305
+ additionalProperties === true || !Object.keys(additionalProperties).length
306
306
  ? [{ keyword: this.#getUnknownReturn({ schema, name }) }]
307
307
  : this.parse({ schema: additionalProperties as SchemaObject, parentName: name })
308
308
  }
@@ -336,7 +336,7 @@ export class SchemaGenerator<
336
336
  return [
337
337
  {
338
338
  keyword: schemaKeywords.ref,
339
- args: { name: ref.propertyName, path: ref.path },
339
+ args: { name: ref.propertyName, path: ref.path, isImportable: !!this.context.oas.get($ref) },
340
340
  },
341
341
  ]
342
342
  }
@@ -349,7 +349,7 @@ export class SchemaGenerator<
349
349
  const file = this.context.pluginManager.getFile({
350
350
  name: fileName,
351
351
  pluginKey: this.context.plugin.key,
352
- extName: '.ts',
352
+ extname: '.ts',
353
353
  })
354
354
 
355
355
  ref = this.refs[$ref] = {
@@ -361,7 +361,7 @@ export class SchemaGenerator<
361
361
  return [
362
362
  {
363
363
  keyword: schemaKeywords.ref,
364
- args: { name: ref.propertyName, path: ref?.path },
364
+ args: { name: ref.propertyName, path: ref?.path, isImportable: !!this.context.oas.get($ref) },
365
365
  },
366
366
  ]
367
367
  }
@@ -453,10 +453,16 @@ export class SchemaGenerator<
453
453
  baseItems.push({ keyword: schemaKeywords.readOnly })
454
454
  }
455
455
 
456
+ if (schema.writeOnly) {
457
+ baseItems.push({ keyword: schemaKeywords.writeOnly })
458
+ }
459
+
456
460
  if (isReference(schema)) {
457
461
  return [
458
462
  ...this.#getRefAlias(schema),
459
463
  nullable && { keyword: schemaKeywords.nullable },
464
+ schema.readOnly && { keyword: schemaKeywords.readOnly },
465
+ schema.writeOnly && { keyword: schemaKeywords.writeOnly },
460
466
  {
461
467
  keyword: schemaKeywords.schema,
462
468
  args: {
@@ -483,7 +489,20 @@ export class SchemaGenerator<
483
489
  }),
484
490
  }
485
491
  if (schemaWithoutOneOf.properties) {
486
- return [...this.parse({ schema: schemaWithoutOneOf, name, parentName }), union, ...baseItems]
492
+ const propertySchemas = this.parse({ schema: schemaWithoutOneOf, name, parentName })
493
+
494
+ return [
495
+ {
496
+ ...union,
497
+ args: union.args.map((arg) => {
498
+ return {
499
+ keyword: schemaKeywords.and,
500
+ args: [arg, ...propertySchemas],
501
+ }
502
+ }),
503
+ },
504
+ ...baseItems,
505
+ ]
487
506
  }
488
507
 
489
508
  return [union, ...baseItems]
@@ -618,6 +637,35 @@ export class SchemaGenerator<
618
637
  ]
619
638
  }
620
639
 
640
+ if (schema.type === 'boolean') {
641
+ // we cannot use z.enum when enum type is boolean
642
+ const enumNames = extensionEnums[0]?.find((item) => isKeyword(item, schemaKeywords.enum)) as unknown as SchemaKeywordMapper['enum']
643
+ return [
644
+ {
645
+ keyword: schemaKeywords.enum,
646
+ args: {
647
+ name: enumName,
648
+ typeName,
649
+ asConst: true,
650
+ items: enumNames?.args?.items
651
+ ? [...new Set(enumNames.args.items)].map(({ name, value }) => ({
652
+ name,
653
+ value,
654
+ format: 'boolean',
655
+ }))
656
+ : [...new Set(filteredValues)].map((value: string) => {
657
+ return {
658
+ name: value,
659
+ value,
660
+ format: 'boolean',
661
+ }
662
+ }),
663
+ },
664
+ },
665
+ ...baseItems.filter((item) => item.keyword !== schemaKeywords.matches),
666
+ ]
667
+ }
668
+
621
669
  if (extensionEnums.length > 0 && extensionEnums[0]) {
622
670
  return extensionEnums[0]
623
671
  }
@@ -808,7 +856,7 @@ export class SchemaGenerator<
808
856
  ].filter(Boolean)
809
857
  }
810
858
 
811
- if (!['boolean', 'object', 'number', 'string', 'integer'].includes(schema.type)) {
859
+ if (!['boolean', 'object', 'number', 'string', 'integer', 'null'].includes(schema.type)) {
812
860
  this.context.pluginManager.logger.emit('warning', `Schema type '${schema.type}' is not valid for schema ${parentName}.${name}`)
813
861
  }
814
862
 
@@ -819,14 +867,20 @@ export class SchemaGenerator<
819
867
  return [{ keyword: unknownReturn }]
820
868
  }
821
869
 
822
- async build(...generators: Array<Generator<Extract<TOptions, PluginFactoryOptions>>>): Promise<Array<KubbFile.File<TFileMeta>>> {
870
+ async build(...generators: Array<Generator<TPluginOptions>>): Promise<Array<KubbFile.File<TFileMeta>>> {
823
871
  const { oas, contentType, include } = this.context
824
872
 
873
+ oas.resolveDiscriminators()
874
+
825
875
  const schemas = getSchemas({ oas, contentType, includes: include })
826
876
 
827
- const promises = Object.entries(schemas).reduce((acc, [name, schema]) => {
877
+ const promises = Object.entries(schemas).reduce((acc, [name, value]) => {
878
+ if (!value) {
879
+ return acc
880
+ }
881
+
828
882
  const options = this.#getOptions({ name })
829
- const promiseOperation = this.schema.call(this, name, schema, {
883
+ const promiseOperation = this.schema.call(this, name, value, {
830
884
  ...this.options,
831
885
  ...options,
832
886
  })
@@ -836,10 +890,15 @@ export class SchemaGenerator<
836
890
  }
837
891
 
838
892
  generators?.forEach((generator) => {
893
+ const tree = this.parse({ schema: value, name: name })
894
+
839
895
  const promise = generator.schema?.({
840
896
  instance: this,
841
- name,
842
- schema,
897
+ schema: {
898
+ name,
899
+ value,
900
+ tree,
901
+ },
843
902
  options: {
844
903
  ...this.options,
845
904
  ...options,
@@ -12,6 +12,7 @@ export type SchemaKeywordMapper = {
12
12
  strict: { keyword: 'strict' }
13
13
  url: { keyword: 'url' }
14
14
  readOnly: { keyword: 'readOnly' }
15
+ writeOnly: { keyword: 'writeOnly' }
15
16
  uuid: { keyword: 'uuid' }
16
17
  email: { keyword: 'email' }
17
18
  firstName: { keyword: 'firstName' }
@@ -34,8 +35,8 @@ export type SchemaKeywordMapper = {
34
35
  asConst: boolean
35
36
  items: Array<{
36
37
  name: string | number
37
- format: 'string' | 'number'
38
- value?: string | number
38
+ format: 'string' | 'number' | 'boolean'
39
+ value?: string | number | boolean
39
40
  }>
40
41
  }
41
42
  }
@@ -44,14 +45,25 @@ export type SchemaKeywordMapper = {
44
45
  keyword: 'const'
45
46
  args: {
46
47
  name: string | number
47
- format: 'string' | 'number'
48
- value?: string | number
48
+ format: 'string' | 'number' | 'boolean'
49
+ value?: string | number | boolean
49
50
  }
50
51
  }
51
52
  union: { keyword: 'union'; args: Schema[] }
52
53
  ref: {
53
54
  keyword: 'ref'
54
- args: { name: string; path: KubbFile.OptionalPath }
55
+ args: {
56
+ name: string
57
+ /**
58
+ * Full qualified path.
59
+ */
60
+ path: KubbFile.OptionalPath
61
+ /**
62
+ * When true `File.Import` will be used.
63
+ * When false a reference will be used inside the current file.
64
+ */
65
+ isImportable: boolean
66
+ }
55
67
  }
56
68
  matches: { keyword: 'matches'; args?: string }
57
69
  boolean: { keyword: 'boolean' }
@@ -107,6 +119,7 @@ export const schemaKeywords = {
107
119
  max: 'max',
108
120
  optional: 'optional',
109
121
  readOnly: 'readOnly',
122
+ writeOnly: 'writeOnly',
110
123
 
111
124
  // custom ones
112
125
  object: 'object',
@@ -140,6 +153,12 @@ export type SchemaKeywordBase<T> = {
140
153
 
141
154
  export type Schema = { keyword: string } | SchemaKeywordMapper[keyof SchemaKeywordMapper]
142
155
 
156
+ export type SchemaTree = {
157
+ parent: Schema | undefined
158
+ current: Schema
159
+ siblings: Schema[]
160
+ }
161
+
143
162
  export function isKeyword<T extends Schema, K extends keyof SchemaKeywordMapper>(meta: T, keyword: K): meta is Extract<T, SchemaKeywordMapper[K]> {
144
163
  return meta.keyword === keyword
145
164
  }
@@ -1,15 +1,8 @@
1
- import { File, createContext, useApp, useFile } from '@kubb/react'
1
+ import { createContext } from '@kubb/react'
2
2
 
3
- import { schemaKeywords } from '../SchemaMapper.ts'
4
- import { useSchema } from '../hooks/useSchema.ts'
5
-
6
- import type * as KubbFile from '@kubb/fs/types'
7
3
  import type { SchemaObject } from '@kubb/oas'
8
4
  import type { KubbNode } from '@kubb/react/types'
9
- import type { ReactNode } from 'react'
10
- import { SchemaGenerator } from '../SchemaGenerator.ts'
11
5
  import type { Schema as SchemaType } from '../SchemaMapper.ts'
12
- import type { PluginOas } from '../types.ts'
13
6
 
14
7
  export type SchemaContextProps = {
15
8
  name: string
@@ -33,95 +26,4 @@ export function Schema({ name, value, tree = [], children }: Props): KubbNode {
33
26
  return <SchemaContext.Provider value={{ name, schema: value, tree }}>{children}</SchemaContext.Provider>
34
27
  }
35
28
 
36
- type FileProps = {
37
- isTypeOnly?: boolean
38
- output: string | undefined
39
- children?: KubbNode
40
- }
41
-
42
- Schema.File = function ({ output, isTypeOnly, children }: FileProps): ReactNode {
43
- const { plugin, pluginManager, mode } = useApp<PluginOas>()
44
- const { name } = useSchema()
45
-
46
- if (mode === 'single') {
47
- const baseName = `${pluginManager.resolveName({
48
- name,
49
- pluginKey: plugin.key,
50
- type: 'file',
51
- })}.ts` as const
52
-
53
- const resolvedPath = pluginManager.resolvePath({
54
- baseName: '',
55
- pluginKey: plugin.key,
56
- })
57
-
58
- if (!resolvedPath) {
59
- return null
60
- }
61
-
62
- return (
63
- <File
64
- baseName={baseName}
65
- path={resolvedPath}
66
- meta={{
67
- pluginKey: plugin.key,
68
- }}
69
- >
70
- {children}
71
- </File>
72
- )
73
- }
74
-
75
- const baseName = `${pluginManager.resolveName({
76
- name,
77
- pluginKey: plugin.key,
78
- type: 'file',
79
- })}.ts` as const
80
- const resolvedPath = pluginManager.resolvePath({
81
- baseName,
82
- pluginKey: plugin.key,
83
- })
84
-
85
- if (!resolvedPath) {
86
- return null
87
- }
88
-
89
- return (
90
- <File
91
- baseName={baseName}
92
- path={resolvedPath}
93
- meta={{
94
- pluginKey: plugin.key,
95
- }}
96
- >
97
- <Schema.Imports isTypeOnly={isTypeOnly} />
98
- {children}
99
- </File>
100
- )
101
- }
102
-
103
- type SchemaImportsProps = {
104
- isTypeOnly?: boolean
105
- }
106
-
107
- Schema.Imports = ({ isTypeOnly }: SchemaImportsProps): ReactNode => {
108
- const { tree } = useSchema()
109
- const { path: root } = useFile()
110
-
111
- const refs = SchemaGenerator.deepSearch(tree, schemaKeywords.ref)
112
-
113
- return (
114
- <>
115
- {refs
116
- ?.map((item, i) => {
117
- if (!item.args.path) {
118
- return undefined
119
- }
120
-
121
- return <File.Import key={i} root={root} name={[item.args.name]} path={item.args.path} isTypeOnly={isTypeOnly} />
122
- })
123
- .filter(Boolean)}
124
- </>
125
- )
126
- }
127
29
  Schema.Context = SchemaContext
package/src/generator.tsx CHANGED
@@ -6,6 +6,7 @@ import { App, createRoot } from '@kubb/react'
6
6
  import type { KubbNode } from '@kubb/react/types'
7
7
  import type { OperationGenerator } from './OperationGenerator.ts'
8
8
  import type { SchemaGenerator, SchemaGeneratorOptions } from './SchemaGenerator.ts'
9
+ import type { Schema } from './SchemaMapper.ts'
9
10
  import type { OperationsByMethod } from './types.ts'
10
11
 
11
12
  type OperationsProps<TOptions extends PluginFactoryOptions> = {
@@ -23,16 +24,19 @@ type OperationProps<TOptions extends PluginFactoryOptions> = {
23
24
 
24
25
  type SchemaProps<TOptions extends PluginFactoryOptions> = {
25
26
  instance: Omit<SchemaGenerator<SchemaGeneratorOptions, TOptions>, 'build'>
26
- name: string
27
- schema: SchemaObject
28
27
  options: TOptions['resolvedOptions']
28
+ schema: {
29
+ name: string
30
+ tree: Array<Schema>
31
+ value: SchemaObject
32
+ }
29
33
  }
30
34
 
31
35
  export type GeneratorOptions<TOptions extends PluginFactoryOptions> = {
32
36
  name: string
33
- operations?: (props: OperationsProps<TOptions>) => Promise<KubbFile.File[]>
34
- operation?: (props: OperationProps<TOptions>) => Promise<KubbFile.File[]>
35
- schema?: (props: SchemaProps<TOptions>) => Promise<KubbFile.File[]>
37
+ operations?: (this: GeneratorOptions<TOptions>, props: OperationsProps<TOptions>) => Promise<KubbFile.File[]>
38
+ operation?: (this: GeneratorOptions<TOptions>, props: OperationProps<TOptions>) => Promise<KubbFile.File[]>
39
+ schema?: (this: GeneratorOptions<TOptions>, props: SchemaProps<TOptions>) => Promise<KubbFile.File[]>
36
40
  }
37
41
 
38
42
  export type Generator<TOptions extends PluginFactoryOptions> = GeneratorOptions<TOptions>
@@ -43,13 +47,9 @@ export function createGenerator<TOptions extends PluginFactoryOptions>(parseOpti
43
47
 
44
48
  export type ReactGeneratorOptions<TOptions extends PluginFactoryOptions> = {
45
49
  name: string
46
- Operations?: (props: OperationsProps<TOptions>) => KubbNode
47
- Operation?: (props: OperationProps<TOptions>) => KubbNode
48
- Schema?: (props: SchemaProps<TOptions>) => KubbNode
49
- /**
50
- * Combine all react nodes and only render ones(to string or render)
51
- */
52
- render?: () => any
50
+ Operations?: (this: ReactGeneratorOptions<TOptions>, props: OperationsProps<TOptions>) => KubbNode
51
+ Operation?: (this: ReactGeneratorOptions<TOptions>, props: OperationProps<TOptions>) => KubbNode
52
+ Schema?: (this: ReactGeneratorOptions<TOptions>, props: SchemaProps<TOptions>) => KubbNode
53
53
  }
54
54
 
55
55
  export function createReactGenerator<TOptions extends PluginFactoryOptions>(parseOptions: ReactGeneratorOptions<TOptions>): Generator<TOptions> {
@@ -65,10 +65,12 @@ export function createReactGenerator<TOptions extends PluginFactoryOptions>(pars
65
65
  logger: pluginManager.logger,
66
66
  })
67
67
 
68
+ const Component = parseOptions.Operations.bind(this)
69
+
68
70
  root.render(
69
71
  <App pluginManager={pluginManager} plugin={plugin} mode={mode}>
70
72
  <Oas oas={oas} operations={operations} generator={instance}>
71
- <parseOptions.Operations operations={operations} instance={instance} operationsByMethod={operationsByMethod} options={options} />
73
+ <Component operations={operations} instance={instance} operationsByMethod={operationsByMethod} options={options} />
72
74
  </Oas>
73
75
  </App>,
74
76
  )
@@ -85,11 +87,13 @@ export function createReactGenerator<TOptions extends PluginFactoryOptions>(pars
85
87
  logger: pluginManager.logger,
86
88
  })
87
89
 
90
+ const Component = parseOptions.Operation.bind(this)
91
+
88
92
  root.render(
89
93
  <App pluginManager={pluginManager} plugin={{ ...plugin, options }} mode={mode}>
90
94
  <Oas oas={oas} operations={[operation]} generator={instance}>
91
95
  <Oas.Operation operation={operation}>
92
- <parseOptions.Operation operation={operation} options={options} instance={instance} />
96
+ <Component operation={operation} options={options} instance={instance} />
93
97
  </Oas.Operation>
94
98
  </Oas>
95
99
  </App>,
@@ -97,7 +101,7 @@ export function createReactGenerator<TOptions extends PluginFactoryOptions>(pars
97
101
 
98
102
  return root.files
99
103
  },
100
- async schema({ instance, schema, name, options }) {
104
+ async schema({ instance, schema, options }) {
101
105
  if (!parseOptions.Schema) {
102
106
  return []
103
107
  }
@@ -107,13 +111,13 @@ export function createReactGenerator<TOptions extends PluginFactoryOptions>(pars
107
111
  logger: pluginManager.logger,
108
112
  })
109
113
 
110
- const tree = instance.parse({ schema, name })
114
+ const Component = parseOptions.Schema.bind(this)
111
115
 
112
116
  root.render(
113
117
  <App pluginManager={pluginManager} plugin={{ ...plugin, options }} mode={mode}>
114
118
  <Oas oas={oas}>
115
- <Oas.Schema name={name} value={schema} tree={tree}>
116
- <parseOptions.Schema schema={schema} options={options} instance={instance} name={name} />
119
+ <Oas.Schema name={schema.name} value={schema.value} tree={schema.tree}>
120
+ <Component schema={schema} options={options} instance={instance} />
117
121
  </Oas.Schema>
118
122
  </Oas>
119
123
  </App>,
@@ -0,0 +1 @@
1
+ export { jsonGenerator } from './jsonGenerator.ts'
@@ -0,0 +1,32 @@
1
+ import { camelCase } from '@kubb/core/transformers'
2
+ import { createGenerator } from '../generator.tsx'
3
+ import type { PluginOas } from '../types.ts'
4
+
5
+ export const jsonGenerator = createGenerator<PluginOas>({
6
+ name: 'plugin-oas',
7
+ async schema({ schema, instance }) {
8
+ const { pluginManager, plugin } = instance.context
9
+ const file = pluginManager.getFile({
10
+ name: camelCase(schema.name),
11
+ extname: '.json',
12
+ mode: 'split',
13
+ pluginKey: plugin.key,
14
+ })
15
+
16
+ return [
17
+ {
18
+ ...file,
19
+ sources: [
20
+ {
21
+ name: camelCase(schema.name),
22
+ isExportable: false,
23
+ isIndexable: false,
24
+ value: JSON.stringify(schema.value),
25
+ },
26
+ ],
27
+ banner: plugin.options.output?.banner,
28
+ format: plugin.options.output?.footer,
29
+ },
30
+ ]
31
+ },
32
+ })
@@ -1,5 +1,7 @@
1
1
  export { useOas } from './useOas.ts'
2
2
  export { useOperation } from './useOperation.ts'
3
3
  export { useOperationManager } from './useOperationManager.ts'
4
+ export type { SchemaNames } from './useOperationManager.ts'
4
5
  export { useOperations } from './useOperations.ts'
5
6
  export { useSchema } from './useSchema.ts'
7
+ export { useSchemaManager } from './useSchemaManager.ts'