namespace ts . NavigationBar { /**
     * Matches all whitespace characters in a string. Eg:
     *
     * "app.
     *
     * onactivated"
     *
     * matches because of the newline, whereas
     *
     * "app.onactivated"
     *
     * does not match.
     */ const whiteSpaceRegex = /\s+/g ; /**
     * Maximum amount of characters to return
     * The amount was chosen arbitrarily.
     */ const maxLength = 150 ; let curCancellationToken ; let curSourceFile ; /**
     * For performance, we keep navigation bar parents on a stack rather than passing them through each recursion.
     * `parent` is the current parent and is *not* stored in parentsStack.
     * `startNode` sets a new parent and `endNode` returns to the previous parent.
     */ let parentsStack = [ ] ; let parent ; const trackedEs5ClassesStack = [ ] ; let trackedEs5Classes ; let emptyChildItemArray = [ ] ; /**
     * Represents a navigation bar item and its children.
     * The returned NavigationBarItem is more complicated and doesn't include 'parent', so we use these to do work before converting.
     */ interface NavigationBarNode { node : Node ; name : DeclarationName | undefined ; additionalNodes : Node [ ] | undefined ; parent : NavigationBarNode | undefined ; children : NavigationBarNode [ ] | undefined ; indent : number ; } export function getNavigationBarItems ( sourceFile , cancellationToken ) { curCancellationToken = cancellationToken ; curSourceFile = sourceFile ; try { return map ( primaryNavBarMenuItems ( rootNavigationBarNode ( sourceFile ) ) , convertToPrimaryNavBarMenuItem ) ; } finally { reset ( ) ; } } export function getNavigationTree ( sourceFile , cancellationToken ) { curCancellationToken = cancellationToken ; curSourceFile = sourceFile ; try { return convertToTree ( rootNavigationBarNode ( sourceFile ) ) ; } finally { reset ( ) ; } } function reset ( ) { curSourceFile = undefined ! ; curCancellationToken = undefined ! ; parentsStack = [ ] ; parent = undefined ! ; emptyChildItemArray = [ ] ; } function nodeText ( node ) { return cleanText ( node . getText ( curSourceFile ) ) ; } function navigationBarNodeKind ( n ) { return n . node . kind ; } function pushChild ( parent , child ) { if ( parent . children ) { parent . children . push ( child ) ; } else { parent . children = [ child ] ; } } function rootNavigationBarNode ( sourceFile ) { Debug . assert ( ! parentsStack . length ) ; const root = { node : sourceFile , name : undefined , additionalNodes : undefined , parent : undefined , children : undefined , indent : 0 } ; parent = root ; for ( const statement of sourceFile . statements ) { addChildrenRecursively ( statement ) ; } endNode ( ) ; Debug . assert ( ! parent && ! parentsStack . length ) ; return root ; } function addLeafNode ( node , name ? ) { pushChild ( parent , emptyNavigationBarNode ( node , name ) ) ; } function emptyNavigationBarNode ( node , name ? ) { return { node , name : name || ( isDeclaration ( node ) || isExpression ( node ) ? getNameOfDeclaration ( node ) : undefined ) , additionalNodes : undefined , parent , children : undefined , indent : parent . indent + 1 } ; } function addTrackedEs5Class ( name ) { if ( ! trackedEs5Classes ) { trackedEs5Classes = new Map ( ) ; } trackedEs5Classes . set ( name , true ) ; } function endNestedNodes ( depth ) { for ( let i = 0 ; i < depth ; i ++ ) endNode ( ) ; } function startNestedNodes ( targetNode , entityName ) { const names = [ ] ; while ( ! isPropertyNameLiteral ( entityName ) ) { const name = getNameOrArgument ( entityName ) ; const nameText = getElementOrPropertyAccessName ( entityName ) ; entityName = entityName . expression ; if ( nameText === "prototype" || isPrivateIdentifier ( name ) ) continue ; names . push ( name ) ; } names . push ( entityName ) ; for ( let i = names . length - 1 ; i > 0 ; i -- ) { const name = names [ i ] ; startNode ( targetNode , name ) ; } return [ names . length - 1 , names [ 0 ] ] as const ; } /**
     * Add a new level of NavigationBarNodes.
     * This pushes to the stack, so you must call `endNode` when you are done adding to this node.
     */ function startNode ( node , name ? ) { const navNode = emptyNavigationBarNode ( node , name ) ; pushChild ( parent , navNode ) ; parentsStack . push ( parent ) ; trackedEs5ClassesStack . push ( trackedEs5Classes ) ; trackedEs5Classes = undefined ; parent = navNode ; } /** Call after calling `startNode` and adding children to it. */ function endNode ( ) { if ( parent . children ) { mergeChildren ( parent . children , parent ) ; sortChildren ( parent . children ) ; } parent = parentsStack . pop ( ) ! ; trackedEs5Classes = trackedEs5ClassesStack . pop ( ) ; } function addNodeWithRecursiveChild ( node , child , name ? ) { startNode ( node , name ) ; addChildrenRecursively ( child ) ; endNode ( ) ; } function addNodeWithRecursiveInitializer ( node ) { if ( node . initializer && isFunctionOrClassExpression ( node . initializer ) ) { startNode ( node ) ; forEachChild ( node . initializer , addChildrenRecursively ) ; endNode ( ) ; } else { addNodeWithRecursiveChild ( node , node . initializer ) ; } } /**
     * Historically, we've elided dynamic names from the nav tree (including late bound names),
     * but included certain "well known" symbol names. While we no longer distinguish those well-known
     * symbols from other unique symbols, we do the below to retain those members in the nav tree.
     */ function hasNavigationBarName ( node ) { return ! hasDynamicName ( node ) || ( node . kind !== SyntaxKind . BinaryExpression && isPropertyAccessExpression ( node . name . expression ) && isIdentifier ( node . name . expression . expression ) && idText ( node . name . expression . expression ) === "Symbol" ) ; } /** Look for navigation bar items in node's subtree, adding them to the current `parent`. */ function addChildrenRecursively ( node ) { curCancellationToken . throwIfCancellationRequested ( ) ; if ( ! node || isToken ( node ) ) { return ; } switch ( node . kind ) { case SyntaxKind . Constructor : const ctr = node as ConstructorDeclaration ; addNodeWithRecursiveChild ( ctr , ctr . body ) ; for ( const param of ctr . parameters ) { if ( isParameterPropertyDeclaration ( param , ctr ) ) { addLeafNode ( param ) ; } } break ; case SyntaxKind . MethodDeclaration : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : case SyntaxKind . MethodSignature : if ( hasNavigationBarName ( node as ClassElement | TypeElement ) ) { addNodeWithRecursiveChild ( node , ( node as FunctionLikeDeclaration ) . body ) ; } break ; case SyntaxKind . PropertyDeclaration : if ( hasNavigationBarName ( node as ClassElement ) ) { addNodeWithRecursiveInitializer ( node as PropertyDeclaration ) ; } break ; case SyntaxKind . PropertySignature : if ( hasNavigationBarName ( node as TypeElement ) ) { addLeafNode ( node ) ; } break ; case SyntaxKind . ImportClause : const importClause = node as ImportClause ; if ( importClause . name ) { addLeafNode ( importClause . name ) ; } const { namedBindings } = importClause ; if ( namedBindings ) { if ( namedBindings . kind === SyntaxKind . NamespaceImport ) { addLeafNode ( namedBindings ) ; } else { for ( const element of namedBindings . elements ) { addLeafNode ( element ) ; } } } break ; case SyntaxKind . ShorthandPropertyAssignment : addNodeWithRecursiveChild ( node , ( node as ShorthandPropertyAssignment ) . name ) ; break ; case SyntaxKind . SpreadAssignment : const { expression } = node as SpreadAssignment ; isIdentifier ( expression ) ? addLeafNode ( node , expression ) : addLeafNode ( node ) ; break ; case SyntaxKind . BindingElement : case SyntaxKind . PropertyAssignment : case SyntaxKind . VariableDeclaration : { const child = node as VariableDeclaration | PropertyAssignment | BindingElement ; if ( isBindingPattern ( child . name ) ) { addChildrenRecursively ( child . name ) ; } else { addNodeWithRecursiveInitializer ( child ) ; } break ; } case SyntaxKind . FunctionDeclaration : const nameNode = ( node as FunctionLikeDeclaration ) . name ; if ( nameNode && isIdentifier ( nameNode ) ) { addTrackedEs5Class ( nameNode . text ) ; } addNodeWithRecursiveChild ( node , ( node as FunctionLikeDeclaration ) . body ) ; break ; case SyntaxKind . ArrowFunction : case SyntaxKind . FunctionExpression : addNodeWithRecursiveChild ( node , ( node as FunctionLikeDeclaration ) . body ) ; break ; case SyntaxKind . EnumDeclaration : startNode ( node ) ; for ( const member of ( node as EnumDeclaration ) . members ) { if ( ! isComputedProperty ( member ) ) { addLeafNode ( member ) ; } } endNode ( ) ; break ; case SyntaxKind . ClassDeclaration : case SyntaxKind . ClassExpression : case SyntaxKind . InterfaceDeclaration : startNode ( node ) ; for ( const member of ( node as InterfaceDeclaration ) . members ) { addChildrenRecursively ( member ) ; } endNode ( ) ; break ; case SyntaxKind . ModuleDeclaration : addNodeWithRecursiveChild ( node , getInteriorModule ( node as ModuleDeclaration ) . body ) ; break ; case SyntaxKind . ExportAssignment : { const expression = ( node as ExportAssignment ) . expression ; const child = isObjectLiteralExpression ( expression ) || isCallExpression ( expression ) ? expression : isArrowFunction ( expression ) || isFunctionExpression ( expression ) ? expression . body : undefined ; if ( child ) { startNode ( node ) ; addChildrenRecursively ( child ) ; endNode ( ) ; } else { addLeafNode ( node ) ; } break ; } case SyntaxKind . ExportSpecifier : case SyntaxKind . ImportEqualsDeclaration : case SyntaxKind . IndexSignature : case SyntaxKind . CallSignature : case SyntaxKind . ConstructSignature : case SyntaxKind . TypeAliasDeclaration : addLeafNode ( node ) ; break ; case SyntaxKind . CallExpression : case SyntaxKind . BinaryExpression : { const special = getAssignmentDeclarationKind ( node as BinaryExpression ) ; switch ( special ) { case AssignmentDeclarationKind . ExportsProperty : case AssignmentDeclarationKind . ModuleExports : addNodeWithRecursiveChild ( node , ( node as BinaryExpression ) . right ) ; return ; case AssignmentDeclarationKind . Prototype : case AssignmentDeclarationKind . PrototypeProperty : { const binaryExpression = ( node as BinaryExpression ) ; const assignmentTarget = binaryExpression . left as PropertyAccessExpression ; const prototypeAccess = special === AssignmentDeclarationKind . PrototypeProperty ? assignmentTarget . expression as PropertyAccessExpression : assignmentTarget ; let depth = 0 ; let className ; if ( isIdentifier ( prototypeAccess . expression ) ) { addTrackedEs5Class ( prototypeAccess . expression . text ) ; className = prototypeAccess . expression ; } else { [ depth , className ] = startNestedNodes ( binaryExpression , prototypeAccess . expression as EntityNameExpression ) ; } if ( special === AssignmentDeclarationKind . Prototype ) { if ( isObjectLiteralExpression ( binaryExpression . right ) ) { if ( binaryExpression . right . properties . length > 0 ) { startNode ( binaryExpression , className ) ; forEachChild ( binaryExpression . right , addChildrenRecursively ) ; endNode ( ) ; } } } else if ( isFunctionExpression ( binaryExpression . right ) || isArrowFunction ( binaryExpression . right ) ) { addNodeWithRecursiveChild ( node , binaryExpression . right , className ) ; } else { startNode ( binaryExpression , className ) ; addNodeWithRecursiveChild ( node , binaryExpression . right , assignmentTarget . name ) ; endNode ( ) ; } endNestedNodes ( depth ) ; return ; } case AssignmentDeclarationKind . ObjectDefinePropertyValue : case AssignmentDeclarationKind . ObjectDefinePrototypeProperty : { const defineCall = node as BindableObjectDefinePropertyCall ; const className = special === AssignmentDeclarationKind . ObjectDefinePropertyValue ? defineCall . arguments [ 0 ] : ( defineCall . arguments [ 0 ] as PropertyAccessExpression ) . expression as EntityNameExpression ; const memberName = defineCall . arguments [ 1 ] ; const [ depth , classNameIdentifier ] = startNestedNodes ( node , className ) ; startNode ( node , classNameIdentifier ) ; startNode ( node , setTextRange ( factory . createIdentifier ( memberName . text ) , memberName ) ) ; addChildrenRecursively ( ( node as CallExpression ) . arguments [ 2 ] ) ; endNode ( ) ; endNode ( ) ; endNestedNodes ( depth ) ; return ; } case AssignmentDeclarationKind . Property : { const binaryExpression = ( node as BinaryExpression ) ; const assignmentTarget = binaryExpression . left as PropertyAccessExpression | BindableElementAccessExpression ; const targetFunction = assignmentTarget . expression ; if ( isIdentifier ( targetFunction ) && getElementOrPropertyAccessName ( assignmentTarget ) !== "prototype" && trackedEs5Classes && trackedEs5Classes . has ( targetFunction . text ) ) { if ( isFunctionExpression ( binaryExpression . right ) || isArrowFunction ( binaryExpression . right ) ) { addNodeWithRecursiveChild ( node , binaryExpression . right , targetFunction ) ; } else if ( isBindableStaticAccessExpression ( assignmentTarget ) ) { startNode ( binaryExpression , targetFunction ) ; addNodeWithRecursiveChild ( binaryExpression . left , binaryExpression . right , getNameOrArgument ( assignmentTarget ) ) ; endNode ( ) ; } return ; } break ; } case AssignmentDeclarationKind . ThisProperty : case AssignmentDeclarationKind . None : case AssignmentDeclarationKind . ObjectDefinePropertyExports : break ; default : Debug . assertNever ( special ) ; } } default : if ( hasJSDocNodes ( node ) ) { forEach ( node . jsDoc , jsDoc => { forEach ( jsDoc . tags , tag => { if ( isJSDocTypeAlias ( tag ) ) { addLeafNode ( tag ) ; } } ) ; } ) ; } forEachChild ( node , addChildrenRecursively ) ; } } /** Merge declarations of the same kind. */ function mergeChildren ( children , node ) { const nameToItems = new Map < string , NavigationBarNode | NavigationBarNode [ ] > ( ) ; filterMutate ( children , ( child , index ) => { const declName = child . name || getNameOfDeclaration ( child . node as Declaration ) ; const name = declName && nodeText ( declName ) ; if ( ! name ) { return true ; } const itemsWithSameName = nameToItems . get ( name ) ; if ( ! itemsWithSameName ) { nameToItems . set ( name , child ) ; return true ; } if ( itemsWithSameName instanceof Array ) { for ( const itemWithSameName of itemsWithSameName ) { if ( tryMerge ( itemWithSameName , child , index , node ) ) { return false ; } } itemsWithSameName . push ( child ) ; return true ; } else { const itemWithSameName = itemsWithSameName ; if ( tryMerge ( itemWithSameName , child , index , node ) ) { return false ; } nameToItems . set ( name , [ itemWithSameName , child ] ) ; return true ; } } ) ; } const isEs5ClassMember = { [ AssignmentDeclarationKind . Property ] : true , [ AssignmentDeclarationKind . PrototypeProperty ] : true , [ AssignmentDeclarationKind . ObjectDefinePropertyValue ] : true , [ AssignmentDeclarationKind . ObjectDefinePrototypeProperty ] : true , [ AssignmentDeclarationKind . None ] : false , [ AssignmentDeclarationKind . ExportsProperty ] : false , [ AssignmentDeclarationKind . ModuleExports ] : false , [ AssignmentDeclarationKind . ObjectDefinePropertyExports ] : false , [ AssignmentDeclarationKind . Prototype ] : true , [ AssignmentDeclarationKind . ThisProperty ] : false , } ; function tryMergeEs5Class ( a , b , bIndex , parent ) { function isPossibleConstructor ( node ) { return isFunctionExpression ( node ) || isFunctionDeclaration ( node ) || isVariableDeclaration ( node ) ; } const bAssignmentDeclarationKind = isBinaryExpression ( b . node ) || isCallExpression ( b . node ) ? getAssignmentDeclarationKind ( b . node ) : AssignmentDeclarationKind . None ; const aAssignmentDeclarationKind = isBinaryExpression ( a . node ) || isCallExpression ( a . node ) ? getAssignmentDeclarationKind ( a . node ) : AssignmentDeclarationKind . None ; if ( ( isEs5ClassMember [ bAssignmentDeclarationKind ] && isEs5ClassMember [ aAssignmentDeclarationKind ] ) || ( isPossibleConstructor ( a . node ) && isEs5ClassMember [ bAssignmentDeclarationKind ] ) || ( isPossibleConstructor ( b . node ) && isEs5ClassMember [ aAssignmentDeclarationKind ] ) || ( isClassDeclaration ( a . node ) && isSynthesized ( a . node ) && isEs5ClassMember [ bAssignmentDeclarationKind ] ) || ( isClassDeclaration ( b . node ) && isEs5ClassMember [ aAssignmentDeclarationKind ] ) || ( isClassDeclaration ( a . node ) && isSynthesized ( a . node ) && isPossibleConstructor ( b . node ) ) || ( isClassDeclaration ( b . node ) && isPossibleConstructor ( a . node ) && isSynthesized ( a . node ) ) ) { let lastANode = a . additionalNodes && lastOrUndefined ( a . additionalNodes ) || a . node ; if ( ( ! isClassDeclaration ( a . node ) && ! isClassDeclaration ( b . node ) ) || isPossibleConstructor ( a . node ) || isPossibleConstructor ( b . node ) ) { const ctorFunction = isPossibleConstructor ( a . node ) ? a . node : isPossibleConstructor ( b . node ) ? b . node : undefined ; if ( ctorFunction !== undefined ) { const ctorNode = setTextRange ( factory . createConstructorDeclaration ( undefined , undefined , [ ] , undefined ) , ctorFunction ) ; const ctor = emptyNavigationBarNode ( ctorNode ) ; ctor . indent = a . indent + 1 ; ctor . children = a . node === ctorFunction ? a . children : b . children ; a . children = a . node === ctorFunction ? concatenate ( [ ctor ] , b . children || [ b ] ) : concatenate ( a . children || [ { ... a } ] , [ ctor ] ) ; } else { if ( a . children || b . children ) { a . children = concatenate ( a . children || [ { ... a } ] , b . children || [ b ] ) ; if ( a . children ) { mergeChildren ( a . children , a ) ; sortChildren ( a . children ) ; } } } lastANode = a . node = setTextRange ( factory . createClassDeclaration ( undefined , undefined , a . name as Identifier || factory . createIdentifier ( "__class__" ) , undefined , undefined , [ ] ) , a . node ) ; } else { a . children = concatenate ( a . children , b . children ) ; if ( a . children ) { mergeChildren ( a . children , a ) ; } } const bNode = b . node ; if ( parent . children ! [ bIndex - 1 ] . node . end === lastANode . end ) { setTextRange ( lastANode , { pos : lastANode . pos , end : bNode . end } ) ; } else { if ( ! a . additionalNodes ) a . additionalNodes = [ ] ; a . additionalNodes . push ( setTextRange ( factory . createClassDeclaration ( undefined , undefined , a . name as Identifier || factory . createIdentifier ( "__class__" ) , undefined , undefined , [ ] ) , b . node ) ) ; } return true ; } return bAssignmentDeclarationKind === AssignmentDeclarationKind . None ? false : true ; } function tryMerge ( a , b , bIndex , parent ) { if ( tryMergeEs5Class ( a , b , bIndex , parent ) ) { return true ; } if ( shouldReallyMerge ( a . node , b . node , parent ) ) { merge ( a , b ) ; return true ; } return false ; } /** a and b have the same name, but they may not be mergeable. */ function shouldReallyMerge ( a , b , parent ) { if ( a . kind !== b . kind || a . parent !== b . parent && ! ( isOwnChild ( a , parent ) && isOwnChild ( b , parent ) ) ) { return false ; } switch ( a . kind ) { case SyntaxKind . PropertyDeclaration : case SyntaxKind . MethodDeclaration : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : return isStatic ( a ) === isStatic ( b ) ; case SyntaxKind . ModuleDeclaration : return areSameModule ( a as ModuleDeclaration , b as ModuleDeclaration ) && getFullyQualifiedModuleName ( a as ModuleDeclaration ) === getFullyQualifiedModuleName ( b as ModuleDeclaration ) ; default : return true ; } } function isSynthesized ( node ) { return ! ! ( node . flags & NodeFlags . Synthesized ) ; } function isOwnChild ( n , parent ) { const par = isModuleBlock ( n . parent ) ? n . parent . parent : n . parent ; return par === parent . node || contains ( parent . additionalNodes , par ) ; } function areSameModule ( a , b ) { if ( ! a . body || ! b . body ) { return a . body === b . body ; } return a . body . kind === b . body . kind && ( a . body . kind !== SyntaxKind . ModuleDeclaration || areSameModule ( a . body as ModuleDeclaration , b . body as ModuleDeclaration ) ) ; } /** Merge source into target. Source should be thrown away after this is called. */ function merge ( target , source ) { target . additionalNodes = target . additionalNodes || [ ] ; target . additionalNodes . push ( source . node ) ; if ( source . additionalNodes ) { target . additionalNodes . push ( ... source . additionalNodes ) ; } target . children = concatenate ( target . children , source . children ) ; if ( target . children ) { mergeChildren ( target . children , target ) ; sortChildren ( target . children ) ; } } /** Recursively ensure that each NavNode's children are in sorted order. */ function sortChildren ( children ) { children . sort ( compareChildren ) ; } function compareChildren ( child1 , child2 ) { return compareStringsCaseSensitiveUI ( tryGetName ( child1 . node ) ! , tryGetName ( child2 . node ) ! ) || compareValues ( navigationBarNodeKind ( child1 ) , navigationBarNodeKind ( child2 ) ) ; } /**
     * This differs from getItemName because this is just used for sorting.
     * We only sort nodes by name that have a more-or-less "direct" name, as opposed to `new()` and the like.
     * So `new()` can still come before an `aardvark` method.
     */ function tryGetName ( node ) { if ( node . kind === SyntaxKind . ModuleDeclaration ) { return getModuleName ( node as ModuleDeclaration ) ; } const declName = getNameOfDeclaration ( node as Declaration ) ; if ( declName && isPropertyName ( declName ) ) { const propertyName = getPropertyNameForPropertyNameNode ( declName ) ; return propertyName && unescapeLeadingUnderscores ( propertyName ) ; } switch ( node . kind ) { case SyntaxKind . FunctionExpression : case SyntaxKind . ArrowFunction : case SyntaxKind . ClassExpression : return getFunctionOrClassName ( node as FunctionExpression | ArrowFunction | ClassExpression ) ; default : return undefined ; } } function getItemName ( node , name ) { if ( node . kind === SyntaxKind . ModuleDeclaration ) { return cleanText ( getModuleName ( node as ModuleDeclaration ) ) ; } if ( name ) { const text = isIdentifier ( name ) ? name . text : isElementAccessExpression ( name ) ? `[${ nodeText ( name . argumentExpression ) }]` : nodeText ( name ) ; if ( text . length > 0 ) { return cleanText ( text ) ; } } switch ( node . kind ) { case SyntaxKind . SourceFile : const sourceFile = node as SourceFile ; return isExternalModule ( sourceFile ) ? `"${ escapeString ( getBaseFileName ( removeFileExtension ( normalizePath ( sourceFile . fileName ) ) ) ) }"` : "<global>" ; case SyntaxKind . ExportAssignment : return isExportAssignment ( node ) && node . isExportEquals ? InternalSymbolName . ExportEquals : InternalSymbolName . Default ; case SyntaxKind . ArrowFunction : case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : case SyntaxKind . ClassDeclaration : case SyntaxKind . ClassExpression : if ( getSyntacticModifierFlags ( node ) & ModifierFlags . Default ) { return "default" ; } return getFunctionOrClassName ( node as ArrowFunction | FunctionExpression | ClassExpression ) ; case SyntaxKind . Constructor : return "constructor" ; case SyntaxKind . ConstructSignature : return "new()" ; case SyntaxKind . CallSignature : return "()" ; case SyntaxKind . IndexSignature : return "[]" ; default : return "<unknown>" ; } } /** Flattens the NavNode tree to a list of items to appear in the primary navbar menu. */ function primaryNavBarMenuItems ( root ) { const primaryNavBarMenuItems = [ ] ; function recur ( item ) { if ( shouldAppearInPrimaryNavBarMenu ( item ) ) { primaryNavBarMenuItems . push ( item ) ; if ( item . children ) { for ( const child of item . children ) { recur ( child ) ; } } } } recur ( root ) ; return primaryNavBarMenuItems ; /** Determines if a node should appear in the primary navbar menu. */ function shouldAppearInPrimaryNavBarMenu ( item ) { if ( item . children ) { return true ; } switch ( navigationBarNodeKind ( item ) ) { case SyntaxKind . ClassDeclaration : case SyntaxKind . ClassExpression : case SyntaxKind . EnumDeclaration : case SyntaxKind . InterfaceDeclaration : case SyntaxKind . ModuleDeclaration : case SyntaxKind . SourceFile : case SyntaxKind . TypeAliasDeclaration : case SyntaxKind . JSDocTypedefTag : case SyntaxKind . JSDocCallbackTag : return true ; case SyntaxKind . ArrowFunction : case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : return isTopLevelFunctionDeclaration ( item ) ; default : return false ; } function isTopLevelFunctionDeclaration ( item ) { if ( ! ( item . node as FunctionDeclaration ) . body ) { return false ; } switch ( navigationBarNodeKind ( item . parent ! ) ) { case SyntaxKind . ModuleBlock : case SyntaxKind . SourceFile : case SyntaxKind . MethodDeclaration : case SyntaxKind . Constructor : return true ; default : return false ; } } } } function convertToTree ( n ) { return { text : getItemName ( n . node , n . name ) , kind : getNodeKind ( n . node ) , kindModifiers : getModifiers ( n . node ) , spans : getSpans ( n ) , nameSpan : n . name && getNodeSpan ( n . name ) , childItems : map ( n . children , convertToTree ) } ; } function convertToPrimaryNavBarMenuItem ( n ) { return { text : getItemName ( n . node , n . name ) , kind : getNodeKind ( n . node ) , kindModifiers : getModifiers ( n . node ) , spans : getSpans ( n ) , childItems : map ( n . children , convertToSecondaryNavBarMenuItem ) || emptyChildItemArray , indent : n . indent , bolded : false , grayed : false } ; function convertToSecondaryNavBarMenuItem ( n ) { return { text : getItemName ( n . node , n . name ) , kind : getNodeKind ( n . node ) , kindModifiers : getNodeModifiers ( n . node ) , spans : getSpans ( n ) , childItems : emptyChildItemArray , indent : 0 , bolded : false , grayed : false } ; } } function getSpans ( n ) { const spans = [ getNodeSpan ( n . node ) ] ; if ( n . additionalNodes ) { for ( const node of n . additionalNodes ) { spans . push ( getNodeSpan ( node ) ) ; } } return spans ; } function getModuleName ( moduleDeclaration ) { if ( isAmbientModule ( moduleDeclaration ) ) { return getTextOfNode ( moduleDeclaration . name ) ; } return getFullyQualifiedModuleName ( moduleDeclaration ) ; } function getFullyQualifiedModuleName ( moduleDeclaration ) { const result = [ getTextOfIdentifierOrLiteral ( moduleDeclaration . name ) ] ; while ( moduleDeclaration . body && moduleDeclaration . body . kind === SyntaxKind . ModuleDeclaration ) { moduleDeclaration = moduleDeclaration . body ; result . push ( getTextOfIdentifierOrLiteral ( moduleDeclaration . name ) ) ; } return result . join ( "." ) ; } /**
     * For 'module A.B.C', we want to get the node for 'C'.
     * We store 'A' as associated with a NavNode, and use getModuleName to traverse down again.
     */ function getInteriorModule ( decl ) { return decl . body && isModuleDeclaration ( decl . body ) ? getInteriorModule ( decl . body ) : decl ; } function isComputedProperty ( member ) { return ! member . name || member . name . kind === SyntaxKind . ComputedPropertyName ; } function getNodeSpan ( node ) { return node . kind === SyntaxKind . SourceFile ? createTextSpanFromRange ( node ) : createTextSpanFromNode ( node , curSourceFile ) ; } function getModifiers ( node ) { if ( node . parent && node . parent . kind === SyntaxKind . VariableDeclaration ) { node = node . parent ; } return getNodeModifiers ( node ) ; } function getFunctionOrClassName ( node ) { const { parent } = node ; if ( node . name && getFullWidth ( node . name ) > 0 ) { return cleanText ( declarationNameToString ( node . name ) ) ; } else if ( isVariableDeclaration ( parent ) ) { return cleanText ( declarationNameToString ( parent . name ) ) ; } else if ( isBinaryExpression ( parent ) && parent . operatorToken . kind === SyntaxKind . EqualsToken ) { return nodeText ( parent . left ) . replace ( whiteSpaceRegex , "" ) ; } else if ( isPropertyAssignment ( parent ) ) { return nodeText ( parent . name ) ; } else if ( getSyntacticModifierFlags ( node ) & ModifierFlags . Default ) { return "default" ; } else if ( isClassLike ( node ) ) { return "<class>" ; } else if ( isCallExpression ( parent ) ) { let name = getCalledExpressionName ( parent . expression ) ; if ( name !== undefined ) { name = cleanText ( name ) ; if ( name . length > maxLength ) { return `${ name } callback` ; } const args = cleanText ( mapDefined ( parent . arguments , a => isStringLiteralLike ( a ) ? a . getText ( curSourceFile ) : undefined ) . join ( ", " ) ) ; return `${ name }(${ args }) callback` ; } } return "<function>" ; } function getCalledExpressionName ( expr ) { if ( isIdentifier ( expr ) ) { return expr . text ; } else if ( isPropertyAccessExpression ( expr ) ) { const left = getCalledExpressionName ( expr . expression ) ; const right = expr . name . text ; return left === undefined ? right : `${ left }.${ right }` ; } else { return undefined ; } } function isFunctionOrClassExpression ( node ) { switch ( node . kind ) { case SyntaxKind . ArrowFunction : case SyntaxKind . FunctionExpression : case SyntaxKind . ClassExpression : return true ; default : return false ; } } function cleanText ( text ) { text = text . length > maxLength ? text . substring ( 0 , maxLength ) + "..." : text ; return text . replace ( /\\?(\r?\n|\r|\u2028|\u2029)/g , "" ) ; } }