1
1
import * as ts from "typescript" ;
2
2
import { ReflectionKind } from "../../models" ;
3
- import type { Logger } from "../../utils" ;
3
+ import { assertNever , Logger } from "../../utils" ;
4
+ import { CommentStyle } from "../../utils/options/declaration" ;
4
5
import { nicePath } from "../../utils/paths" ;
5
6
6
7
// Note: This does NOT include JSDoc syntax kinds. This is important!
@@ -82,13 +83,14 @@ const wantedKinds: Record<ReflectionKind, ts.SyntaxKind[]> = {
82
83
export function discoverComment (
83
84
symbol : ts . Symbol ,
84
85
kind : ReflectionKind ,
85
- logger : Logger
86
- ) : [ ts . SourceFile , ts . CommentRange ] | undefined {
86
+ logger : Logger ,
87
+ commentStyle : CommentStyle
88
+ ) : [ ts . SourceFile , ts . CommentRange [ ] ] | undefined {
87
89
// For a module comment, we want the first one defined in the file,
88
90
// not the last one, since that will apply to the import or declaration.
89
91
const reverse = symbol . declarations ?. some ( ts . isSourceFile ) ;
90
92
91
- const discovered : [ ts . SourceFile , ts . CommentRange ] [ ] = [ ] ;
93
+ const discovered : [ ts . SourceFile , ts . CommentRange [ ] ] [ ] = [ ] ;
92
94
93
95
for ( const decl of symbol . declarations || [ ] ) {
94
96
const text = decl . getSourceFile ( ) . text ;
@@ -111,21 +113,20 @@ export function discoverComment(
111
113
continue ;
112
114
}
113
115
114
- const comments = ts . getLeadingCommentRanges ( text , node . pos ) ;
116
+ const comments = collectCommentRanges (
117
+ ts . getLeadingCommentRanges ( text , node . pos )
118
+ ) ;
115
119
116
120
if ( reverse ) {
117
121
comments ?. reverse ( ) ;
118
122
}
119
123
120
- const lastDocComment = comments ?. find (
121
- ( c ) =>
122
- text [ c . pos ] === "/" &&
123
- text [ c . pos + 1 ] === "*" &&
124
- text [ c . pos + 2 ] === "*"
124
+ const selectedDocComment = comments . find ( ( ranges ) =>
125
+ permittedRange ( text , ranges , commentStyle )
125
126
) ;
126
127
127
- if ( lastDocComment ) {
128
- discovered . push ( [ decl . getSourceFile ( ) , lastDocComment ] ) ;
128
+ if ( selectedDocComment ) {
129
+ discovered . push ( [ decl . getSourceFile ( ) , selectedDocComment ] ) ;
129
130
}
130
131
}
131
132
}
@@ -139,7 +140,7 @@ export function discoverComment(
139
140
logger . warn (
140
141
`${ symbol . name } has multiple declarations with a comment. An arbitrary comment will be used.`
141
142
) ;
142
- const locations = discovered . map ( ( [ sf , { pos } ] ) => {
143
+ const locations = discovered . map ( ( [ sf , [ { pos } ] ] ) => {
143
144
const path = nicePath ( sf . fileName ) ;
144
145
const line = ts . getLineAndCharacterOfPosition ( sf , pos ) . line + 1 ;
145
146
return `${ path } :${ line } ` ;
@@ -155,23 +156,23 @@ export function discoverComment(
155
156
}
156
157
157
158
export function discoverSignatureComment (
158
- declaration : ts . SignatureDeclaration | ts . JSDocSignature
159
- ) : [ ts . SourceFile , ts . CommentRange ] | undefined {
159
+ declaration : ts . SignatureDeclaration | ts . JSDocSignature ,
160
+ commentStyle : CommentStyle
161
+ ) : [ ts . SourceFile , ts . CommentRange [ ] ] | undefined {
160
162
const node = declarationToCommentNode ( declaration ) ;
161
163
if ( ! node ) {
162
164
return ;
163
165
}
164
166
165
167
const text = node . getSourceFile ( ) . text ;
166
- const comments = ts . getLeadingCommentRanges ( text , node . pos ) ;
167
168
168
- const comment = comments ?. find (
169
- ( c ) =>
170
- text [ c . pos ] === "/" &&
171
- text [ c . pos + 1 ] === "*" &&
172
- text [ c . pos + 2 ] === "*"
169
+ const comments = collectCommentRanges (
170
+ ts . getLeadingCommentRanges ( text , node . pos )
173
171
) ;
174
172
173
+ const comment = comments . find ( ( ranges ) =>
174
+ permittedRange ( text , ranges , commentStyle )
175
+ ) ;
175
176
if ( comment ) {
176
177
return [ node . getSourceFile ( ) , comment ] ;
177
178
}
@@ -181,7 +182,7 @@ export function discoverSignatureComment(
181
182
* Check whether the given module declaration is the topmost.
182
183
*
183
184
* This function returns TRUE if there is no trailing module defined, in
184
- * the following example this would be the case only for module <code>C</code> .
185
+ * the following example this would be the case only for module `C` .
185
186
*
186
187
* ```
187
188
* module A.B.C { }
@@ -198,7 +199,7 @@ function isTopmostModuleDeclaration(node: ts.ModuleDeclaration): boolean {
198
199
* Return the root module declaration of the given module declaration.
199
200
*
200
201
* In the following example this function would always return module
201
- * <code>A</code> no matter which of the modules was passed in.
202
+ * `A` no matter which of the modules was passed in.
202
203
*
203
204
* ```
204
205
* module A.B.C { }
@@ -251,3 +252,62 @@ function declarationToCommentNode(node: ts.Declaration): ts.Node | undefined {
251
252
252
253
return node ;
253
254
}
255
+
256
+ /**
257
+ * Separate comment ranges into arrays so that multiple line comments are kept together
258
+ * and each block comment is left on its own.
259
+ */
260
+ function collectCommentRanges (
261
+ ranges : ts . CommentRange [ ] | undefined
262
+ ) : ts . CommentRange [ ] [ ] {
263
+ const result : ts . CommentRange [ ] [ ] = [ ] ;
264
+
265
+ let collect : ts . CommentRange [ ] = [ ] ;
266
+ for ( const range of ranges || [ ] ) {
267
+ collect . push ( range ) ;
268
+
269
+ switch ( range . kind ) {
270
+ case ts . SyntaxKind . MultiLineCommentTrivia :
271
+ if ( collect . length ) {
272
+ result . push ( collect ) ;
273
+ collect = [ ] ;
274
+ }
275
+ result . push ( [ range ] ) ;
276
+ break ;
277
+ case ts . SyntaxKind . SingleLineCommentTrivia :
278
+ collect . push ( range ) ;
279
+ break ;
280
+ /* istanbul ignore next */
281
+ default :
282
+ assertNever ( range . kind ) ;
283
+ }
284
+ }
285
+
286
+ if ( collect . length ) {
287
+ result . push ( collect ) ;
288
+ }
289
+
290
+ return result ;
291
+ }
292
+
293
+ function permittedRange (
294
+ text : string ,
295
+ ranges : ts . CommentRange [ ] ,
296
+ commentStyle : CommentStyle
297
+ ) : boolean {
298
+ switch ( commentStyle ) {
299
+ case CommentStyle . All :
300
+ return true ;
301
+ case CommentStyle . Block :
302
+ return ranges [ 0 ] . kind === ts . SyntaxKind . MultiLineCommentTrivia ;
303
+ case CommentStyle . Line :
304
+ return ranges [ 0 ] . kind === ts . SyntaxKind . SingleLineCommentTrivia ;
305
+ case CommentStyle . JSDoc :
306
+ return (
307
+ ranges [ 0 ] . kind === ts . SyntaxKind . MultiLineCommentTrivia &&
308
+ text [ ranges [ 0 ] . pos ] === "/" &&
309
+ text [ ranges [ 0 ] . pos + 1 ] === "*" &&
310
+ text [ ranges [ 0 ] . pos + 2 ] === "*"
311
+ ) ;
312
+ }
313
+ }
0 commit comments