@namecheap/tsoa-cli
Version:
Build swagger-compliant REST APIs using TypeScript and Node
126 lines • 5.93 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ControllerGenerator = void 0;
const decoratorUtils_1 = require("./../utils/decoratorUtils");
const exceptions_1 = require("./exceptions");
const methodGenerator_1 = require("./methodGenerator");
const typeResolver_1 = require("./typeResolver");
const headerTypeHelpers_1 = require("../utils/headerTypeHelpers");
const typescript_1 = require("typescript");
class ControllerGenerator {
constructor(node, current, parentSecurity = []) {
this.node = node;
this.current = current;
this.parentSecurity = parentSecurity;
this.path = this.getPath();
this.tags = this.getTags();
this.security = this.getSecurity();
this.isHidden = this.getIsHidden();
this.commonResponses = this.getCommonResponses();
this.produces = this.getProduces();
}
IsValid() {
return !!this.path || this.path === '';
}
Generate() {
if (!this.node.parent) {
throw new exceptions_1.GenerateMetadataError("Controller node doesn't have a valid parent source file.");
}
if (!this.node.name) {
throw new exceptions_1.GenerateMetadataError("Controller node doesn't have a valid name.");
}
const sourceFile = this.node.parent.getSourceFile();
return {
location: sourceFile.fileName,
methods: this.buildMethods(),
name: this.node.name.text,
path: this.path || '',
produces: this.produces,
};
}
buildMethods() {
return this.node.members
.filter(typescript_1.isMethodDeclaration)
.map(m => new methodGenerator_1.MethodGenerator(m, this.current, this.commonResponses, this.path, this.tags, this.security, this.isHidden))
.filter(generator => generator.IsValid())
.map(generator => generator.Generate());
}
getPath() {
const decorators = (0, decoratorUtils_1.getDecorators)(this.node, identifier => identifier.text === 'Route');
if (!decorators || !decorators.length) {
return;
}
if (decorators.length > 1) {
throw new exceptions_1.GenerateMetadataError(`Only one Route decorator allowed in '${this.node.name.text}' class.`);
}
const decorator = decorators[0];
const expression = decorator.parent;
const decoratorArgument = expression.arguments[0];
return decoratorArgument ? `${decoratorArgument.text}` : '';
}
getCommonResponses() {
const decorators = (0, decoratorUtils_1.getDecorators)(this.node, identifier => identifier.text === 'Response');
if (!decorators || !decorators.length) {
return [];
}
return decorators.map(decorator => {
const expression = decorator.parent;
const [name, description, example] = (0, decoratorUtils_1.getDecoratorValues)(decorator, this.current.typeChecker);
if (!name) {
throw new exceptions_1.GenerateMetadataError(`Controller's responses should have an explicit name.`);
}
return {
description: description || '',
examples: example === undefined ? undefined : [example],
name,
schema: expression.typeArguments && expression.typeArguments.length > 0 && !this.isHidden ? new typeResolver_1.TypeResolver(expression.typeArguments[0], this.current).resolve() : undefined,
headers: (0, headerTypeHelpers_1.getHeaderType)(expression.typeArguments, 1, this.current),
};
});
}
getTags() {
const decorators = (0, decoratorUtils_1.getDecorators)(this.node, identifier => identifier.text === 'Tags');
if (!decorators || !decorators.length) {
return;
}
if (decorators.length > 1) {
throw new exceptions_1.GenerateMetadataError(`Only one Tags decorator allowed in '${this.node.name.text}' class.`);
}
const decorator = decorators[0];
const expression = decorator.parent;
return expression.arguments.map((a) => a.text);
}
getSecurity() {
if (this.current.securityGenerator) {
return this.current.securityGenerator(this.node, this.current.typeChecker);
}
const noSecurityDecorators = (0, decoratorUtils_1.getDecorators)(this.node, identifier => identifier.text === 'NoSecurity');
const securityDecorators = (0, decoratorUtils_1.getDecorators)(this.node, identifier => identifier.text === 'Security');
if (noSecurityDecorators?.length && securityDecorators?.length) {
throw new exceptions_1.GenerateMetadataError(`NoSecurity decorator cannot be used in conjunction with Security decorator in '${this.node.name.text}' class.`);
}
if (noSecurityDecorators?.length) {
return [];
}
if (!securityDecorators || !securityDecorators.length) {
return this.parentSecurity;
}
return securityDecorators.map(d => (0, decoratorUtils_1.getSecurites)(d, this.current.typeChecker));
}
getIsHidden() {
const hiddenDecorators = (0, decoratorUtils_1.getDecorators)(this.node, identifier => identifier.text === 'Hidden');
if (!hiddenDecorators || !hiddenDecorators.length) {
return false;
}
if (hiddenDecorators.length > 1) {
throw new exceptions_1.GenerateMetadataError(`Only one Hidden decorator allowed in '${this.node.name.text}' class.`);
}
return true;
}
getProduces() {
const produces = (0, decoratorUtils_1.getProduces)(this.node, this.current.typeChecker);
return produces.length ? produces : undefined;
}
}
exports.ControllerGenerator = ControllerGenerator;
//# sourceMappingURL=controllerGenerator.js.map