@kubb/plugin-oas 0.0.0-canary-20240509211223

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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/dist/OperationGenerator-DvnXUUp4.d.ts +56 -0
  4. package/dist/OperationGenerator-X6CTMfhG.d.cts +56 -0
  5. package/dist/Schema-BWPWyiQO.d.cts +39 -0
  6. package/dist/Schema-DFZBfjF2.d.ts +39 -0
  7. package/dist/SchemaGenerator-hK5SHxTI.d.ts +316 -0
  8. package/dist/SchemaGenerator-z_7YrAAB.d.cts +316 -0
  9. package/dist/chunk-2MJ2CQMI.js +61 -0
  10. package/dist/chunk-2MJ2CQMI.js.map +1 -0
  11. package/dist/chunk-3RCQ2LNT.js +81 -0
  12. package/dist/chunk-3RCQ2LNT.js.map +1 -0
  13. package/dist/chunk-55NUFNT6.cjs +68 -0
  14. package/dist/chunk-55NUFNT6.cjs.map +1 -0
  15. package/dist/chunk-ECXSQTMV.cjs +81 -0
  16. package/dist/chunk-ECXSQTMV.cjs.map +1 -0
  17. package/dist/chunk-EPTOYYAP.js +3312 -0
  18. package/dist/chunk-EPTOYYAP.js.map +1 -0
  19. package/dist/chunk-H52M2RUX.cjs +3312 -0
  20. package/dist/chunk-H52M2RUX.cjs.map +1 -0
  21. package/dist/chunk-LQ6IAWRX.js +68 -0
  22. package/dist/chunk-LQ6IAWRX.js.map +1 -0
  23. package/dist/chunk-VNFSHGSN.cjs +61 -0
  24. package/dist/chunk-VNFSHGSN.cjs.map +1 -0
  25. package/dist/components.cjs +18 -0
  26. package/dist/components.cjs.map +1 -0
  27. package/dist/components.d.cts +41 -0
  28. package/dist/components.d.ts +41 -0
  29. package/dist/components.js +18 -0
  30. package/dist/components.js.map +1 -0
  31. package/dist/hooks.cjs +152 -0
  32. package/dist/hooks.cjs.map +1 -0
  33. package/dist/hooks.d.cts +76 -0
  34. package/dist/hooks.d.ts +76 -0
  35. package/dist/hooks.js +152 -0
  36. package/dist/hooks.js.map +1 -0
  37. package/dist/index.cjs +985 -0
  38. package/dist/index.cjs.map +1 -0
  39. package/dist/index.d.cts +17 -0
  40. package/dist/index.d.ts +17 -0
  41. package/dist/index.js +985 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/types-n5zV4Q3s.d.cts +146 -0
  44. package/dist/types-n5zV4Q3s.d.ts +146 -0
  45. package/dist/utils.cjs +126 -0
  46. package/dist/utils.cjs.map +1 -0
  47. package/dist/utils.d.cts +80 -0
  48. package/dist/utils.d.ts +80 -0
  49. package/dist/utils.js +126 -0
  50. package/dist/utils.js.map +1 -0
  51. package/package.json +107 -0
  52. package/src/OperationGenerator.ts +328 -0
  53. package/src/SchemaGenerator.ts +827 -0
  54. package/src/SchemaMapper.ts +145 -0
  55. package/src/components/Oas.tsx +31 -0
  56. package/src/components/Operation.tsx +21 -0
  57. package/src/components/Schema.tsx +156 -0
  58. package/src/components/index.ts +3 -0
  59. package/src/hooks/index.ts +5 -0
  60. package/src/hooks/useOas.ts +15 -0
  61. package/src/hooks/useOperation.ts +18 -0
  62. package/src/hooks/useOperationManager.ts +142 -0
  63. package/src/hooks/useOperations.ts +40 -0
  64. package/src/hooks/useSchema.ts +23 -0
  65. package/src/index.ts +30 -0
  66. package/src/plugin.ts +133 -0
  67. package/src/types.ts +147 -0
  68. package/src/utils/getComments.ts +15 -0
  69. package/src/utils/getGroupedByTagFiles.ts +81 -0
  70. package/src/utils/getParams.ts +57 -0
  71. package/src/utils/getSchemaFactory.ts +33 -0
  72. package/src/utils/getSchemas.ts +45 -0
  73. package/src/utils/index.ts +8 -0
  74. package/src/utils/parseFromConfig.ts +36 -0
  75. package/src/utils/refSorter.ts +13 -0
