UNPKG

@kubb/plugin-oas

Version:

OpenAPI Specification (OAS) plugin for Kubb, providing core functionality for parsing and processing OpenAPI/Swagger schemas for code generation.

324 lines (322 loc) • 11.3 kB
import { parseFromConfig } from './chunk-G3FDK7YW.js'; import { jsonGenerator } from './chunk-MBX66JAT.js'; export { createGenerator, createReactGenerator } from './chunk-MBX66JAT.js'; import './chunk-6S7YFY6F.js'; import { SchemaGenerator } from './chunk-P2VXWGXZ.js'; export { SchemaGenerator } from './chunk-P2VXWGXZ.js'; export { isKeyword, schemaKeywords } from './chunk-76E35IZ2.js'; import './chunk-PORSNYI5.js'; import './chunk-JNN4JPWK.js'; import { createPlugin, FileManager, BaseGenerator } from '@kubb/core'; import transformers, { camelCase } from '@kubb/core/transformers'; import pLimit from 'p-limit'; import path from 'path'; var OperationGenerator = class extends BaseGenerator { #getOptions(operation, method) { const { override = [] } = this.context; const operationId = operation.getOperationId({ friendlyCase: true }); const contentType = operation.getContentType(); return override.find(({ pattern, type }) => { switch (type) { case "tag": return operation.getTags().some((tag) => tag.name.match(pattern)); case "operationId": return !!operationId.match(pattern); case "path": return !!operation.path.match(pattern); case "method": return !!method.match(pattern); case "contentType": return !!contentType.match(pattern); default: return false; } })?.options || {}; } #isExcluded(operation, method) { const { exclude = [] } = this.context; const operationId = operation.getOperationId({ friendlyCase: true }); const contentType = operation.getContentType(); return exclude.some(({ pattern, type }) => { switch (type) { case "tag": return operation.getTags().some((tag) => tag.name.match(pattern)); case "operationId": return !!operationId.match(pattern); case "path": return !!operation.path.match(pattern); case "method": return !!method.match(pattern); case "contentType": return !!contentType.match(pattern); default: return false; } }); } #isIncluded(operation, method) { const { include = [] } = this.context; const operationId = operation.getOperationId({ friendlyCase: true }); const contentType = operation.getContentType(); return include.some(({ pattern, type }) => { switch (type) { case "tag": return operation.getTags().some((tag) => tag.name.match(pattern)); case "operationId": return !!operationId.match(pattern); case "path": return !!operation.path.match(pattern); case "method": return !!method.match(pattern); case "contentType": return !!contentType.match(pattern); default: return false; } }); } getSchemas(operation, { resolveName = (name) => name } = {}) { const operationId = operation.getOperationId({ friendlyCase: true }); const method = operation.method; const operationName = transformers.pascalCase(operationId); const resolveKeys = (schema) => schema?.properties ? Object.keys(schema.properties) : void 0; const pathParamsSchema = this.context.oas.getParametersSchema(operation, "path"); const queryParamsSchema = this.context.oas.getParametersSchema(operation, "query"); const headerParamsSchema = this.context.oas.getParametersSchema(operation, "header"); const requestSchema = this.context.oas.getRequestSchema(operation); const statusCodes = operation.getResponseStatusCodes().map((statusCode) => { const name = statusCode === "default" ? "error" : statusCode; const schema = this.context.oas.getResponseSchema(operation, statusCode); const keys = resolveKeys(schema); return { name: resolveName(transformers.pascalCase(`${operationId} ${name}`)), description: operation.getResponseByStatusCode(statusCode)?.description, schema, operation, operationName, statusCode: name === "error" ? void 0 : Number(statusCode), keys, keysToOmit: keys?.filter((key) => schema?.properties?.[key]?.writeOnly) }; }); const successful = statusCodes.filter((item) => item.statusCode?.toString().startsWith("2")); const errors = statusCodes.filter((item) => item.statusCode?.toString().startsWith("4") || item.statusCode?.toString().startsWith("5")); return { pathParams: pathParamsSchema ? { name: resolveName(transformers.pascalCase(`${operationId} PathParams`)), operation, operationName, schema: pathParamsSchema, keys: resolveKeys(pathParamsSchema) } : void 0, queryParams: queryParamsSchema ? { name: resolveName(transformers.pascalCase(`${operationId} QueryParams`)), operation, operationName, schema: queryParamsSchema, keys: resolveKeys(queryParamsSchema) || [] } : void 0, headerParams: headerParamsSchema ? { name: resolveName(transformers.pascalCase(`${operationId} HeaderParams`)), operation, operationName, schema: headerParamsSchema, keys: resolveKeys(headerParamsSchema) } : void 0, request: requestSchema ? { name: resolveName(transformers.pascalCase(`${operationId} ${method === "get" ? "queryRequest" : "mutationRequest"}`)), description: operation.schema.requestBody?.description, operation, operationName, schema: requestSchema, keys: resolveKeys(requestSchema), keysToOmit: resolveKeys(requestSchema)?.filter((key) => requestSchema.properties?.[key]?.readOnly) } : void 0, response: { name: resolveName(transformers.pascalCase(`${operationId} ${method === "get" ? "queryResponse" : "mutationResponse"}`)), operation, operationName, schema: { oneOf: successful.map((item) => ({ ...item.schema, $ref: item.name })) || void 0 } }, responses: successful, errors, statusCodes }; } async getOperations() { const { oas } = this.context; const paths = oas.getPaths(); return Object.entries(paths).flatMap( ([path2, methods]) => Object.entries(methods).map((values) => { const [method, operation] = values; if (this.#isExcluded(operation, method)) { return null; } if (this.context.include && !this.#isIncluded(operation, method)) { return null; } return operation ? { path: path2, method, operation } : null; }).filter(Boolean) ); } async build(...generators) { const operations = await this.getOperations(); const generatorLimit = pLimit(1); const operationLimit = pLimit(10); const writeTasks = generators.map( (generator) => generatorLimit(async () => { const operationTasks = operations.map( ({ operation, method }) => operationLimit(async () => { const options = this.#getOptions(operation, method); const result = await generator.operation?.({ instance: this, operation, options: { ...this.options, ...options } }); return result ?? []; }) ); const operationResults = await Promise.all(operationTasks); const opResultsFlat = operationResults.flat(); const operationsResult = await generator.operations?.({ instance: this, operations: operations.map((op) => op.operation), options: this.options }); return [...opResultsFlat, ...operationsResult ?? []]; }) ); const nestedResults = await Promise.all(writeTasks); return nestedResults.flat(); } }; var pluginOasName = "plugin-oas"; var pluginOas = createPlugin((options) => { const { output = { path: "schemas" }, group, validate = true, generators = [jsonGenerator], serverIndex, contentType, oasClass, discriminator = "strict" } = options; let oas; const getOas = async ({ config, logger }) => { oas = await parseFromConfig(config, oasClass); oas.setOptions({ contentType, discriminator }); try { if (validate) { await oas.valdiate(); } } catch (e) { const error = e; logger.emit("warning", error?.message); } return oas; }; return { name: pluginOasName, options: { output, validate, discriminator, ...options }, context() { const { config, logger } = this; return { getOas() { return getOas({ config, logger }); }, async getBaseURL() { const oasInstance = await this.getOas(); if (serverIndex) { return oasInstance.api.servers?.at(serverIndex)?.url; } return void 0; } }; }, resolvePath(baseName, pathMode, options2) { const root = path.resolve(this.config.root, this.config.output.path); const mode = pathMode ?? FileManager.getMode(path.resolve(root, output.path)); if (mode === "single") { return path.resolve(root, output.path); } if (group && (options2?.group?.path || options2?.group?.tag)) { const groupName = 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" ? options2.group.path : options2.group.tag }), baseName ); } return path.resolve(root, output.path, baseName); }, async buildStart() { if (!output) { return; } const oas2 = await getOas({ config: this.config, logger: this.logger }); await oas2.dereference(); const schemaGenerator = new SchemaGenerator( { unknownType: "unknown", emptySchemaType: "unknown", dateType: "date", transformers: {}, ...this.plugin.options }, { oas: oas2, pluginManager: this.pluginManager, plugin: this.plugin, contentType, include: void 0, override: void 0, mode: "split", output: output.path } ); const schemaFiles = await schemaGenerator.build(...generators); await this.addFile(...schemaFiles); const operationGenerator = new OperationGenerator(this.plugin.options, { oas: oas2, pluginManager: this.pluginManager, plugin: this.plugin, contentType, exclude: void 0, include: void 0, override: void 0, mode: "split" }); const operationFiles = await operationGenerator.build(...generators); await this.addFile(...operationFiles); } }; }); export { OperationGenerator, pluginOas, pluginOasName }; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map