diff --git a/.changeset/tricky-dancers-sniff.md b/.changeset/tricky-dancers-sniff.md new file mode 100644 index 000000000..16565812e --- /dev/null +++ b/.changeset/tricky-dancers-sniff.md @@ -0,0 +1,5 @@ +--- +"@kubb/plugin-oas": patch +--- + +allow `grouping` diff --git a/docs/changelog.md b/docs/changelog.md index 9ff0436b1..d4ad22472 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -6,6 +6,7 @@ title: Changelog ## 3.5.1 - [`core`](/plugins/core): build of `@kubb/core` with correct types +- [`plugin-oas`](/plugins/plugin-oas): allow `grouping` ## 3.5.0 - [`core`](/plugins/core): support banner with context for Oas diff --git a/docs/plugins/plugin-oas/index.md b/docs/plugins/plugin-oas/index.md index 9a5a87afd..ceafedd87 100644 --- a/docs/plugins/plugin-oas/index.md +++ b/docs/plugins/plugin-oas/index.md @@ -76,6 +76,30 @@ Add a footer text at the end of every file. | Type: | `string \| (oas: Oas) => string` | | Required: | `false` | + +### group + + +#### group.type +Define a type where to group the files on. + +| | | +|----------:|:--------| +| Type: | `'tag'` | +| Required: | `true` | + + + +#### group.name + +Return the name of a group based on the group name, this will be used for the file and name generation. + +| | | +|----------:|:------------------------------------| +| Type: | `(context: GroupContext) => string` | +| Required: | `false` | +| Default: | `(ctx) => '${ctx.group}Controller'` | + ### validate Validate your [`input`](/getting-started/configure#input) based on `@readme/openapi-parser`. diff --git a/examples/advanced/configs/kubb.config.ts b/examples/advanced/configs/kubb.config.ts index 8bdbc15f8..a3e10b7d9 100644 --- a/examples/advanced/configs/kubb.config.ts +++ b/examples/advanced/configs/kubb.config.ts @@ -26,11 +26,16 @@ export default defineConfig(() => { done: ['npm run typecheck', 'biome format --write ./', 'biome lint --apply-unsafe ./src'], }, plugins: [ - pluginOas({ validate: true }), + pluginOas({ + validate: true, + }), pluginOas({ output: { path: 'schemas2', }, + group: { + type: 'tag', + }, validate: false, }), pluginRedoc(), diff --git a/examples/advanced/configs/swagger.json b/examples/advanced/configs/swagger.json deleted file mode 100644 index 54b94e346..000000000 --- a/examples/advanced/configs/swagger.json +++ /dev/null @@ -1,349 +0,0 @@ -{ - "openapi": "3.0.0", - "info": { - "title": "X", - "version": "2025-01-01" - }, - "tags": [], - "paths": {}, - "components": { - "schemas": { - "BaseDateFilter": { - "type": "object", - "required": ["type", "operand"], - "properties": { - "type": { - "type": "string", - "enum": ["date"] - }, - "operand": { - "$ref": "#/components/schemas/DateFilterOperand" - } - }, - "discriminator": { - "propertyName": "operand", - "mapping": { - "between": "#/components/schemas/DateBetweenFilter", - "hasValue": "#/components/schemas/DateHasValueFilter", - "hasNoValue": "#/components/schemas/DateHasNoValueFilter" - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/BaseFilter" - } - ] - }, - "BaseDateFilterWithTimeZone": { - "type": "object", - "properties": { - "timezone": { - "type": "string" - }, - "timezoneVariant": { - "type": "string", - "enum": ["utc", "organization", "local"] - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/BaseDateFilter" - } - ] - }, - "BaseFilter": { - "type": "object", - "required": ["id", "type"], - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - } - }, - "discriminator": { - "propertyName": "type", - "mapping": { - "multiSelect": "#/components/schemas/MultiSelectFilterValue", - "text": "#/components/schemas/TextFilterValue", - "metadata": "#/components/schemas/MetadataFilterValue" - } - } - }, - "DateBetweenFilter": { - "type": "object", - "required": ["operand", "from", "to"], - "properties": { - "operand": { - "type": "string", - "enum": ["between"] - }, - "from": { - "type": "string", - "format": "date-time" - }, - "to": { - "type": "string", - "format": "date-time" - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/BaseDateFilterWithTimeZone" - } - ] - }, - "DateEqualsFilter": { - "type": "object", - "required": ["operand"], - "properties": { - "operand": { - "type": "string", - "enum": ["equals"] - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/SingleDateFilter" - } - ] - }, - "DateFilterOperand": { - "type": "string", - "enum": ["equals", "notEqualTo", "lessThan", "greaterThan", "lessOrEqual", "greaterOrEqual", "between", "hasValue", "hasNoValue"] - }, - "DateFilterValue": { - "anyOf": [ - { - "$ref": "#/components/schemas/DateEqualsFilter" - }, - { - "$ref": "#/components/schemas/DateNotEqualsFilter" - }, - { - "$ref": "#/components/schemas/DateLessThanFilter" - }, - { - "$ref": "#/components/schemas/DateGreaterThanFilter" - }, - { - "$ref": "#/components/schemas/DateLessOrEqualFilter" - }, - { - "$ref": "#/components/schemas/DateGreaterOrEqualFilter" - }, - { - "$ref": "#/components/schemas/DateBetweenFilter" - }, - { - "$ref": "#/components/schemas/DateHasValueFilter" - }, - { - "$ref": "#/components/schemas/DateHasNoValueFilter" - } - ] - }, - "DateGreaterOrEqualFilter": { - "type": "object", - "required": ["operand"], - "properties": { - "operand": { - "type": "string", - "enum": ["greaterOrEqual"] - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/SingleDateFilter" - } - ] - }, - "DateGreaterThanFilter": { - "type": "object", - "required": ["operand"], - "properties": { - "operand": { - "type": "string", - "enum": ["greaterThan"] - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/SingleDateFilter" - } - ] - }, - "DateHasNoValueFilter": { - "type": "object", - "required": ["operand"], - "properties": { - "operand": { - "type": "string", - "enum": ["hasNoValue"] - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/BaseDateFilter" - } - ] - }, - "DateHasValueFilter": { - "type": "object", - "required": ["operand"], - "properties": { - "operand": { - "type": "string", - "enum": ["hasValue"] - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/BaseDateFilter" - } - ] - }, - "DateLessOrEqualFilter": { - "type": "object", - "required": ["operand"], - "properties": { - "operand": { - "type": "string", - "enum": ["lessOrEqual"] - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/SingleDateFilter" - } - ] - }, - "DateLessThanFilter": { - "type": "object", - "required": ["operand"], - "properties": { - "operand": { - "type": "string", - "enum": ["lessThan"] - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/SingleDateFilter" - } - ] - }, - "DateNotEqualsFilter": { - "type": "object", - "required": ["operand"], - "properties": { - "operand": { - "type": "string", - "enum": ["notEqualTo"] - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/SingleDateFilter" - } - ] - }, - "MetadataFilterValue": { - "type": "object", - "required": ["type", "operand", "key"], - "properties": { - "type": { - "type": "string", - "enum": ["metadata"] - }, - "operand": { - "type": "string", - "enum": ["equals"] - }, - "key": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/BaseFilter" - } - ] - }, - "MultiSelectFilterOperand": { - "type": "string", - "enum": ["is", "isNot"] - }, - "MultiSelectFilterValue": { - "type": "object", - "required": ["type", "operand", "value"], - "properties": { - "type": { - "type": "string", - "enum": ["multiSelect"] - }, - "operand": { - "$ref": "#/components/schemas/MultiSelectFilterOperand" - }, - "value": { - "type": "array", - "items": {} - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/BaseFilter" - } - ] - }, - "SingleDateFilter": { - "type": "object", - "required": ["operand", "value"], - "properties": { - "operand": { - "type": "string", - "enum": ["equals", "notEqualTo", "lessThan", "greaterThan", "lessOrEqual", "greaterOrEqual"] - }, - "value": { - "type": "string", - "format": "date-time" - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/BaseDateFilterWithTimeZone" - } - ] - }, - "TextFilterOperand": { - "type": "string", - "enum": ["is", "isNot", "startsWith", "endsWith", "contains", "doesNotContain", "isEmpty", "isNotEmpty"] - }, - "TextFilterValue": { - "type": "object", - "required": ["type", "operand", "value"], - "properties": { - "type": { - "type": "string", - "enum": ["text"] - }, - "operand": { - "$ref": "#/components/schemas/TextFilterOperand" - }, - "value": { - "type": "string" - } - }, - "allOf": [ - { - "$ref": "#/components/schemas/BaseFilter" - } - ] - } - } - } -} diff --git a/packages/plugin-oas/src/plugin.ts b/packages/plugin-oas/src/plugin.ts index d87260703..296f2e648 100644 --- a/packages/plugin-oas/src/plugin.ts +++ b/packages/plugin-oas/src/plugin.ts @@ -1,4 +1,4 @@ -import { FileManager, createPlugin } from '@kubb/core' +import { FileManager, type Group, createPlugin } from '@kubb/core' import { getSchemas } from './utils/getSchemas.ts' import { parseFromConfig } from './utils/parseFromConfig.ts' @@ -6,6 +6,7 @@ import { parseFromConfig } from './utils/parseFromConfig.ts' import path from 'node:path' import type { Config } from '@kubb/core' import type { Logger } from '@kubb/core/logger' +import { camelCase } from '@kubb/core/transformers' import type { Oas } from '@kubb/oas' import { OperationGenerator } from './OperationGenerator.ts' import { SchemaGenerator } from './SchemaGenerator.ts' @@ -19,6 +20,7 @@ export const pluginOas = createPlugin((options) => { output = { path: 'schemas', }, + group, validate = true, generators = [jsonGenerator], serverIndex, @@ -84,6 +86,26 @@ export const pluginOas = createPlugin((options) => { return path.resolve(root, output.path) } + if (group && (options?.group?.path || options?.group?.tag)) { + const groupName: Group['name'] = group?.name + ? group.name + : (ctx) => { + if (group?.type === 'path') { + return `${ctx.group.split('/')[1]}` + } + return `${camelCase(ctx.group)}Controller` + } + + return path.resolve( + root, + output.path, + groupName({ + group: group.type === 'path' ? options.group.path! : options.group.tag!, + }), + baseName, + ) + } + return path.resolve(root, output.path, baseName) }, async buildStart() { diff --git a/packages/plugin-oas/src/types.ts b/packages/plugin-oas/src/types.ts index 7ce0e1b7b..2092932fb 100644 --- a/packages/plugin-oas/src/types.ts +++ b/packages/plugin-oas/src/types.ts @@ -1,4 +1,4 @@ -import type { Output, Plugin } from '@kubb/core' +import type { Group, Output, Plugin } from '@kubb/core' import type { PluginFactoryOptions, ResolveNameParams } from '@kubb/core' import type * as KubbFile from '@kubb/fs/types' @@ -33,6 +33,10 @@ export type Options = { * @default { path: 'schemas', barrelType: 'named' } */ output?: Output + /** + * Group the JSON files based on the provided name. + */ + group?: Group /** * Which server to use from the array of `servers.url[serverIndex]` * @example @@ -152,4 +156,4 @@ type ResolvedOptions = Options & { output: Output } -export type PluginOas = PluginFactoryOptions<'plugin-oas', Options, ResolvedOptions, API, never> +export type PluginOas = PluginFactoryOptions<'plugin-oas', Options, ResolvedOptions, API, ResolvePathOptions>