typescript-rest-swagger
Version:
Generate Swagger files from a typescript-rest project
178 lines • 9.35 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.MethodGenerator = void 0;
var pathUtil = require("path");
var decoratorUtils_1 = require("../utils/decoratorUtils");
var jsDocUtils_1 = require("../utils/jsDocUtils");
var pathUtils_1 = require("../utils/pathUtils");
var endpointGenerator_1 = require("./endpointGenerator");
var parameterGenerator_1 = require("./parameterGenerator");
var resolveType_1 = require("./resolveType");
var MethodGenerator = /** @class */ (function (_super) {
__extends(MethodGenerator, _super);
function MethodGenerator(node, controllerPath, genericTypeMap) {
var _this = _super.call(this, node, 'methods') || this;
_this.controllerPath = controllerPath;
_this.genericTypeMap = genericTypeMap;
_this.processMethodDecorators();
return _this;
}
MethodGenerator.prototype.isValid = function () {
return !!this.method;
};
MethodGenerator.prototype.getMethodName = function () {
var identifier = this.node.name;
return identifier.text;
};
MethodGenerator.prototype.generate = function () {
if (!this.isValid()) {
throw new Error('This isn\'t a valid controller method.');
}
this.debugger('Generating Metadata for method %s', this.getCurrentLocation());
var identifier = this.node.name;
var type = resolveType_1.resolveType(this.node.type, this.genericTypeMap);
var responses = this.mergeResponses(this.getResponses(this.genericTypeMap), this.getMethodSuccessResponse(type));
var methodMetadata = {
consumes: this.getDecoratorValues('Consumes'),
deprecated: jsDocUtils_1.isExistJSDocTag(this.node, 'deprecated'),
description: jsDocUtils_1.getJSDocDescription(this.node),
method: this.method,
name: identifier.text,
parameters: this.buildParameters(),
path: this.path,
produces: (this.getDecoratorValues('Produces') ? this.getDecoratorValues('Produces') : this.getDecoratorValues('Accept')),
responses: responses,
security: this.getSecurity(),
summary: jsDocUtils_1.getJSDocTag(this.node, 'summary'),
tags: this.getDecoratorValues('Tags'),
type: type
};
this.debugger('Generated Metadata for method %s: %j', this.getCurrentLocation(), methodMetadata);
return methodMetadata;
};
MethodGenerator.prototype.getCurrentLocation = function () {
var methodId = this.node.name;
var controllerId = this.node.parent.name;
return controllerId.text + "." + methodId.text;
};
MethodGenerator.prototype.buildParameters = function () {
var _this = this;
this.debugger('Processing method %s parameters.', this.getCurrentLocation());
var parameters = this.node.parameters.map(function (p) {
try {
var path = pathUtil.posix.join('/', (_this.controllerPath ? _this.controllerPath : ''), _this.path);
return new parameterGenerator_1.ParameterGenerator(p, _this.method, path, _this.genericTypeMap).generate();
}
catch (e) {
var methodId = _this.node.name;
var controllerId = _this.node.parent.name;
var parameterId = p.name;
throw new Error("Error generate parameter method: '" + controllerId.text + "." + methodId.text + "' argument: " + parameterId.text + " " + e);
}
}).filter(function (p) { return (p.in !== 'context') && (p.in !== 'cookie'); });
var bodyParameters = parameters.filter(function (p) { return p.in === 'body'; });
var formParameters = parameters.filter(function (p) { return p.in === 'formData'; });
if (bodyParameters.length > 1) {
throw new Error("Only one body parameter allowed in '" + this.getCurrentLocation() + "' method.");
}
if (bodyParameters.length > 0 && formParameters.length > 0) {
throw new Error("Choose either during @FormParam and @FileParam or body parameter in '" + this.getCurrentLocation() + "' method.");
}
this.debugger('Parameters list for method %s: %j.', this.getCurrentLocation(), parameters);
return parameters;
};
MethodGenerator.prototype.processMethodDecorators = function () {
var _this = this;
var httpMethodDecorators = decoratorUtils_1.getDecorators(this.node, function (decorator) { return _this.supportsPathMethod(decorator.text); });
if (!httpMethodDecorators || !httpMethodDecorators.length) {
return;
}
if (httpMethodDecorators.length > 1) {
throw new Error("Only one HTTP Method decorator in '" + this.getCurrentLocation + "' method is acceptable, Found: " + httpMethodDecorators.map(function (d) { return d.text; }).join(', '));
}
var methodDecorator = httpMethodDecorators[0];
this.method = methodDecorator.text.toLowerCase();
this.debugger('Processing method %s decorators.', this.getCurrentLocation());
var pathDecorators = decoratorUtils_1.getDecorators(this.node, function (decorator) { return decorator.text === 'Path'; });
if (pathDecorators && pathDecorators.length > 1) {
throw new Error("Only one Path decorator in '" + this.getCurrentLocation + "' method is acceptable, Found: " + httpMethodDecorators.map(function (d) { return d.text; }).join(', '));
}
if (pathDecorators) {
var pathDecorator = pathDecorators[0];
this.path = pathDecorator ? "/" + pathUtils_1.normalizePath(pathDecorator.arguments[0]) : '';
}
else {
this.path = '';
}
this.debugger('Mapping endpoint %s %s', this.method, this.path);
};
MethodGenerator.prototype.getMethodSuccessResponse = function (type) {
var responseData = this.getMethodSuccessResponseData(type);
return {
description: type.typeName === 'void' ? 'No content' : 'Ok',
examples: this.getMethodSuccessExamples(),
schema: responseData.type,
status: responseData.status
};
};
MethodGenerator.prototype.getMethodSuccessResponseData = function (type) {
switch (type.typeName) {
case 'void': return { status: '204', type: type };
case 'NewResource': return { status: '201', type: type.typeArgument || type };
case 'RequestAccepted': return { status: '202', type: type.typeArgument || type };
case 'MovedPermanently': return { status: '301', type: type.typeArgument || type };
case 'MovedTemporarily': return { status: '302', type: type.typeArgument || type };
case 'DownloadResource':
case 'DownloadBinaryData': return { status: '200', type: { typeName: 'buffer' } };
default: return { status: '200', type: type };
}
};
MethodGenerator.prototype.getMethodSuccessExamples = function () {
var exampleDecorators = decoratorUtils_1.getDecorators(this.node, function (decorator) { return decorator.text === 'Example'; });
if (!exampleDecorators || !exampleDecorators.length) {
return undefined;
}
if (exampleDecorators.length > 1) {
throw new Error("Only one Example decorator allowed in '" + this.getCurrentLocation + "' method.");
}
var d = exampleDecorators[0];
var argument = d.arguments[0];
return this.getExamplesValue(argument);
};
MethodGenerator.prototype.mergeResponses = function (responses, defaultResponse) {
if (!responses || !responses.length) {
return [defaultResponse];
}
var index = responses.findIndex(function (resp) { return resp.status === defaultResponse.status; });
if (index >= 0) {
if (defaultResponse.examples && !responses[index].examples) {
responses[index].examples = defaultResponse.examples;
}
}
else {
responses.push(defaultResponse);
}
return responses;
};
MethodGenerator.prototype.supportsPathMethod = function (method) {
return ['GET', 'POST', 'PATCH', 'DELETE', 'PUT', 'OPTIONS', 'HEAD'].some(function (m) { return m === method; });
};
return MethodGenerator;
}(endpointGenerator_1.EndpointGenerator));
exports.MethodGenerator = MethodGenerator;
//# sourceMappingURL=methodGenerator.js.map