1
1
import { compact , head } from 'lodash' ;
2
2
import * as ts from 'typescript' ;
3
- import { ApiResponse } from '../../decorators' ;
3
+ import { ApiOperation , ApiResponse } from '../../decorators' ;
4
+ import { PluginOptions } from '../merge-options' ;
4
5
import { OPENAPI_NAMESPACE } from '../plugin-constants' ;
5
- import { getDecoratorArguments } from '../utils/ast-utils' ;
6
+ import {
7
+ getDecoratorArguments ,
8
+ getMainCommentAndExamplesOfNode
9
+ } from '../utils/ast-utils' ;
6
10
import {
7
11
getDecoratorOrUndefinedByNames ,
8
12
getTypeReferenceAsString ,
@@ -15,14 +19,25 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
15
19
visit (
16
20
sourceFile : ts . SourceFile ,
17
21
ctx : ts . TransformationContext ,
18
- program : ts . Program
22
+ program : ts . Program ,
23
+ options : PluginOptions
19
24
) {
20
25
const typeChecker = program . getTypeChecker ( ) ;
21
26
sourceFile = this . updateImports ( sourceFile ) ;
22
27
23
28
const visitNode = ( node : ts . Node ) : ts . Node => {
24
29
if ( ts . isMethodDeclaration ( node ) ) {
25
- return this . addDecoratorToNode ( node , typeChecker , sourceFile . fileName ) ;
30
+ try {
31
+ return this . addDecoratorToNode (
32
+ node ,
33
+ typeChecker ,
34
+ options ,
35
+ sourceFile . fileName ,
36
+ sourceFile
37
+ ) ;
38
+ } catch {
39
+ return node ;
40
+ }
26
41
}
27
42
return ts . visitEachChild ( node , visitNode , ctx ) ;
28
43
} ;
@@ -32,17 +47,23 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
32
47
addDecoratorToNode (
33
48
compilerNode : ts . MethodDeclaration ,
34
49
typeChecker : ts . TypeChecker ,
35
- hostFilename : string
50
+ options : PluginOptions ,
51
+ hostFilename : string ,
52
+ sourceFile : ts . SourceFile
36
53
) : ts . MethodDeclaration {
37
54
const node = ts . getMutableClone ( compilerNode ) ;
38
- if ( ! node . decorators ) {
39
- return compilerNode ;
40
- }
41
- const { pos, end } = node . decorators ;
55
+ const nodeArray = node . decorators || ts . createNodeArray ( ) ;
56
+ const { pos, end } = nodeArray ;
42
57
43
58
node . decorators = Object . assign (
44
59
[
45
- ...node . decorators ,
60
+ ...this . createApiOperationDecorator (
61
+ node ,
62
+ nodeArray ,
63
+ options ,
64
+ sourceFile
65
+ ) ,
66
+ ...nodeArray ,
46
67
ts . createDecorator (
47
68
ts . createCall (
48
69
ts . createIdentifier ( `${ OPENAPI_NAMESPACE } .${ ApiResponse . name } ` ) ,
@@ -63,6 +84,68 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
63
84
return node ;
64
85
}
65
86
87
+ createApiOperationDecorator (
88
+ node : ts . MethodDeclaration ,
89
+ nodeArray : ts . NodeArray < ts . Decorator > ,
90
+ options : PluginOptions ,
91
+ sourceFile : ts . SourceFile
92
+ ) {
93
+ if ( ! options . introspectComments ) {
94
+ return [ ] ;
95
+ }
96
+ const keyToGenerate = options . controllerKeyOfComment ;
97
+ const apiOperationDecorator = getDecoratorOrUndefinedByNames (
98
+ [ ApiOperation . name ] ,
99
+ nodeArray
100
+ ) ;
101
+ const apiOperationExpr : ts . ObjectLiteralExpression | undefined =
102
+ apiOperationDecorator &&
103
+ head ( getDecoratorArguments ( apiOperationDecorator ) ) ;
104
+ const apiOperationExprProperties =
105
+ apiOperationExpr &&
106
+ ( apiOperationExpr . properties as ts . NodeArray < ts . PropertyAssignment > ) ;
107
+
108
+ if (
109
+ ! apiOperationDecorator ||
110
+ ! apiOperationExpr ||
111
+ ! apiOperationExprProperties ||
112
+ ! hasPropertyKey ( keyToGenerate , apiOperationExprProperties )
113
+ ) {
114
+ const [ extractedComments ] = getMainCommentAndExamplesOfNode (
115
+ node ,
116
+ sourceFile
117
+ ) ;
118
+ if ( ! extractedComments ) {
119
+ // Node does not have any comments
120
+ return [ ] ;
121
+ }
122
+ const properties = [
123
+ ts . createPropertyAssignment (
124
+ keyToGenerate ,
125
+ ts . createLiteral ( extractedComments )
126
+ ) ,
127
+ ...( apiOperationExprProperties ?? ts . createNodeArray ( ) )
128
+ ] ;
129
+ const apiOperationDecoratorArguments : ts . NodeArray < ts . Expression > = ts . createNodeArray (
130
+ [ ts . createObjectLiteral ( compact ( properties ) ) ]
131
+ ) ;
132
+ if ( apiOperationDecorator ) {
133
+ ( apiOperationDecorator . expression as ts . CallExpression ) . arguments = apiOperationDecoratorArguments ;
134
+ } else {
135
+ return [
136
+ ts . createDecorator (
137
+ ts . createCall (
138
+ ts . createIdentifier ( `${ OPENAPI_NAMESPACE } .${ ApiOperation . name } ` ) ,
139
+ undefined ,
140
+ apiOperationDecoratorArguments
141
+ )
142
+ )
143
+ ] ;
144
+ }
145
+ }
146
+ return [ ] ;
147
+ }
148
+
66
149
createDecoratorObjectLiteralExpr (
67
150
node : ts . MethodDeclaration ,
68
151
typeChecker : ts . TypeChecker ,
0 commit comments