@@ -160,6 +160,20 @@ namespace ts.NavigationBar {
160
160
for ( let node of nodes ) {
161
161
switch ( node . kind ) {
162
162
case SyntaxKind . ClassDeclaration :
163
+ topLevelNodes . push ( node ) ;
164
+ for ( const member of ( < ClassDeclaration > node ) . members ) {
165
+ if ( member . kind === SyntaxKind . MethodDeclaration || member . kind === SyntaxKind . Constructor ) {
166
+ type FunctionLikeMember = MethodDeclaration | ConstructorDeclaration ;
167
+ if ( ( < FunctionLikeMember > member ) . body ) {
168
+ // We do not include methods that does not have child functions in it, because of duplications.
169
+ if ( hasNamedFunctionDeclarations ( ( < Block > ( < FunctionLikeMember > member ) . body ) . statements ) ) {
170
+ topLevelNodes . push ( member ) ;
171
+ }
172
+ addTopLevelNodes ( ( < Block > ( < MethodDeclaration > member ) . body ) . statements , topLevelNodes ) ;
173
+ }
174
+ }
175
+ }
176
+ break ;
163
177
case SyntaxKind . EnumDeclaration :
164
178
case SyntaxKind . InterfaceDeclaration :
165
179
topLevelNodes . push ( node ) ;
@@ -182,23 +196,40 @@ namespace ts.NavigationBar {
182
196
}
183
197
}
184
198
185
- function isTopLevelFunctionDeclaration ( functionDeclaration : FunctionLikeDeclaration ) {
199
+ function hasNamedFunctionDeclarations ( nodes : NodeArray < Statement > ) : boolean {
200
+ for ( let s of nodes ) {
201
+ if ( s . kind === SyntaxKind . FunctionDeclaration && ! isEmpty ( ( < FunctionDeclaration > s ) . name . text ) ) {
202
+ return true ;
203
+ }
204
+ }
205
+ return false ;
206
+ }
207
+
208
+ function isTopLevelFunctionDeclaration ( functionDeclaration : FunctionLikeDeclaration ) : boolean {
186
209
if ( functionDeclaration . kind === SyntaxKind . FunctionDeclaration ) {
187
210
// A function declaration is 'top level' if it contains any function declarations
188
211
// within it.
189
212
if ( functionDeclaration . body && functionDeclaration . body . kind === SyntaxKind . Block ) {
190
213
// Proper function declarations can only have identifier names
191
- if ( forEach ( ( < Block > functionDeclaration . body ) . statements ,
192
- s => s . kind === SyntaxKind . FunctionDeclaration && ! isEmpty ( ( < FunctionDeclaration > s ) . name . text ) ) ) {
193
-
214
+ if ( hasNamedFunctionDeclarations ( ( < Block > functionDeclaration . body ) . statements ) ) {
194
215
return true ;
195
216
}
196
217
197
- // Or if it is not parented by another function. i.e all functions
198
- // at module scope are 'top level'.
218
+ // Or if it is not parented by another function. I.e all functions at module scope are 'top level'.
199
219
if ( ! isFunctionBlock ( functionDeclaration . parent ) ) {
200
220
return true ;
201
221
}
222
+
223
+ // Or if it is nested inside class methods and constructors.
224
+ else {
225
+ // We have made sure that a grand parent node exists with 'isFunctionBlock()' above.
226
+ const grandParentKind = functionDeclaration . parent . parent . kind ;
227
+ if ( grandParentKind === SyntaxKind . MethodDeclaration ||
228
+ grandParentKind === SyntaxKind . Constructor ) {
229
+
230
+ return true ;
231
+ }
232
+ }
202
233
}
203
234
}
204
235
@@ -376,6 +407,10 @@ namespace ts.NavigationBar {
376
407
case SyntaxKind . ClassDeclaration :
377
408
return createClassItem ( < ClassDeclaration > node ) ;
378
409
410
+ case SyntaxKind . MethodDeclaration :
411
+ case SyntaxKind . Constructor :
412
+ return createMemberFunctionLikeItem ( < MethodDeclaration | ConstructorDeclaration > node ) ;
413
+
379
414
case SyntaxKind . EnumDeclaration :
380
415
return createEnumItem ( < EnumDeclaration > node ) ;
381
416
@@ -424,11 +459,11 @@ namespace ts.NavigationBar {
424
459
getIndent ( node ) ) ;
425
460
}
426
461
427
- function createFunctionItem ( node : FunctionDeclaration ) {
462
+ function createFunctionItem ( node : FunctionDeclaration ) : ts . NavigationBarItem {
428
463
if ( node . body && node . body . kind === SyntaxKind . Block ) {
429
464
let childItems = getItemsWorker ( sortNodes ( ( < Block > node . body ) . statements ) , createChildItem ) ;
430
465
431
- return getNavigationBarItem ( ! node . name ? "default" : node . name . text ,
466
+ return getNavigationBarItem ( ! node . name ? "default" : node . name . text ,
432
467
ts . ScriptElementKind . functionElement ,
433
468
getNodeModifiers ( node ) ,
434
469
[ getNodeSpan ( node ) ] ,
@@ -439,6 +474,31 @@ namespace ts.NavigationBar {
439
474
return undefined ;
440
475
}
441
476
477
+ function createMemberFunctionLikeItem ( node : MethodDeclaration | ConstructorDeclaration ) : ts . NavigationBarItem {
478
+ if ( node . body && node . body . kind === SyntaxKind . Block ) {
479
+ let childItems = getItemsWorker ( sortNodes ( ( < Block > node . body ) . statements ) , createChildItem ) ;
480
+ let scriptElementKind : string ;
481
+ let memberFunctionName : string ;
482
+ if ( node . kind === SyntaxKind . MethodDeclaration ) {
483
+ memberFunctionName = getPropertyNameForPropertyNameNode ( node . name ) ;
484
+ scriptElementKind = ts . ScriptElementKind . memberFunctionElement ;
485
+ }
486
+ else {
487
+ memberFunctionName = "constructor" ;
488
+ scriptElementKind = ts . ScriptElementKind . constructorImplementationElement ;
489
+ }
490
+
491
+ return getNavigationBarItem ( memberFunctionName ,
492
+ scriptElementKind ,
493
+ getNodeModifiers ( node ) ,
494
+ [ getNodeSpan ( node ) ] ,
495
+ childItems ,
496
+ getIndent ( node ) ) ;
497
+ }
498
+
499
+ return undefined ;
500
+ }
501
+
442
502
function createSourceFileItem ( node : SourceFile ) : ts . NavigationBarItem {
443
503
let childItems = getItemsWorker ( getChildNodes ( node . statements ) , createChildItem ) ;
444
504
0 commit comments