UNPKG

@trapi/metadata

Version:

Generate REST-API metadata scheme from TypeScript Decorators.

188 lines 7.84 kB
"use strict"; /* * Copyright (c) 2021-2023. * Author Peter Placzek (tada5hi) * For the full copyright and license information, * view the LICENSE file that was distributed with this source code. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MethodGenerator = void 0; const node_path_1 = __importDefault(require("node:path")); const typescript_1 = require("typescript"); const decorator_1 = require("../../decorator"); const resolver_1 = require("../../resolver"); const utils_1 = require("../../utils"); const abstract_1 = require("../abstract"); const parameter_1 = require("../parameter"); class MethodGenerator extends abstract_1.AbstractGenerator { // -------------------------------------------------------------------- constructor(node, current) { super(node, current); this.determineVerb(); } // -------------------------------------------------------------------- isValid() { return typeof this.method !== 'undefined'; } getMethodName() { const identifier = this.node.name; return identifier.text; } generate(controllerPath) { let nodeType = this.node.type; if (!nodeType) { const { typeChecker } = this.current; const signature = typeChecker.getSignatureFromDeclaration(this.node); const implicitType = typeChecker.getReturnTypeOfSignature(signature); nodeType = typeChecker.typeToTypeNode(implicitType, undefined, typescript_1.NodeBuilderFlags.NoTruncation); } const type = new resolver_1.TypeNodeResolver(nodeType, this.current).resolve(); const responses = this.mergeResponses(this.buildResponses(), this.buildResponse(type)); const methodPath = this.buildPath(); return { consumes: this.getConsumes(), deprecated: this.isDeprecated(this.node), description: (0, utils_1.getJSDocDescription)(this.node), extensions: (0, resolver_1.getNodeExtensions)(this.node, this.current.decoratorResolver), hidden: this.isHidden(this.node), method: this.method, name: this.node.name.text, path: methodPath, produces: this.getProduces(), responses, security: this.getSecurity(), summary: (0, utils_1.getJSDocTagComment)(this.node, utils_1.JSDocTagName.SUMMARY), tags: this.getTags(), type, parameters: this.buildParameters(controllerPath, methodPath), }; } getCurrentLocation() { const methodId = this.node.name; const controllerId = this.node.parent.name; return `${controllerId.text}.${methodId.text}`; } buildParameters(controllerPath, methodPath) { const controllerId = this.node.parent.name; const methodId = this.node.name; const fullPath = node_path_1.default.posix.join('/', controllerPath, methodPath); const output = []; let bodyParameterCount = 0; let formParameterCount = 0; for (let i = 0; i < this.node.parameters.length; i++) { try { const generator = new parameter_1.ParameterGenerator(this.node.parameters[i], this.method, fullPath, this.current); const parameters = generator.generate(); for (let j = 0; j < parameters.length; j++) { if (parameters[j].in === parameter_1.ParameterSource.BODY) { bodyParameterCount++; } if (parameters[j].in === parameter_1.ParameterSource.FORM_DATA) { formParameterCount++; } if (parameters[j].in !== parameter_1.ParameterSource.CONTEXT) { output.push(parameters[j]); } } } catch (e) { const parameterId = this.node.parameters[i].name; throw new Error(`Parameter generation: '${controllerId.text}.${methodId.text}' argument: ${parameterId.text} ${e}`); } } if (bodyParameterCount > 1) { throw new Error(`Only one body parameter allowed in '${this.getCurrentLocation()}' method.`); } if (bodyParameterCount > 0 && formParameterCount > 0) { throw new Error(`Choose either form-, file- or body-parameter in '${this.getCurrentLocation()}' method.`); } return output; } determineVerb() { const methods = [ decorator_1.DecoratorID.ALL, decorator_1.DecoratorID.DELETE, decorator_1.DecoratorID.GET, decorator_1.DecoratorID.HEAD, decorator_1.DecoratorID.OPTIONS, decorator_1.DecoratorID.PATCH, decorator_1.DecoratorID.POST, decorator_1.DecoratorID.PUT, ]; const decorators = (0, utils_1.getNodeDecorators)(this.node); let method; for (let i = 0; i < methods.length; i++) { const representationManager = this.current.decoratorResolver.match(methods[i], decorators); if (representationManager) { method = methods[i]; break; } } if (typeof method === 'undefined') { return; } this.method = method.toLowerCase(); } buildResponse(type) { type = this.guessResponseType(type); return { description: (0, resolver_1.isVoidType)(type) ? 'No content' : 'Ok', examples: this.getResponseExamples(), schema: type, status: (0, resolver_1.isVoidType)(type) ? '204' : '200', name: (0, resolver_1.isVoidType)(type) ? '204' : '200', }; } guessResponseType(type) { if (!(0, resolver_1.isVoidType)(type)) { return type; } const representation = this.current.decoratorResolver.match(decorator_1.DecoratorID.EXAMPLE, this.node); if (typeof representation === 'undefined') { return type; } const value = representation.get('type'); if (typeof value !== 'undefined' && (0, utils_1.hasOwnProperty)(value, 'kind') && (0, typescript_1.isTypeNode)(value)) { type = new resolver_1.TypeNodeResolver(value, this.current).resolve(); } return type; } getResponseExamples() { const representation = this.current.decoratorResolver.match(decorator_1.DecoratorID.EXAMPLE, this.node); if (typeof representation === 'undefined') { return []; } const output = []; for (let i = 0; i < representation.decorators.length; i++) { const value = representation.get('payload'); const label = representation.get('label'); if (typeof value !== 'undefined') { output.push({ value, label }); } } return output; } mergeResponses(responses, exampleResponse) { if (!responses || !responses.length) { return [exampleResponse]; } const index = responses.findIndex((resp) => resp.status === exampleResponse.status); if (index >= 0) { if (exampleResponse.examples && (!responses[index].examples || !responses[index].examples.length)) { responses[index].examples = exampleResponse.examples; } } else { responses.push(exampleResponse); } return responses; } } exports.MethodGenerator = MethodGenerator; //# sourceMappingURL=module.js.map