@kubb/plugin-oas
Version:
OpenAPI Specification (OAS) plugin for Kubb, providing core functionality for parsing and processing OpenAPI/Swagger schemas for code generation.
235 lines (214 loc) • 7.26 kB
text/typescript
import type { Group, Output, Plugin, PluginFactoryOptions, ResolveNameParams } from '@kubb/core'
import type { KubbFile } from '@kubb/fabric-core/types'
import type { contentType, HttpMethod, Oas, Operation, SchemaObject } from '@kubb/oas'
import type { Generator } from './generators/types.ts'
type GetOasOptions = {
validate?: boolean
}
type Context = {
getOas(options?: GetOasOptions): Promise<Oas>
getBaseURL(): Promise<string | undefined>
}
declare global {
namespace Kubb {
interface PluginContext extends Context {}
}
}
export type ResolvePathOptions = {
pluginKey?: Plugin['key']
group?: {
tag?: string
path?: string
}
type?: ResolveNameParams['type']
}
export type Options = {
/**
* Validate your input(see kubb.config) based on '@apidevtools/swagger-parser'.
* @default true
*/
validate?: boolean
/**
* Specify the export location for the files and define the behavior of the output
* @default { path: 'schemas', barrelType: 'named' }
*/
output?: Output<Oas>
/**
* Group the JSON files based on the provided name.
*/
group?: Group
/**
* Which server to use from the array of `servers.url[serverIndex]`
* @example
* - `0` returns `http://petstore.swagger.io/api`
* - `1` returns `http://localhost:3000`
*/
serverIndex?: number
/**
* Override OpenAPI server variables when resolving the base URL.
*
* When `serverIndex` is set and the selected server URL contains `{variable}` placeholders
* (as defined in the OpenAPI `servers[].variables` object), these values will be substituted.
* Any variable not provided here falls back to its `default` value from the specification.
*
* @example
* Given an OpenAPI spec with:
* ```yaml
* servers:
* - url: https://api.{env}.example.com
* variables:
* env:
* default: dev
* enum: [dev, staging, prod]
* ```
*
* ```ts
* pluginOas({
* serverIndex: 0,
* serverVariables: { env: 'prod' },
* })
* ```
* Results in baseURL: `https://api.prod.example.com`
*/
serverVariables?: Record<string, string>
/**
* Define which contentType should be used.
* By default, uses the first valid JSON media type.
*/
contentType?: contentType
/**
* Defines how the discriminator value should be interpreted during processing.
* - 'strict' uses the oneOf schemas as defined, without modification.
* - 'inherit' replaces the oneOf schema with the schema referenced by discriminator.mapping[key].
* @default 'strict'
* @see https://github.com/kubb-labs/kubb/issues/1736
*/
discriminator?: 'strict' | 'inherit'
/**
* Override some behavior of the Oas class instance, see '@kubb/oas'
*/
oasClass?: typeof Oas
/**
* Define some generators next to the JSON generation
*/
generators?: Array<Generator<PluginOas>>
/**
* Resolve name collisions when schemas from different components share the same name (case-insensitive).
*
* When enabled, Kubb automatically detects and resolves collisions using intelligent suffixes:
* - Cross-component collisions: Adds semantic suffixes based on the component type (Schema/Response/Request)
* - Same-component collisions: Adds numeric suffixes (2, 3, ...) for case-insensitive duplicates
* - Nested enum collisions: Includes root schema name in enum names to prevent duplicates across schemas
*
* When disabled (legacy behavior), collisions may result in duplicate files or overwrite issues.
*
* **Cross-component collision example:**
* If you have "Order" in both schemas and requestBodies:
* - With `collisionDetection: true`: Generates `OrderSchema.ts`, `OrderRequest.ts`
* - With `collisionDetection: false`: May generate duplicate `Order.ts` files
*
* **Same-component collision example:**
* If you have "Variant" and "variant" in schemas:
* - With `collisionDetection: true`: Generates `Variant.ts`, `Variant2.ts`
* - With `collisionDetection: false`: May overwrite or create duplicates
*
* **Nested enum collision example:**
* If you have "params.channel" enum in both "NotificationTypeA" and "NotificationTypeB":
* - With `collisionDetection: true`: Generates `notificationTypeAParamsChannelEnum`, `notificationTypeBParamsChannelEnum`
* - With `collisionDetection: false`: Generates duplicate `paramsChannelEnum` in both files
*
* @default false (will be `true` in v5)
* @see https://github.com/kubb-labs/kubb/issues/1999
* @note In Kubb v5, this will be enabled by default and the deprecated `usedEnumNames` mechanism will be removed
*/
collisionDetection?: boolean
}
/**
* `propertyName` is the ref name + resolved with the nameResolver
* @example import { Pet } from './Pet'
*
* `originalName` is the original name used(in PascalCase), only used to remove duplicates
*
* `pluginKey` can be used to override the current plugin being used, handy when you want to import a type/schema out of another plugin
* @example import a type(plugin-ts) for a mock file(swagger-faker)
*/
export type Ref = {
propertyName: string
originalName: string
path: KubbFile.Path
pluginKey?: Plugin['key']
}
export type Refs = Record<string, Ref>
export type Resolver = {
/**
* Original name or name resolved by `resolveName({ name: operation?.getOperationId() as string, pluginName })`
*/
name: string
baseName: KubbFile.BaseName
path: KubbFile.Path
}
export type OperationSchema = {
/**
* Converted name, contains already `PathParams`, `QueryParams`, ...
*/
name: string
schema: SchemaObject
operation?: Operation
/**
* OperationName in PascalCase, only being used in OperationGenerator
*/
operationName: string
description?: string
statusCode?: number
keys?: string[]
keysToOmit?: string[]
withData?: boolean
}
export type OperationSchemas = {
pathParams?: OperationSchema & { keysToOmit?: never }
queryParams?: OperationSchema & { keysToOmit?: never }
headerParams?: OperationSchema & { keysToOmit?: never }
request?: OperationSchema
response: OperationSchema
responses: Array<OperationSchema>
statusCodes?: Array<OperationSchema>
errors?: Array<OperationSchema>
}
type ByTag = {
type: 'tag'
pattern: string | RegExp
}
type ByOperationId = {
type: 'operationId'
pattern: string | RegExp
}
type ByPath = {
type: 'path'
pattern: string | RegExp
}
type ByMethod = {
type: 'method'
pattern: HttpMethod | RegExp
}
// TODO implement as alternative for ByMethod
// type ByMethods = {
// type: 'methods'
// pattern: Array<HttpMethod>
// }
type BySchemaName = {
type: 'schemaName'
pattern: string | RegExp
}
type ByContentType = {
type: 'contentType'
pattern: string | RegExp
}
export type Exclude = ByTag | ByOperationId | ByPath | ByMethod | ByContentType
export type Include = ByTag | ByOperationId | ByPath | ByMethod | ByContentType
export type Override<TOptions> = (ByTag | ByOperationId | ByPath | ByMethod | BySchemaName | ByContentType) & {
options: Partial<TOptions>
}
type ResolvedOptions = Options & {
output: Output<Oas>
}
export type PluginOas = PluginFactoryOptions<'plugin-oas', Options, ResolvedOptions, Context, ResolvePathOptions>