trpc-to-openapi
Version:
121 lines • 6.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.mergePaths = exports.getOpenApiPathsObject = exports.HttpMethods = void 0;
const server_1 = require("@trpc/server");
const utils_1 = require("../utils");
const schema_1 = require("./schema");
var HttpMethods;
(function (HttpMethods) {
HttpMethods["GET"] = "get";
HttpMethods["POST"] = "post";
HttpMethods["PATCH"] = "patch";
HttpMethods["PUT"] = "put";
HttpMethods["DELETE"] = "delete";
})(HttpMethods || (exports.HttpMethods = HttpMethods = {}));
const getOpenApiPathsObject = (appRouter, securitySchemeNames, filter) => {
const pathsObject = {};
const procedures = Object.assign({}, appRouter._def.procedures);
(0, utils_1.forEachOpenApiProcedure)(procedures, ({ path: procedurePath, type, procedure, meta }) => {
var _a, _b, _c, _d;
if (typeof filter === 'function' && !filter({ metadata: meta })) {
return;
}
const procedureName = `${type}.${procedurePath}`;
try {
if (type === 'subscription') {
throw new server_1.TRPCError({
message: 'Subscriptions are not supported by OpenAPI v3',
code: 'INTERNAL_SERVER_ERROR',
});
}
const { openapi } = meta;
const { method, summary, description, tags, requestHeaders, responseHeaders, successDescription, errorResponses, protect = true, } = meta.openapi;
const path = (0, utils_1.normalizePath)(openapi.path);
const pathParameters = (0, utils_1.getPathParameters)(path);
const httpMethod = HttpMethods[method];
if (!httpMethod) {
throw new server_1.TRPCError({
message: 'Method must be GET, POST, PATCH, PUT or DELETE',
code: 'INTERNAL_SERVER_ERROR',
});
}
if ((_a = pathsObject[path]) === null || _a === void 0 ? void 0 : _a[httpMethod]) {
throw new server_1.TRPCError({
message: `Duplicate procedure defined for route ${method} ${path}`,
code: 'INTERNAL_SERVER_ERROR',
});
}
const contentTypes = (_b = openapi.contentTypes) !== null && _b !== void 0 ? _b : ['application/json'];
if (contentTypes.length === 0) {
throw new server_1.TRPCError({
message: 'At least one content type must be specified',
code: 'INTERNAL_SERVER_ERROR',
});
}
const { inputParser, outputParser } = (0, utils_1.getInputOutputParsers)(procedure);
if (!(0, utils_1.instanceofZodType)(inputParser)) {
throw new server_1.TRPCError({
message: 'Input parser expects a Zod validator',
code: 'INTERNAL_SERVER_ERROR',
});
}
if (!(0, utils_1.instanceofZodType)(outputParser)) {
throw new server_1.TRPCError({
message: 'Output parser expects a Zod validator',
code: 'INTERNAL_SERVER_ERROR',
});
}
const isInputRequired = !inputParser.safeParse(undefined).success;
const o = inputParser.meta();
const inputSchema = (0, utils_1.unwrapZodType)(inputParser, true).meta(Object.assign(Object.assign({}, ((o === null || o === void 0 ? void 0 : o.title) ? { title: o === null || o === void 0 ? void 0 : o.title } : {})), ((o === null || o === void 0 ? void 0 : o.description) ? { description: o === null || o === void 0 ? void 0 : o.description } : {})));
const requestData = {};
if (!(pathParameters.length === 0 && (0, utils_1.instanceofZodTypeLikeVoid)(inputSchema))) {
if (!(0, utils_1.instanceofZodTypeObject)(inputSchema)) {
throw new server_1.TRPCError({
message: 'Input parser must be a ZodObject',
code: 'INTERNAL_SERVER_ERROR',
});
}
if ((0, utils_1.acceptsRequestBody)(method)) {
requestData.requestBody = (0, schema_1.getRequestBodyObject)(inputSchema, isInputRequired, pathParameters, contentTypes);
requestData.requestParams =
(_c = (0, schema_1.getParameterObjects)(inputSchema, isInputRequired, pathParameters, requestHeaders, 'path')) !== null && _c !== void 0 ? _c : {};
}
else {
requestData.requestParams =
(_d = (0, schema_1.getParameterObjects)(inputSchema, isInputRequired, pathParameters, requestHeaders, 'all')) !== null && _d !== void 0 ? _d : {};
}
}
const responses = (0, schema_1.getResponsesObject)(outputParser, httpMethod, responseHeaders, protect, (0, schema_1.hasInputs)(inputParser), successDescription, errorResponses);
const security = protect ? securitySchemeNames.map((name) => ({ [name]: [] })) : undefined;
pathsObject[path] = Object.assign(Object.assign({}, pathsObject[path]), { [httpMethod]: Object.assign(Object.assign(Object.assign({ operationId: procedurePath.replace(/\./g, '-'), summary,
description,
tags,
security }, requestData), { responses }), (openapi.deprecated ? { deprecated: openapi.deprecated } : {})) });
}
catch (error) {
if (error instanceof server_1.TRPCError) {
error.message = `[${procedureName}] - ${error.message}`;
}
throw error;
}
});
return pathsObject;
};
exports.getOpenApiPathsObject = getOpenApiPathsObject;
const mergePaths = (x, y) => {
if (x === undefined)
return y;
if (y === undefined)
return x;
const obj = x;
for (const [k, v] of Object.entries(y)) {
if (k in obj)
obj[k] = Object.assign(Object.assign({}, obj[k]), v);
else
obj[k] = v;
}
return obj;
};
exports.mergePaths = mergePaths;
//# sourceMappingURL=paths.js.map