@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.
- package/LICENSE +21 -0
- package/README.md +44 -0
- package/dist/OperationGenerator-DvnXUUp4.d.ts +56 -0
- package/dist/OperationGenerator-X6CTMfhG.d.cts +56 -0
- package/dist/Schema-BWPWyiQO.d.cts +39 -0
- package/dist/Schema-DFZBfjF2.d.ts +39 -0
- package/dist/SchemaGenerator-hK5SHxTI.d.ts +316 -0
- package/dist/SchemaGenerator-z_7YrAAB.d.cts +316 -0
- package/dist/chunk-2MJ2CQMI.js +61 -0
- package/dist/chunk-2MJ2CQMI.js.map +1 -0
- package/dist/chunk-3RCQ2LNT.js +81 -0
- package/dist/chunk-3RCQ2LNT.js.map +1 -0
- package/dist/chunk-55NUFNT6.cjs +68 -0
- package/dist/chunk-55NUFNT6.cjs.map +1 -0
- package/dist/chunk-ECXSQTMV.cjs +81 -0
- package/dist/chunk-ECXSQTMV.cjs.map +1 -0
- package/dist/chunk-EPTOYYAP.js +3312 -0
- package/dist/chunk-EPTOYYAP.js.map +1 -0
- package/dist/chunk-H52M2RUX.cjs +3312 -0
- package/dist/chunk-H52M2RUX.cjs.map +1 -0
- package/dist/chunk-LQ6IAWRX.js +68 -0
- package/dist/chunk-LQ6IAWRX.js.map +1 -0
- package/dist/chunk-VNFSHGSN.cjs +61 -0
- package/dist/chunk-VNFSHGSN.cjs.map +1 -0
- package/dist/components.cjs +18 -0
- package/dist/components.cjs.map +1 -0
- package/dist/components.d.cts +41 -0
- package/dist/components.d.ts +41 -0
- package/dist/components.js +18 -0
- package/dist/components.js.map +1 -0
- package/dist/hooks.cjs +152 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.d.cts +76 -0
- package/dist/hooks.d.ts +76 -0
- package/dist/hooks.js +152 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.cjs +985 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +985 -0
- package/dist/index.js.map +1 -0
- package/dist/types-n5zV4Q3s.d.cts +146 -0
- package/dist/types-n5zV4Q3s.d.ts +146 -0
- package/dist/utils.cjs +126 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +80 -0
- package/dist/utils.d.ts +80 -0
- package/dist/utils.js +126 -0
- package/dist/utils.js.map +1 -0
- package/package.json +107 -0
- package/src/OperationGenerator.ts +328 -0
- package/src/SchemaGenerator.ts +827 -0
- package/src/SchemaMapper.ts +145 -0
- package/src/components/Oas.tsx +31 -0
- package/src/components/Operation.tsx +21 -0
- package/src/components/Schema.tsx +156 -0
- package/src/components/index.ts +3 -0
- package/src/hooks/index.ts +5 -0
- package/src/hooks/useOas.ts +15 -0
- package/src/hooks/useOperation.ts +18 -0
- package/src/hooks/useOperationManager.ts +142 -0
- package/src/hooks/useOperations.ts +40 -0
- package/src/hooks/useSchema.ts +23 -0
- package/src/index.ts +30 -0
- package/src/plugin.ts +133 -0
- package/src/types.ts +147 -0
- package/src/utils/getComments.ts +15 -0
- package/src/utils/getGroupedByTagFiles.ts +81 -0
- package/src/utils/getParams.ts +57 -0
- package/src/utils/getSchemaFactory.ts +33 -0
- package/src/utils/getSchemas.ts +45 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/parseFromConfig.ts +36 -0
- package/src/utils/refSorter.ts +13 -0
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
|
|
3
|
+
import { createPlugin } from '@kubb/core'
|
|
4
|
+
import { camelCase } from '@kubb/core/transformers'
|
|
5
|
+
|
|
6
|
+
import { getSchemas } from './utils/getSchemas.ts'
|
|
7
|
+
|
|
8
|
+
import type { Config } from '@kubb/core'
|
|
9
|
+
import type { Logger } from '@kubb/core/logger'
|
|
10
|
+
import type { Oas, OasTypes } from '@kubb/oas'
|
|
11
|
+
import type { FormatOptions } from '@kubb/oas/parser'
|
|
12
|
+
import type { PluginOas } from './types.ts'
|
|
13
|
+
import { parseFromConfig } from './utils/parseFromConfig.ts'
|
|
14
|
+
|
|
15
|
+
export const pluginOasName = 'plugin-oas' satisfies PluginOas['name']
|
|
16
|
+
|
|
17
|
+
export const pluginOas = createPlugin<PluginOas>((options) => {
|
|
18
|
+
const {
|
|
19
|
+
output = { path: 'schemas', export: false },
|
|
20
|
+
experimentalFilter: filter,
|
|
21
|
+
experimentalSort: sort,
|
|
22
|
+
validate = true,
|
|
23
|
+
serverIndex = 0,
|
|
24
|
+
contentType,
|
|
25
|
+
} = options
|
|
26
|
+
|
|
27
|
+
const getOas = async ({ config, logger, formatOptions }: { config: Config; logger: Logger; formatOptions?: FormatOptions }): Promise<Oas> => {
|
|
28
|
+
try {
|
|
29
|
+
// needs to be in a different variable or the catch here will not work(return of a promise instead)
|
|
30
|
+
const oas = await parseFromConfig(config, formatOptions)
|
|
31
|
+
|
|
32
|
+
if (validate) {
|
|
33
|
+
await oas.valdiate()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return oas
|
|
37
|
+
} catch (e) {
|
|
38
|
+
const error = e as Error
|
|
39
|
+
|
|
40
|
+
logger.emit('warning', error?.message)
|
|
41
|
+
return parseFromConfig(config)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
name: pluginOasName,
|
|
47
|
+
options,
|
|
48
|
+
|
|
49
|
+
api() {
|
|
50
|
+
const { config, logger } = this
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
getOas(formatOptions) {
|
|
54
|
+
return getOas({ config, logger, formatOptions })
|
|
55
|
+
},
|
|
56
|
+
async getSchemas({ includes } = {}) {
|
|
57
|
+
const oas = await this.getOas()
|
|
58
|
+
return getSchemas({ oas, contentType, includes })
|
|
59
|
+
},
|
|
60
|
+
async getBaseURL() {
|
|
61
|
+
const oasInstance = await this.getOas()
|
|
62
|
+
const baseURL = oasInstance.api.servers?.at(serverIndex)?.url
|
|
63
|
+
return baseURL
|
|
64
|
+
},
|
|
65
|
+
contentType,
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
resolvePath(baseName) {
|
|
69
|
+
if (output === false) {
|
|
70
|
+
return undefined
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const root = path.resolve(this.config.root, this.config.output.path)
|
|
74
|
+
|
|
75
|
+
return path.resolve(root, output.path, baseName)
|
|
76
|
+
},
|
|
77
|
+
resolveName(name, type) {
|
|
78
|
+
return camelCase(name, { isFile: type === 'file' })
|
|
79
|
+
},
|
|
80
|
+
async writeFile(source, writePath) {
|
|
81
|
+
if (!writePath.endsWith('.json') || !source) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return this.fileManager.write(source, writePath, { sanity: false })
|
|
86
|
+
},
|
|
87
|
+
async buildStart() {
|
|
88
|
+
if (!output) {
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const oas = await getOas({
|
|
93
|
+
config: this.config,
|
|
94
|
+
logger: this.logger,
|
|
95
|
+
formatOptions: {
|
|
96
|
+
filterSet: filter,
|
|
97
|
+
sortSet: sort,
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
await oas.dereference()
|
|
101
|
+
const schemas = getSchemas({ oas, contentType })
|
|
102
|
+
|
|
103
|
+
const mapSchema = async ([name, schema]: [string, OasTypes.SchemaObject]) => {
|
|
104
|
+
const resolvedPath = this.resolvePath({
|
|
105
|
+
baseName: `${name}.json`,
|
|
106
|
+
pluginKey: this.plugin.key,
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const resvoledFileName = this.resolveName({
|
|
110
|
+
name: `${name}.json`,
|
|
111
|
+
pluginKey: [pluginOasName],
|
|
112
|
+
type: 'file',
|
|
113
|
+
}) as `${string}.json`
|
|
114
|
+
|
|
115
|
+
if (!resolvedPath) {
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
await this.addFile({
|
|
120
|
+
path: resolvedPath,
|
|
121
|
+
baseName: resvoledFileName,
|
|
122
|
+
source: JSON.stringify(schema),
|
|
123
|
+
meta: {
|
|
124
|
+
pluginKey: this.plugin.key,
|
|
125
|
+
},
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const promises = Object.entries(schemas).map(mapSchema)
|
|
130
|
+
await Promise.all(promises)
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
})
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { Plugin } from '@kubb/core'
|
|
2
|
+
import type { KubbFile, PluginFactoryOptions, ResolveNameParams } from '@kubb/core'
|
|
3
|
+
import type { HttpMethod, Oas, Operation, SchemaObject, contentType } from '@kubb/oas'
|
|
4
|
+
import type { FormatOptions } from '@kubb/oas/parser'
|
|
5
|
+
import type { GetSchemasProps } from './utils/getSchemas.ts'
|
|
6
|
+
|
|
7
|
+
export type ResolvePathOptions = {
|
|
8
|
+
pluginKey?: Plugin['key']
|
|
9
|
+
tag?: string
|
|
10
|
+
type?: ResolveNameParams['type']
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type API = {
|
|
14
|
+
getOas: (formatOptions?: FormatOptions) => Promise<Oas>
|
|
15
|
+
getSchemas: (options?: Pick<GetSchemasProps, 'includes'>) => Promise<Record<string, SchemaObject>>
|
|
16
|
+
getBaseURL: () => Promise<string | undefined>
|
|
17
|
+
contentType?: contentType
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type Options = {
|
|
21
|
+
/**
|
|
22
|
+
* Validate your input(see kubb.config) based on '@apidevtools/swagger-parser'.
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
validate?: boolean
|
|
26
|
+
output?:
|
|
27
|
+
| {
|
|
28
|
+
/**
|
|
29
|
+
* Relative path to save the JSON models.
|
|
30
|
+
* False will not generate the schema JSON's.
|
|
31
|
+
* @default 'schemas'
|
|
32
|
+
*/
|
|
33
|
+
path: string
|
|
34
|
+
}
|
|
35
|
+
| false
|
|
36
|
+
/**
|
|
37
|
+
* Which server to use from the array of `servers.url[serverIndex]`
|
|
38
|
+
* @example
|
|
39
|
+
* - `0` will return `http://petstore.swagger.io/api`
|
|
40
|
+
* - `1` will return `http://localhost:3000`
|
|
41
|
+
* @default 0
|
|
42
|
+
*/
|
|
43
|
+
serverIndex?: number
|
|
44
|
+
/**
|
|
45
|
+
* Define which contentType should be used.
|
|
46
|
+
* By default, this is set based on the first used contentType..
|
|
47
|
+
*/
|
|
48
|
+
contentType?: contentType
|
|
49
|
+
experimentalFilter?: FormatOptions['filterSet']
|
|
50
|
+
experimentalSort?: FormatOptions['sortSet']
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* `propertyName` is the ref name + resolved with the nameResolver
|
|
55
|
+
* @example `import { Pet } from './Pet'`
|
|
56
|
+
*
|
|
57
|
+
* `originalName` is the original name used(in PascalCase), only used to remove duplicates
|
|
58
|
+
*
|
|
59
|
+
* `pluginKey` can be used to override the current plugin being used, handy when you want to import a type/schema out of another plugin
|
|
60
|
+
* @example import a type(swagger-ts) for a mock file(swagger-faker)
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
export type Ref = {
|
|
64
|
+
propertyName: string
|
|
65
|
+
originalName: string
|
|
66
|
+
path: KubbFile.OptionalPath
|
|
67
|
+
pluginKey?: Plugin['key']
|
|
68
|
+
}
|
|
69
|
+
export type Refs = Record<string, Ref>
|
|
70
|
+
|
|
71
|
+
export type Resolver = {
|
|
72
|
+
/**
|
|
73
|
+
* Original name or name resolved by `resolveName({ name: operation?.getOperationId() as string, pluginName })`
|
|
74
|
+
*/
|
|
75
|
+
name: string
|
|
76
|
+
baseName: KubbFile.BaseName
|
|
77
|
+
path: KubbFile.Path
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type OperationSchema = {
|
|
81
|
+
/**
|
|
82
|
+
* Converted name, contains already `PathParams`, `QueryParams`, ...
|
|
83
|
+
*/
|
|
84
|
+
name: string
|
|
85
|
+
schema: SchemaObject
|
|
86
|
+
operation?: Operation
|
|
87
|
+
/**
|
|
88
|
+
* OperationName in PascalCase, only being used in OperationGenerator
|
|
89
|
+
*/
|
|
90
|
+
operationName?: string
|
|
91
|
+
description?: string
|
|
92
|
+
statusCode?: number
|
|
93
|
+
keys?: string[]
|
|
94
|
+
keysToOmit?: string[]
|
|
95
|
+
withData?: boolean
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export type OperationSchemas = {
|
|
99
|
+
pathParams?: OperationSchema & { keysToOmit?: never }
|
|
100
|
+
queryParams?: OperationSchema & { keysToOmit?: never }
|
|
101
|
+
headerParams?: OperationSchema & { keysToOmit?: never }
|
|
102
|
+
request?: OperationSchema
|
|
103
|
+
response: OperationSchema
|
|
104
|
+
statusCodes?: Array<OperationSchema>
|
|
105
|
+
errors?: Array<OperationSchema>
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export type OperationsByMethod = Record<string, Record<HttpMethod, { operation: Operation; schemas: OperationSchemas }>>
|
|
109
|
+
type ByTag = {
|
|
110
|
+
type: 'tag'
|
|
111
|
+
pattern: string | RegExp
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
type ByOperationId = {
|
|
115
|
+
type: 'operationId'
|
|
116
|
+
pattern: string | RegExp
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
type ByPath = {
|
|
120
|
+
type: 'path'
|
|
121
|
+
pattern: string | RegExp
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
type ByMethod = {
|
|
125
|
+
type: 'method'
|
|
126
|
+
pattern: HttpMethod | RegExp
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
type BySchemaName = {
|
|
130
|
+
type: 'schemaName'
|
|
131
|
+
pattern: string | RegExp
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export type Exclude = ByTag | ByOperationId | ByPath | ByMethod
|
|
135
|
+
export type Include = ByTag | ByOperationId | ByPath | ByMethod
|
|
136
|
+
|
|
137
|
+
export type Override<TOptions> = (ByTag | ByOperationId | ByPath | ByMethod | BySchemaName) & {
|
|
138
|
+
options: Partial<TOptions>
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export type PluginOas = PluginFactoryOptions<'plugin-oas', Options, Options, API, never>
|
|
142
|
+
|
|
143
|
+
declare module '@kubb/core' {
|
|
144
|
+
export interface _Register {
|
|
145
|
+
['@kubb/plugin-oas']: PluginOas
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import transformers from '@kubb/core/transformers'
|
|
2
|
+
import { URLPath } from '@kubb/core/utils'
|
|
3
|
+
|
|
4
|
+
import type { Operation } from '@kubb/oas'
|
|
5
|
+
|
|
6
|
+
export function getComments(operation: Operation): string[] {
|
|
7
|
+
return [
|
|
8
|
+
operation.getDescription() && `@description ${operation.getDescription()}`,
|
|
9
|
+
operation.getSummary() && `@summary ${operation.getSummary()}`,
|
|
10
|
+
operation.path && `@link ${new URLPath(operation.path).URL}`,
|
|
11
|
+
operation.isDeprecated() && '@deprecated',
|
|
12
|
+
]
|
|
13
|
+
.filter(Boolean)
|
|
14
|
+
.map((text) => transformers.trim(text))
|
|
15
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
|
|
3
|
+
import { FileManager } from '@kubb/core'
|
|
4
|
+
import { getRelativePath } from '@kubb/core/fs'
|
|
5
|
+
import transformers from '@kubb/core/transformers'
|
|
6
|
+
import { renderTemplate } from '@kubb/core/utils'
|
|
7
|
+
|
|
8
|
+
import type { KubbFile, Plugin } from '@kubb/core'
|
|
9
|
+
import type { Logger } from '@kubb/core/logger'
|
|
10
|
+
|
|
11
|
+
type Options = {
|
|
12
|
+
logger: Logger
|
|
13
|
+
files: KubbFile.File[]
|
|
14
|
+
plugin: Plugin
|
|
15
|
+
template: string
|
|
16
|
+
exportAs: string
|
|
17
|
+
/**
|
|
18
|
+
* Root based on root and output.path specified in the config
|
|
19
|
+
*/
|
|
20
|
+
root: string
|
|
21
|
+
/**
|
|
22
|
+
* Output for plugin
|
|
23
|
+
*/
|
|
24
|
+
output: {
|
|
25
|
+
path: string
|
|
26
|
+
exportAs?: string
|
|
27
|
+
extName?: KubbFile.Extname
|
|
28
|
+
exportType?: 'barrel' | 'barrelNamed' | false
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type FileMeta = {
|
|
33
|
+
pluginKey?: Plugin['key']
|
|
34
|
+
tag?: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function getGroupedByTagFiles({ logger, files, plugin, template, exportAs, root, output }: Options): Promise<KubbFile.File<FileMeta>[]> {
|
|
38
|
+
const { path, exportType = 'barrel' } = output
|
|
39
|
+
const mode = FileManager.getMode(resolve(root, path))
|
|
40
|
+
|
|
41
|
+
if (mode === 'single' || exportType === false) {
|
|
42
|
+
return []
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return files
|
|
46
|
+
.filter((file) => {
|
|
47
|
+
const name = file.meta?.pluginKey?.[0]
|
|
48
|
+
return name === plugin.name
|
|
49
|
+
})
|
|
50
|
+
.map((file: KubbFile.File<FileMeta>) => {
|
|
51
|
+
if (!file.meta?.tag) {
|
|
52
|
+
logger?.emit('debug', [`Could not find a tagName for ${JSON.stringify(file, undefined, 2)}`])
|
|
53
|
+
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const tag = file.meta?.tag && transformers.camelCase(file.meta.tag)
|
|
58
|
+
const tagPath = getRelativePath(resolve(root, output.path), resolve(root, renderTemplate(template, { tag })))
|
|
59
|
+
const tagName = renderTemplate(exportAs, { tag })
|
|
60
|
+
|
|
61
|
+
if (tagName) {
|
|
62
|
+
return {
|
|
63
|
+
baseName: 'index.ts' as const,
|
|
64
|
+
path: resolve(root, output.path, 'index.ts'),
|
|
65
|
+
source: '',
|
|
66
|
+
exports: [
|
|
67
|
+
{
|
|
68
|
+
path: output.extName ? `${tagPath}/index${output.extName}` : `${tagPath}/index`,
|
|
69
|
+
asAlias: true,
|
|
70
|
+
name: tagName,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
meta: {
|
|
74
|
+
pluginKey: plugin.key,
|
|
75
|
+
},
|
|
76
|
+
exportable: true,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
.filter(Boolean)
|
|
81
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isParameterObject } from '@kubb/oas'
|
|
2
|
+
|
|
3
|
+
import type { FunctionParamsAST } from '@kubb/core/utils'
|
|
4
|
+
import type { OasTypes } from '@kubb/oas'
|
|
5
|
+
import type { Params } from '@kubb/react'
|
|
6
|
+
import type { OperationSchema } from '../types.ts'
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @deprecated
|
|
10
|
+
* TODO move to operationManager hook
|
|
11
|
+
*/
|
|
12
|
+
export function getASTParams(
|
|
13
|
+
operationSchema: OperationSchema | undefined,
|
|
14
|
+
{
|
|
15
|
+
typed = false,
|
|
16
|
+
override,
|
|
17
|
+
}: {
|
|
18
|
+
typed?: boolean
|
|
19
|
+
override?: (data: FunctionParamsAST) => FunctionParamsAST
|
|
20
|
+
} = {},
|
|
21
|
+
): FunctionParamsAST[] {
|
|
22
|
+
if (!operationSchema || !operationSchema.schema.properties || !operationSchema.name) {
|
|
23
|
+
return []
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return Object.entries(operationSchema.schema.properties).map(([name, schema]: [string, OasTypes.SchemaObject]) => {
|
|
27
|
+
const isParam = isParameterObject(schema)
|
|
28
|
+
const data: FunctionParamsAST = {
|
|
29
|
+
name,
|
|
30
|
+
enabled: !!name,
|
|
31
|
+
required: isParam ? schema.required : true,
|
|
32
|
+
type: typed ? `${operationSchema.name}["${name}"]` : undefined,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return override ? override(data) : data
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getPathParams(
|
|
40
|
+
operationSchema: OperationSchema | undefined,
|
|
41
|
+
options: {
|
|
42
|
+
typed?: boolean
|
|
43
|
+
override?: (data: FunctionParamsAST) => FunctionParamsAST
|
|
44
|
+
} = {},
|
|
45
|
+
) {
|
|
46
|
+
return getASTParams(operationSchema, options).reduce((acc, curr) => {
|
|
47
|
+
if (curr.name && curr.enabled) {
|
|
48
|
+
acc[curr.name] = {
|
|
49
|
+
default: curr.default,
|
|
50
|
+
type: curr.type,
|
|
51
|
+
optional: !curr.required,
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return acc
|
|
56
|
+
}, {} as Params)
|
|
57
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isOpenApiV3_1Document } from '@kubb/oas'
|
|
2
|
+
|
|
3
|
+
import type { Oas, OpenAPIV3, OpenAPIV3_1, SchemaObject } from '@kubb/oas'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Make it possible to narrow down the schema based on a specific version(3 or 3.1)
|
|
7
|
+
*/
|
|
8
|
+
type SchemaResult<TWithRef extends boolean = false> =
|
|
9
|
+
| {
|
|
10
|
+
schema?: (TWithRef extends true ? OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject : OpenAPIV3.SchemaObject) & {
|
|
11
|
+
nullable?: boolean
|
|
12
|
+
'x-nullable'?: boolean
|
|
13
|
+
}
|
|
14
|
+
version: '3.0'
|
|
15
|
+
}
|
|
16
|
+
| {
|
|
17
|
+
schema?: (TWithRef extends true ? OpenAPIV3_1.SchemaObject | OpenAPIV3_1.ReferenceObject : OpenAPIV3_1.SchemaObject) & {
|
|
18
|
+
nullable?: boolean
|
|
19
|
+
'x-nullable'?: boolean
|
|
20
|
+
}
|
|
21
|
+
version: '3.1'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function getSchemaFactory<TWithRef extends boolean = false>(oas: Oas): (schema?: SchemaObject) => SchemaResult<TWithRef> {
|
|
25
|
+
return (schema?: SchemaObject) => {
|
|
26
|
+
const version = isOpenApiV3_1Document(oas.api) ? '3.1' : '3.0'
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
schema,
|
|
30
|
+
version,
|
|
31
|
+
} as SchemaResult<TWithRef>
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Oas, OasTypes, contentType } from '@kubb/oas'
|
|
2
|
+
|
|
3
|
+
type Mode = 'schemas' | 'responses' | 'requestBodies'
|
|
4
|
+
|
|
5
|
+
export type GetSchemasProps = {
|
|
6
|
+
oas: Oas
|
|
7
|
+
contentType?: contentType
|
|
8
|
+
includes?: Mode[]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getSchemas({ oas, contentType, includes = ['schemas', 'requestBodies', 'responses'] }: GetSchemasProps): Record<string, OasTypes.SchemaObject> {
|
|
12
|
+
const components = oas.getDefinition().components
|
|
13
|
+
|
|
14
|
+
let schemas: Record<string, OasTypes.SchemaObject> = {}
|
|
15
|
+
|
|
16
|
+
if (includes.includes('schemas')) {
|
|
17
|
+
schemas = {
|
|
18
|
+
...schemas,
|
|
19
|
+
...((components?.schemas as Record<string, OasTypes.SchemaObject>) || {}),
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const requestBodies = components?.requestBodies || {}
|
|
24
|
+
if (includes.includes('responses')) {
|
|
25
|
+
const responses = components?.responses || {}
|
|
26
|
+
|
|
27
|
+
Object.entries(responses).forEach(([name, response]: [string, OasTypes.ResponseObject]) => {
|
|
28
|
+
if (response.content && !schemas[name]) {
|
|
29
|
+
const firstContentType = Object.keys(response.content)[0] || 'application/json'
|
|
30
|
+
schemas[name] = response.content?.[contentType || firstContentType]?.schema as OasTypes.SchemaObject
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (includes.includes('requestBodies')) {
|
|
36
|
+
Object.entries(requestBodies).forEach(([name, request]: [string, OasTypes.RequestBodyObject]) => {
|
|
37
|
+
if (request.content && !schemas[name]) {
|
|
38
|
+
const firstContentType = Object.keys(request.content)[0] || 'application/json'
|
|
39
|
+
schemas[name] = request.content?.[contentType || firstContentType]?.schema as OasTypes.SchemaObject
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return schemas
|
|
45
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { getComments } from './getComments.ts'
|
|
2
|
+
export { getGroupedByTagFiles } from './getGroupedByTagFiles.ts'
|
|
3
|
+
export { getASTParams, getPathParams } from './getParams.ts'
|
|
4
|
+
export { getSchemaFactory } from './getSchemaFactory.ts'
|
|
5
|
+
export type { GetSchemasProps } from './getSchemas.ts'
|
|
6
|
+
export { getSchemas } from './getSchemas.ts'
|
|
7
|
+
export { refsSorter } from './refSorter.ts'
|
|
8
|
+
export { parseFromConfig } from './parseFromConfig.ts'
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
|
|
3
|
+
import { URLPath } from '@kubb/core/utils'
|
|
4
|
+
|
|
5
|
+
import { type FormatOptions, parse } from '@kubb/oas/parser'
|
|
6
|
+
|
|
7
|
+
import type { Config } from '@kubb/core'
|
|
8
|
+
import type { Oas, OasTypes } from '@kubb/oas'
|
|
9
|
+
import yaml from '@stoplight/yaml'
|
|
10
|
+
|
|
11
|
+
export function parseFromConfig(config: Config, options: FormatOptions = {}): Promise<Oas> {
|
|
12
|
+
if ('data' in config.input) {
|
|
13
|
+
if (typeof config.input.data === 'object') {
|
|
14
|
+
const api: OasTypes.OASDocument = JSON.parse(JSON.stringify(config.input.data)) as OasTypes.OASDocument
|
|
15
|
+
return parse(api, options)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const api: string = yaml.parse(config.input.data as string) as string
|
|
20
|
+
|
|
21
|
+
return parse(api, options)
|
|
22
|
+
} catch (e) {
|
|
23
|
+
/* empty */
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const api: OasTypes.OASDocument = JSON.parse(JSON.stringify(config.input.data)) as OasTypes.OASDocument
|
|
27
|
+
|
|
28
|
+
return parse(api, options)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (new URLPath(config.input.path).isURL) {
|
|
32
|
+
return parse(config.input.path, options)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return parse(resolve(config.root, config.input.path), options)
|
|
36
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Refs } from '../types.ts'
|
|
2
|
+
|
|
3
|
+
type Generated = { import: { refs: Refs; name: string } }
|
|
4
|
+
|
|
5
|
+
export function refsSorter<T extends Generated>(a: T, b: T): number {
|
|
6
|
+
if (Object.keys(a.import.refs)?.length < Object.keys(b.import.refs)?.length) {
|
|
7
|
+
return -1
|
|
8
|
+
}
|
|
9
|
+
if (Object.keys(a.import.refs)?.length > Object.keys(b.import.refs)?.length) {
|
|
10
|
+
return 1
|
|
11
|
+
}
|
|
12
|
+
return 0
|
|
13
|
+
}
|