@@ -0,0 +1,328 @@
1
+ import { Generator } from '@kubb/core'
2
+ import transformers from '@kubb/core/transformers'
3
+
4
+ import type { KubbFile, PluginFactoryOptions, PluginManager } from '@kubb/core'
5
+ import type { Plugin } from '@kubb/core'
6
+ import type { HttpMethod, Oas, OasTypes, Operation, contentType } from '@kubb/oas'
7
+ import type { Exclude, Include, OperationSchemas, OperationsByMethod, Override } from './types.ts'
8
+
9
+ export type GetOperationGeneratorOptions<T extends OperationGenerator<any, any, any>> = T extends OperationGenerator<infer Options, any, any> ? Options : never
10
+
11
+ export type OperationMethodResult<TFileMeta extends KubbFile.FileMetaBase> = Promise<KubbFile.File<TFileMeta> | Array<KubbFile.File<TFileMeta>> | null>
12
+
13
+ type Context<TOptions, TPluginOptions extends PluginFactoryOptions> = {
14
+ oas: Oas
15
+ exclude: Array<Exclude> | undefined
16
+ include: Array<Include> | undefined
17
+ override: Array<Override<TOptions>> | undefined
18
+ contentType: contentType | undefined
19
+ pluginManager: PluginManager
20
+ /**
21
+ * Current plugin
22
+ */
23
+ plugin: Plugin<TPluginOptions>
24
+ mode: KubbFile.Mode
25
+ }
26
+
27
+ export abstract class OperationGenerator<
28
+ TOptions = unknown,
29
+ TPluginOptions extends PluginFactoryOptions = PluginFactoryOptions,
30
+ TFileMeta extends KubbFile.FileMetaBase = KubbFile.FileMetaBase,
31
+ > extends Generator<TOptions, Context<TOptions, TPluginOptions>> {
32
+ #operationsByMethod: OperationsByMethod = {}
33
+ get operationsByMethod(): OperationsByMethod {
34
+ return this.#operationsByMethod
35
+ }
36
+
37
+ set operationsByMethod(paths: OperationsByMethod) {
38
+ this.#operationsByMethod = paths
39
+ }
40
+
41
+ #getOptions(operation: Operation, method: HttpMethod): Partial<TOptions> {
42
+ const { override = [] } = this.context
43
+
44
+ return (
45
+ override.find(({ pattern, type }) => {
46
+ if (type === 'tag') {
47
+ return !!operation.getTags()[0]?.name.match(pattern)
48
+ }
49
+
50
+ if (type === 'operationId') {
51
+ return !!operation.getOperationId().match(pattern)
52
+ }
53
+
54
+ if (type === 'path') {
55
+ return !!operation.path.match(pattern)
56
+ }
57
+
58
+ if (type === 'method') {
59
+ return !!method.match(pattern)
60
+ }
61
+
62
+ return false
63
+ })?.options || {}
64
+ )
65
+ }
66
+ /**
67
+ *
68
+ * @deprecated
69
+ */
70
+ #isExcluded(operation: Operation, method: HttpMethod): boolean {
71
+ const { exclude = [] } = this.context
72
+ let matched = false
73
+
74
+ exclude.forEach(({ pattern, type }) => {
75
+ if (type === 'tag' && !matched) {
76
+ matched = !!operation.getTags()[0]?.name.match(pattern)
77
+ }
78
+
79
+ if (type === 'operationId' && !matched) {
80
+ matched = !!operation.getOperationId().match(pattern)
81
+ }
82
+
83
+ if (type === 'path' && !matched) {
84
+ matched = !!operation.path.match(pattern)
85
+ }
86
+
87
+ if (type === 'method' && !matched) {
88
+ matched = !!method.match(pattern)
89
+ }
90
+ })
91
+
92
+ return matched
93
+ }
94
+ /**
95
+ *
96
+ * @deprecated
97
+ */
98
+ #isIncluded(operation: Operation, method: HttpMethod): boolean {
99
+ const { include = [] } = this.context
100
+ let matched = false
101
+
102
+ include.forEach(({ pattern, type }) => {
103
+ if (type === 'tag' && !matched) {
104
+ matched = !!operation.getTags()[0]?.name.match(pattern)
105
+ }
106
+
107
+ if (type === 'operationId' && !matched) {
108
+ matched = !!operation.getOperationId().match(pattern)
109
+ }
110
+
111
+ if (type === 'path' && !matched) {
112
+ matched = !!operation.path.match(pattern)
113
+ }
114
+
115
+ if (type === 'method' && !matched) {
116
+ matched = !!method.match(pattern)
117
+ }
118
+ })
119
+
120
+ return matched
121
+ }
122
+
123
+ getSchemas(operation: Operation, forStatusCode?: string | number): OperationSchemas {
124
+ const pathParamsSchema = this.context.oas.getParametersSchema(operation, 'path')
125
+ const queryParamsSchema = this.context.oas.getParametersSchema(operation, 'query')
126
+ const headerParamsSchema = this.context.oas.getParametersSchema(operation, 'header')
127
+ const requestSchema = this.context.oas.getRequestSchema(operation)
128
+ const responseStatusCode =
129
+ forStatusCode || (operation.schema.responses && Object.keys(operation.schema.responses).find((key) => key.startsWith('2'))) || 200
130
+ const responseSchema = this.context.oas.getResponseSchema(operation, responseStatusCode)
131
+ const statusCodes = operation.getResponseStatusCodes().map((statusCode) => {
132
+ let name = statusCode
133
+ if (name === 'default') {
134
+ name = 'error'
135
+ }
136
+
137
+ const schema = this.context.oas.getResponseSchema(operation, statusCode)
138
+
139
+ return {
140
+ name: transformers.pascalCase(`${operation.getOperationId()} ${name}`),
141
+ description: (operation.getResponseByStatusCode(statusCode) as OasTypes.ResponseObject)?.description,
142
+ schema,
143
+ operation,
144
+ operationName: transformers.pascalCase(`${operation.getOperationId()}`),
145
+ statusCode: name === 'error' ? undefined : Number(statusCode),
146
+ keys: schema?.properties ? Object.keys(schema.properties) : undefined,
147
+ }
148
+ })
149
+
150
+ return {
151
+ pathParams: pathParamsSchema
152
+ ? {
153
+ name: transformers.pascalCase(`${operation.getOperationId()} PathParams`),
154
+ operation,
155
+ operationName: transformers.pascalCase(`${operation.getOperationId()}`),
156
+ schema: pathParamsSchema,
157
+ keys: pathParamsSchema.properties ? Object.keys(pathParamsSchema.properties) : undefined,
158
+ }
159
+ : undefined,
160
+ queryParams: queryParamsSchema
161
+ ? {
162
+ name: transformers.pascalCase(`${operation.getOperationId()} QueryParams`),
163
+ operation,
164
+ operationName: transformers.pascalCase(`${operation.getOperationId()}`),
165
+ schema: queryParamsSchema,
166
+ keys: queryParamsSchema.properties ? Object.keys(queryParamsSchema.properties) : [],
167
+ }
168
+ : undefined,
169
+ headerParams: headerParamsSchema
170
+ ? {
171
+ name: transformers.pascalCase(`${operation.getOperationId()} HeaderParams`),
172
+ operation,
173
+ operationName: transformers.pascalCase(`${operation.getOperationId()}`),
174
+ schema: headerParamsSchema,
175
+ keys: headerParamsSchema.properties ? Object.keys(headerParamsSchema.properties) : undefined,
176
+ }
177
+ : undefined,
178
+ request: requestSchema
179
+ ? {
180
+ name: transformers.pascalCase(`${operation.getOperationId()} ${operation.method === 'get' ? 'queryRequest' : 'mutationRequest'}`),
181
+ description: (operation.schema.requestBody as OasTypes.RequestBodyObject)?.description,
182
+ operation,
183
+ operationName: transformers.pascalCase(`${operation.getOperationId()}`),
184
+ schema: requestSchema,
185
+ keys: requestSchema.properties ? Object.keys(requestSchema.properties) : undefined,
186
+ keysToOmit: requestSchema.properties
187
+ ? Object.keys(requestSchema.properties).filter((key) => {
188
+ const item = requestSchema.properties?.[key] as OasTypes.SchemaObject
189
+
190
+ return item?.readOnly
191
+ })
192
+ : undefined,
193
+ }
194
+ : undefined,
195
+ response: {
196
+ name: transformers.pascalCase(`${operation.getOperationId()} ${operation.method === 'get' ? 'queryResponse' : 'mutationResponse'}`),
197
+ description: operation.getResponseAsJSONSchema(responseStatusCode)?.at(0)?.description,
198
+ operation,
199
+ operationName: transformers.pascalCase(`${operation.getOperationId()}`),
200
+ schema: responseSchema,
201
+ statusCode: Number(responseStatusCode),
202
+ keys: responseSchema?.properties ? Object.keys(responseSchema.properties) : undefined,
203
+ keysToOmit: responseSchema?.properties
204
+ ? Object.keys(responseSchema.properties).filter((key) => {
205
+ const item = responseSchema.properties?.[key] as OasTypes.SchemaObject
206
+ return item?.writeOnly
207
+ })
208
+ : undefined,
209
+ },
210
+ errors: statusCodes.filter((item) => item.statusCode?.toString().startsWith('4') || item.statusCode?.toString().startsWith('5')),
211
+ statusCodes,
212
+ }
213
+ }
214
+
215
+ get #methods() {
216
+ return {
217
+ get: this.get,
218
+ post: this.post,
219
+ patch: this.patch,
220
+ put: this.put,
221
+ delete: this.delete,
222
+ head: undefined,
223
+ options: undefined,
224
+ trace: undefined,
225
+ } as const
226
+ }
227
+
228
+ async build(): Promise<Array<KubbFile.File<TFileMeta>>> {
229
+ const { oas } = this.context
230
+
231
+ const paths = oas.getPaths()
232
+ this.operationsByMethod = Object.entries(paths).reduce((acc, [path, method]) => {
233
+ const methods = Object.keys(method) as HttpMethod[]
234
+
235
+ methods.forEach((method) => {
236
+ const operation = oas.operation(path, method)
237
+ if (operation && this.#methods[method]) {
238
+ const isExcluded = this.#isExcluded(operation, method)
239
+ const isIncluded = this.context.include ? this.#isIncluded(operation, method) : true
240
+
241
+ if (isIncluded && !isExcluded) {
242
+ if (!acc[path]) {
243
+ acc[path] = {} as OperationsByMethod['get']
244
+ }
245
+ acc[path] = {
246
+ ...acc[path],
247
+ [method]: {
248
+ operation,
249
+ schemas: this.getSchemas(operation),
250
+ },
251
+ } as OperationsByMethod['get']
252
+ }
253
+ }
254
+ })
255
+
256
+ return acc
257
+ }, {} as OperationsByMethod)
258
+
259
+ const promises = Object.keys(this.operationsByMethod).reduce((acc, path) => {
260
+ const methods = this.operationsByMethod[path] ? (Object.keys(this.operationsByMethod[path]!) as HttpMethod[]) : []
261
+
262
+ methods.forEach((method) => {
263
+ const { operation } = this.operationsByMethod[path]?.[method]!
264
+ const options = this.#getOptions(operation, method)
265
+ const promiseMethod = this.#methods[method]?.call(this, operation, {
266
+ ...this.options,
267
+ ...options,
268
+ })
269
+ const promiseOperation = this.operation.call(this, operation, {
270
+ ...this.options,
271
+ ...options,
272
+ })
273
+
274
+ if (promiseMethod) {
275
+ acc.push(promiseMethod)
276
+ }
277
+ if (promiseOperation) {
278
+ acc.push(promiseOperation)
279
+ }
280
+ })
281
+
282
+ return acc
283
+ }, [] as OperationMethodResult<TFileMeta>[])
284
+
285
+ const operations = Object.values(this.operationsByMethod).map((item) => Object.values(item).map((item) => item.operation))
286
+
287
+ promises.push(this.all(operations.flat().filter(Boolean), this.operationsByMethod))
288
+
289
+ const files = await Promise.all(promises)
290
+
291
+ // using .flat because operationGenerator[method] can return a array of files or just one file
292
+ return files.flat().filter(Boolean)
293
+ }
294
+
295
+ /**
296
+ * Operation
297
+ */
298
+ abstract operation(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta>
299
+
300
+ /**
301
+ * GET
302
+ */
303
+ abstract get(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta>
304
+
305
+ /**
306
+ * POST
307
+ */
308
+ abstract post(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta>
309
+ /**
310
+ * PATCH
311
+ */
312
+ abstract patch(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta>
313
+
314
+ /**
315
+ * PUT
316
+ */
317
+ abstract put(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta>
318
+
319
+ /**
320
+ * DELETE
321
+ */
322
+ abstract delete(operation: Operation, options: TOptions): OperationMethodResult<TFileMeta>
323
+
324
+ /**
325
+ * Combination of GET, POST, PATCH, PUT, DELETE
326
+ */
327
+ abstract all(operations: Operation[], paths: OperationsByMethod): OperationMethodResult<TFileMeta>
328
+ }