@@ -13,11 +13,26 @@ namespace ts {
1313 referenced : boolean ;
1414 }
1515
16- export function getModuleInstanceState ( node : ModuleDeclaration ) : ModuleInstanceState {
17- return node . body ? getModuleInstanceStateWorker ( node . body ) : ModuleInstanceState . Instantiated ;
16+ export function getModuleInstanceState ( node : ModuleDeclaration , visited ?: Map < ModuleInstanceState | undefined > ) : ModuleInstanceState {
17+ if ( node . body && ! node . body . parent ) {
18+ // getModuleInstanceStateForAliasTarget needs to walk up the parent chain, so parent pointers must be set on this tree already
19+ setParentPointers ( node , node . body ) ;
20+ }
21+ return node . body ? getModuleInstanceStateCached ( node . body , visited ) : ModuleInstanceState . Instantiated ;
1822 }
1923
20- function getModuleInstanceStateWorker ( node : Node ) : ModuleInstanceState {
24+ function getModuleInstanceStateCached ( node : Node , visited = createMap < ModuleInstanceState | undefined > ( ) ) {
25+ const nodeId = "" + getNodeId ( node ) ;
26+ if ( visited . has ( nodeId ) ) {
27+ return visited . get ( nodeId ) || ModuleInstanceState . NonInstantiated ;
28+ }
29+ visited . set ( nodeId , undefined ) ;
30+ const result = getModuleInstanceStateWorker ( node , visited ) ;
31+ visited . set ( nodeId , result ) ;
32+ return result ;
33+ }
34+
35+ function getModuleInstanceStateWorker ( node : Node , visited : Map < ModuleInstanceState | undefined > ) : ModuleInstanceState {
2136 // A module is uninstantiated if it contains only
2237 switch ( node . kind ) {
2338 // 1. interface declarations, type alias declarations
@@ -37,11 +52,27 @@ namespace ts {
3752 return ModuleInstanceState . NonInstantiated ;
3853 }
3954 break ;
40- // 4. other uninstantiated module declarations.
55+ // 4. Export alias declarations pointing at only uninstantiated modules or things uninstantiated modules contain
56+ case SyntaxKind . ExportDeclaration :
57+ if ( ! ( node as ExportDeclaration ) . moduleSpecifier && ! ! ( node as ExportDeclaration ) . exportClause ) {
58+ let state = ModuleInstanceState . NonInstantiated ;
59+ for ( const specifier of ( node as ExportDeclaration ) . exportClause ! . elements ) {
60+ const specifierState = getModuleInstanceStateForAliasTarget ( specifier , visited ) ;
61+ if ( specifierState > state ) {
62+ state = specifierState ;
63+ }
64+ if ( state === ModuleInstanceState . Instantiated ) {
65+ return state ;
66+ }
67+ }
68+ return state ;
69+ }
70+ break ;
71+ // 5. other uninstantiated module declarations.
4172 case SyntaxKind . ModuleBlock : {
4273 let state = ModuleInstanceState . NonInstantiated ;
4374 forEachChild ( node , n => {
44- const childState = getModuleInstanceStateWorker ( n ) ;
75+ const childState = getModuleInstanceStateCached ( n , visited ) ;
4576 switch ( childState ) {
4677 case ModuleInstanceState . NonInstantiated :
4778 // child is non-instantiated - continue searching
@@ -61,7 +92,7 @@ namespace ts {
6192 return state ;
6293 }
6394 case SyntaxKind . ModuleDeclaration :
64- return getModuleInstanceState ( node as ModuleDeclaration ) ;
95+ return getModuleInstanceState ( node as ModuleDeclaration , visited ) ;
6596 case SyntaxKind . Identifier :
6697 // Only jsdoc typedef definition can exist in jsdoc namespace, and it should
6798 // be considered the same as type alias
@@ -72,6 +103,36 @@ namespace ts {
72103 return ModuleInstanceState . Instantiated ;
73104 }
74105
106+ function getModuleInstanceStateForAliasTarget ( specifier : ExportSpecifier , visited : Map < ModuleInstanceState | undefined > ) {
107+ const name = specifier . propertyName || specifier . name ;
108+ let p : Node | undefined = specifier . parent ;
109+ while ( p ) {
110+ if ( isBlock ( p ) || isModuleBlock ( p ) || isSourceFile ( p ) ) {
111+ const statements = p . statements ;
112+ let found : ModuleInstanceState | undefined ;
113+ for ( const statement of statements ) {
114+ if ( nodeHasName ( statement , name ) ) {
115+ if ( ! statement . parent ) {
116+ setParentPointers ( p , statement ) ;
117+ }
118+ const state = getModuleInstanceStateCached ( statement , visited ) ;
119+ if ( found === undefined || state > found ) {
120+ found = state ;
121+ }
122+ if ( found === ModuleInstanceState . Instantiated ) {
123+ return found ;
124+ }
125+ }
126+ }
127+ if ( found !== undefined ) {
128+ return found ;
129+ }
130+ }
131+ p = p . parent ;
132+ }
133+ return ModuleInstanceState . Instantiated ; // Couldn't locate, assume could refer to a value
134+ }
135+
75136 const enum ContainerFlags {
76137 // The current node is not a container, and no container manipulation should happen before
77138 // recursing into it.
@@ -2561,7 +2622,7 @@ namespace ts {
25612622 // Declare a 'member' if the container is an ES5 class or ES6 constructor
25622623 constructorSymbol . members = constructorSymbol . members || createSymbolTable ( ) ;
25632624 // It's acceptable for multiple 'this' assignments of the same identifier to occur
2564- declareSymbol ( constructorSymbol . members , constructorSymbol , node , SymbolFlags . Property , SymbolFlags . PropertyExcludes & ~ SymbolFlags . Property ) ;
2625+ declareSymbol ( constructorSymbol . members , constructorSymbol , node , SymbolFlags . Property | SymbolFlags . Assignment , SymbolFlags . PropertyExcludes & ~ SymbolFlags . Property ) ;
25652626 addDeclarationToSymbol ( constructorSymbol , constructorSymbol . valueDeclaration , SymbolFlags . Class ) ;
25662627 }
25672628 break ;
@@ -2575,7 +2636,7 @@ namespace ts {
25752636 // Bind this property to the containing class
25762637 const containingClass = thisContainer . parent ;
25772638 const symbolTable = hasModifier ( thisContainer , ModifierFlags . Static ) ? containingClass . symbol . exports ! : containingClass . symbol . members ! ;
2578- declareSymbol ( symbolTable , containingClass . symbol , node , SymbolFlags . Property , SymbolFlags . None , /*isReplaceableByMethod*/ true ) ;
2639+ declareSymbol ( symbolTable , containingClass . symbol , node , SymbolFlags . Property | SymbolFlags . Assignment , SymbolFlags . None , /*isReplaceableByMethod*/ true ) ;
25792640 break ;
25802641 case SyntaxKind . SourceFile :
25812642 // this.property = assignment in a source file -- declare symbol in exports for a module, in locals for a script
0 commit comments