UNPKG

routing-controllers-openapi

Version:

Runtime OpenAPI v3 spec generation for routing-controllers

273 lines 23.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.expressToOpenAPIPath = exports.getTags = exports.getSummary = exports.getSpec = exports.getResponses = exports.getStatusCode = exports.getContentType = exports.getRequestBody = exports.getQueryParams = exports.getPathParams = exports.getHeaderParams = exports.getPaths = exports.getOperationId = exports.getOperation = exports.getFullPath = exports.getFullExpressPath = void 0; const tslib_1 = require("tslib"); const lodash_merge_1 = tslib_1.__importDefault(require("lodash.merge")); const lodash_capitalize_1 = tslib_1.__importDefault(require("lodash.capitalize")); const lodash_startcase_1 = tslib_1.__importDefault(require("lodash.startcase")); const oa = tslib_1.__importStar(require("openapi3-ts")); const pathToRegexp = tslib_1.__importStar(require("path-to-regexp")); require("reflect-metadata"); const decorators_1 = require("./decorators"); function getFullExpressPath(route) { const { action, controller, options } = route; return ((options.routePrefix || '') + (controller.route || '') + (action.route || '')); } exports.getFullExpressPath = getFullExpressPath; function getFullPath(route) { return expressToOpenAPIPath(getFullExpressPath(route)); } exports.getFullPath = getFullPath; function getOperation(route, schemas) { const operation = { operationId: getOperationId(route), parameters: [ ...getHeaderParams(route), ...getPathParams(route), ...getQueryParams(route, schemas), ], requestBody: getRequestBody(route) || undefined, responses: getResponses(route), summary: getSummary(route), tags: getTags(route), }; const cleanedOperation = Object.entries(operation) .filter(([_, value]) => value && (value.length || Object.keys(value).length)) .reduce((acc, [key, value]) => { acc[key] = value; return acc; }, {}); return (0, decorators_1.applyOpenAPIDecorator)(cleanedOperation, route); } exports.getOperation = getOperation; function getOperationId(route) { return `${route.action.target.name}.${route.action.method}`; } exports.getOperationId = getOperationId; function getPaths(routes, schemas) { const routePaths = routes.map((route) => ({ [getFullPath(route)]: { [route.action.type]: getOperation(route, schemas), }, })); return (0, lodash_merge_1.default)(...routePaths); } exports.getPaths = getPaths; function getHeaderParams(route) { const headers = route.params .filter((p) => p.type === 'header') .map((headerMeta) => { const schema = getParamSchema(headerMeta); return { in: 'header', name: headerMeta.name || '', required: isRequired(headerMeta, route), schema, }; }); const headersMeta = route.params.find((p) => p.type === 'headers'); if (headersMeta) { const schema = getParamSchema(headersMeta); headers.push({ in: 'header', name: schema.$ref.split('/').pop() || '', required: isRequired(headersMeta, route), schema, }); } return headers; } exports.getHeaderParams = getHeaderParams; function getPathParams(route) { const path = getFullExpressPath(route); const tokens = pathToRegexp.parse(path); return tokens .filter((token) => token && typeof token === 'object') .map((token) => { const name = token.name + ''; const param = { in: 'path', name, required: token.modifier !== '?', schema: { type: 'string' }, }; if (token.pattern && token.pattern !== '[^\\/]+?') { param.schema = { pattern: token.pattern, type: 'string' }; } const meta = route.params.find((p) => p.name === name && p.type === 'param'); if (meta) { const metaSchema = getParamSchema(meta); param.schema = 'type' in metaSchema ? Object.assign(Object.assign({}, param.schema), metaSchema) : metaSchema; } return param; }); } exports.getPathParams = getPathParams; function getQueryParams(route, schemas) { var _a; const queries = route.params .filter((p) => p.type === 'query') .map((queryMeta) => { const schema = getParamSchema(queryMeta); return { in: 'query', name: queryMeta.name || '', required: isRequired(queryMeta, route), schema, }; }); const queriesMeta = route.params.find((p) => p.type === 'queries'); if (queriesMeta) { const paramSchema = getParamSchema(queriesMeta); const paramSchemaName = paramSchema.$ref.split('/').pop() || ''; const currentSchema = schemas[paramSchemaName]; if (oa.isSchemaObject(currentSchema)) { for (const [name, schema] of Object.entries((currentSchema === null || currentSchema === void 0 ? void 0 : currentSchema.properties) || {})) { queries.push({ in: 'query', name, required: (_a = currentSchema.required) === null || _a === void 0 ? void 0 : _a.includes(name), schema, }); } } } return queries; } exports.getQueryParams = getQueryParams; function getNamedParamSchema(param) { const { type } = param; if (type === 'file') { return { type: 'string', format: 'binary' }; } if (type === 'files') { return { type: 'array', items: { type: 'string', format: 'binary', }, }; } return getParamSchema(param); } function getRequestBody(route) { const bodyParamMetas = route.params.filter((d) => d.type === 'body-param'); const uploadFileMetas = route.params.filter((d) => ['file', 'files'].includes(d.type)); const namedParamMetas = [...bodyParamMetas, ...uploadFileMetas]; const namedParamsSchema = namedParamMetas.length > 0 ? namedParamMetas.reduce((acc, d) => (Object.assign(Object.assign({}, acc), { properties: Object.assign(Object.assign({}, acc.properties), { [d.name]: getNamedParamSchema(d) }), required: isRequired(d, route) ? [...(acc.required || []), d.name] : acc.required })), { properties: {}, required: [], type: 'object' }) : null; const contentType = uploadFileMetas.length > 0 ? 'multipart/form-data' : 'application/json'; const bodyMeta = route.params.find((d) => d.type === 'body'); if (bodyMeta) { const bodySchema = getParamSchema(bodyMeta); const items = 'items' in bodySchema && bodySchema.items ? bodySchema.items : bodySchema; const $ref = oa.isReferenceObject(items) ? items.$ref : ''; return { content: { [contentType]: { schema: namedParamsSchema ? { allOf: [bodySchema, namedParamsSchema] } : bodySchema, }, }, description: ($ref || '').split('/').pop(), required: isRequired(bodyMeta, route), }; } else if (namedParamsSchema) { return { content: { [contentType]: { schema: namedParamsSchema } }, }; } } exports.getRequestBody = getRequestBody; function getContentType(route) { const defaultContentType = route.controller.type === 'json' ? 'application/json' : 'text/html; charset=utf-8'; const contentMeta = route.responseHandlers.find((h) => h.type === 'content-type'); return contentMeta ? contentMeta.value : defaultContentType; } exports.getContentType = getContentType; function getStatusCode(route) { const successMeta = route.responseHandlers.find((h) => h.type === 'success-code'); return successMeta ? successMeta.value + '' : '200'; } exports.getStatusCode = getStatusCode; function getResponses(route) { const contentType = getContentType(route); const successStatus = getStatusCode(route); return { [successStatus]: { content: { [contentType]: {} }, description: 'Successful response', }, }; } exports.getResponses = getResponses; function getSpec(routes, schemas) { return { components: { schemas: {} }, info: { title: '', version: '1.0.0' }, openapi: '3.0.0', paths: getPaths(routes, schemas), }; } exports.getSpec = getSpec; function getSummary(route) { return (0, lodash_capitalize_1.default)((0, lodash_startcase_1.default)(route.action.method)); } exports.getSummary = getSummary; function getTags(route) { return [(0, lodash_startcase_1.default)(route.controller.target.name.replace(/Controller$/, ''))]; } exports.getTags = getTags; function expressToOpenAPIPath(expressPath) { const tokens = pathToRegexp.parse(expressPath); return tokens .map((d) => (typeof d === 'string' ? d : `${d.prefix}{${d.name}}`)) .join(''); } exports.expressToOpenAPIPath = expressToOpenAPIPath; function isRequired(meta, route) { var _a, _b, _c; const globalRequired = (_c = (_b = (_a = route.options) === null || _a === void 0 ? void 0 : _a.defaults) === null || _b === void 0 ? void 0 : _b.paramOptions) === null || _c === void 0 ? void 0 : _c.required; return globalRequired ? meta.required !== false : !!meta.required; } function getParamSchema(param) { const { explicitType, index, object, method } = param; const type = Reflect.getMetadata('design:paramtypes', object, method)[index]; if (typeof type === 'function' && type.name === 'Array') { const items = explicitType ? { $ref: '#/components/schemas/' + explicitType.name } : { type: 'object' }; return { items, type: 'array' }; } if (explicitType) { return { $ref: '#/components/schemas/' + explicitType.name }; } if (typeof type === 'function') { if (type.prototype === String.prototype || type.prototype === Symbol.prototype) { return { type: 'string' }; } else if (type.prototype === Number.prototype) { return { type: 'number' }; } else if (type.prototype === Boolean.prototype) { return { type: 'boolean' }; } else if (type.name !== 'Object') { return { $ref: '#/components/schemas/' + type.name }; } } return {}; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVTcGVjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2dlbmVyYXRlU3BlYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQ0Esd0VBQWlDO0FBQ2pDLGtGQUEyQztBQUMzQyxnRkFBeUM7QUFDekMsd0RBQWlDO0FBQ2pDLHFFQUE4QztBQUM5Qyw0QkFBeUI7QUFHekIsNkNBQW9EO0FBSXBELFNBQWdCLGtCQUFrQixDQUFDLEtBQWE7SUFDOUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLEdBQUcsS0FBSyxDQUFBO0lBQzdDLE9BQU8sQ0FDTCxDQUFDLE9BQU8sQ0FBQyxXQUFXLElBQUksRUFBRSxDQUFDO1FBQzNCLENBQUMsVUFBVSxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUM7UUFDeEIsQ0FBQyxNQUFNLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUNyQixDQUFBO0FBQ0gsQ0FBQztBQVBELGdEQU9DO0FBS0QsU0FBZ0IsV0FBVyxDQUFDLEtBQWE7SUFDdkMsT0FBTyxvQkFBb0IsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFBO0FBQ3hELENBQUM7QUFGRCxrQ0FFQztBQUtELFNBQWdCLFlBQVksQ0FDMUIsS0FBYSxFQUNiLE9BQThEO0lBRTlELE1BQU0sU0FBUyxHQUF1QjtRQUNwQyxXQUFXLEVBQUUsY0FBYyxDQUFDLEtBQUssQ0FBQztRQUNsQyxVQUFVLEVBQUU7WUFDVixHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUM7WUFDekIsR0FBRyxhQUFhLENBQUMsS0FBSyxDQUFDO1lBQ3ZCLEdBQUcsY0FBYyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUM7U0FDbEM7UUFDRCxXQUFXLEVBQUUsY0FBYyxDQUFDLEtBQUssQ0FBQyxJQUFJLFNBQVM7UUFDL0MsU0FBUyxFQUFFLFlBQVksQ0FBQyxLQUFLLENBQUM7UUFDOUIsT0FBTyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENB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