UNPKG

8.21 kBJavaScriptView Raw
1"use strict";
2var _a;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.ControllerClassVisitor = void 0;
5const lodash_1 = require("lodash");
6const ts = require("typescript");
7const decorators_1 = require("../../decorators");
8const plugin_constants_1 = require("../plugin-constants");
9const ast_utils_1 = require("../utils/ast-utils");
10const plugin_utils_1 = require("../utils/plugin-utils");
11const abstract_visitor_1 = require("./abstract.visitor");
12const [tsVersionMajor, tsVersionMinor] = (_a = ts.versionMajorMinor) === null || _a === void 0 ? void 0 : _a.split('.').map((x) => +x);
13const isInUpdatedAstContext = tsVersionMinor >= 8 || tsVersionMajor > 4;
14class ControllerClassVisitor extends abstract_visitor_1.AbstractFileVisitor {
15 visit(sourceFile, ctx, program, options) {
16 const typeChecker = program.getTypeChecker();
17 sourceFile = this.updateImports(sourceFile, ctx.factory, program);
18 const visitNode = (node) => {
19 if (ts.isMethodDeclaration(node)) {
20 try {
21 return this.addDecoratorToNode(ctx.factory, node, typeChecker, options, sourceFile.fileName, sourceFile);
22 }
23 catch (_a) {
24 return node;
25 }
26 }
27 return ts.visitEachChild(node, visitNode, ctx);
28 };
29 return ts.visitNode(sourceFile, visitNode);
30 }
31 addDecoratorToNode(factory, compilerNode, typeChecker, options, hostFilename, sourceFile) {
32 var _a;
33 const decorators = ts.canHaveDecorators
34 ? ts.getDecorators(compilerNode)
35 : compilerNode.decorators;
36 if (!decorators) {
37 return compilerNode;
38 }
39 const apiOperationDecoratorsArray = this.createApiOperationDecorator(factory, compilerNode, decorators, options, sourceFile, typeChecker);
40 const removeExistingApiOperationDecorator = apiOperationDecoratorsArray.length > 0;
41 const existingDecorators = removeExistingApiOperationDecorator
42 ? decorators.filter((item) => (0, ast_utils_1.getDecoratorName)(item) !== decorators_1.ApiOperation.name)
43 : decorators;
44 const modifiers = (_a = (isInUpdatedAstContext
45 ? ts.getModifiers(compilerNode)
46 : compilerNode.modifiers)) !== null && _a !== void 0 ? _a : [];
47 const updatedDecorators = [
48 ...apiOperationDecoratorsArray,
49 ...existingDecorators,
50 factory.createDecorator(factory.createCallExpression(factory.createIdentifier(`${plugin_constants_1.OPENAPI_NAMESPACE}.${decorators_1.ApiResponse.name}`), undefined, [
51 this.createDecoratorObjectLiteralExpr(factory, compilerNode, typeChecker, factory.createNodeArray(), hostFilename)
52 ]))
53 ];
54 return isInUpdatedAstContext
55 ? factory.updateMethodDeclaration(compilerNode, [...updatedDecorators, ...modifiers], compilerNode.asteriskToken, compilerNode.name, compilerNode.questionToken, compilerNode.typeParameters, compilerNode.parameters, compilerNode.type, compilerNode.body)
56 : factory.updateMethodDeclaration(compilerNode, updatedDecorators, modifiers, compilerNode.asteriskToken, compilerNode.name, compilerNode.questionToken, compilerNode.typeParameters, compilerNode.parameters, compilerNode.type, compilerNode.body);
57 }
58 createApiOperationDecorator(factory, node, nodeArray, options, sourceFile, typeChecker) {
59 if (!options.introspectComments) {
60 return [];
61 }
62 const keyToGenerate = options.controllerKeyOfComment;
63 const apiOperationDecorator = (0, plugin_utils_1.getDecoratorOrUndefinedByNames)([decorators_1.ApiOperation.name], nodeArray, factory);
64 const apiOperationExpr = apiOperationDecorator &&
65 (0, lodash_1.head)((0, ast_utils_1.getDecoratorArguments)(apiOperationDecorator));
66 const apiOperationExprProperties = apiOperationExpr &&
67 apiOperationExpr.properties;
68 const extractedComments = (0, ast_utils_1.getMainCommentOfNode)(node, sourceFile);
69 const tags = (0, ast_utils_1.getTsDocTagsOfNode)(node, sourceFile, typeChecker);
70 const properties = [
71 factory.createPropertyAssignment(keyToGenerate, factory.createStringLiteral(extractedComments)),
72 ...(apiOperationExprProperties !== null && apiOperationExprProperties !== void 0 ? apiOperationExprProperties : factory.createNodeArray())
73 ];
74 const hasDeprecatedKey = (0, plugin_utils_1.hasPropertyKey)('deprecated', factory.createNodeArray(apiOperationExprProperties));
75 if (!hasDeprecatedKey && tags.deprecated) {
76 const deprecatedPropertyAssignment = factory.createPropertyAssignment('deprecated', (0, ast_utils_1.createLiteralFromAnyValue)(factory, tags.deprecated));
77 properties.push(deprecatedPropertyAssignment);
78 }
79 const apiOperationDecoratorArguments = factory.createNodeArray([
80 factory.createObjectLiteralExpression((0, lodash_1.compact)(properties))
81 ]);
82 if (apiOperationDecorator) {
83 const expr = apiOperationDecorator.expression;
84 const updatedCallExpr = factory.updateCallExpression(expr, expr.expression, undefined, apiOperationDecoratorArguments);
85 return [factory.updateDecorator(apiOperationDecorator, updatedCallExpr)];
86 }
87 else {
88 return [
89 factory.createDecorator(factory.createCallExpression(factory.createIdentifier(`${plugin_constants_1.OPENAPI_NAMESPACE}.${decorators_1.ApiOperation.name}`), undefined, apiOperationDecoratorArguments))
90 ];
91 }
92 }
93 createDecoratorObjectLiteralExpr(factory, node, typeChecker, existingProperties = factory.createNodeArray(), hostFilename) {
94 const properties = [
95 ...existingProperties,
96 this.createStatusPropertyAssignment(factory, node, existingProperties),
97 this.createTypePropertyAssignment(factory, node, typeChecker, existingProperties, hostFilename)
98 ];
99 return factory.createObjectLiteralExpression((0, lodash_1.compact)(properties));
100 }
101 createTypePropertyAssignment(factory, node, typeChecker, existingProperties, hostFilename) {
102 if ((0, plugin_utils_1.hasPropertyKey)('type', existingProperties)) {
103 return undefined;
104 }
105 const signature = typeChecker.getSignatureFromDeclaration(node);
106 const type = typeChecker.getReturnTypeOfSignature(signature);
107 if (!type) {
108 return undefined;
109 }
110 let typeReference = (0, plugin_utils_1.getTypeReferenceAsString)(type, typeChecker);
111 if (!typeReference) {
112 return undefined;
113 }
114 if (typeReference.includes('node_modules')) {
115 return undefined;
116 }
117 typeReference = (0, plugin_utils_1.replaceImportPath)(typeReference, hostFilename);
118 return factory.createPropertyAssignment('type', factory.createIdentifier(typeReference));
119 }
120 createStatusPropertyAssignment(factory, node, existingProperties) {
121 if ((0, plugin_utils_1.hasPropertyKey)('status', existingProperties)) {
122 return undefined;
123 }
124 const statusNode = this.getStatusCodeIdentifier(factory, node);
125 return factory.createPropertyAssignment('status', statusNode);
126 }
127 getStatusCodeIdentifier(factory, node) {
128 const decorators = ts.canHaveDecorators
129 ? ts.getDecorators(node)
130 : node.decorators;
131 const httpCodeDecorator = (0, plugin_utils_1.getDecoratorOrUndefinedByNames)(['HttpCode'], decorators, factory);
132 if (httpCodeDecorator) {
133 const argument = (0, lodash_1.head)((0, ast_utils_1.getDecoratorArguments)(httpCodeDecorator));
134 if (argument) {
135 return argument;
136 }
137 }
138 const postDecorator = (0, plugin_utils_1.getDecoratorOrUndefinedByNames)(['Post'], decorators, factory);
139 if (postDecorator) {
140 return factory.createIdentifier('201');
141 }
142 return factory.createIdentifier('200');
143 }
144}
145exports.ControllerClassVisitor = ControllerClassVisitor;