@@ -6,8 +6,8 @@ namespace ts {
66
77 export const enum ModuleInstanceState {
88 NonInstantiated = 0 ,
9- Instantiated = 1 ,
10- ConstEnumOnly = 2
9+ Instantiated = 1 ,
10+ ConstEnumOnly = 2
1111 }
1212
1313 export function getModuleInstanceState ( node : Node ) : ModuleInstanceState {
@@ -90,6 +90,8 @@ namespace ts {
9090 let lastContainer : Node ;
9191 let seenThisKeyword : boolean ;
9292
93+ let isJavaScriptFile = isSourceFileJavaScript ( file ) ;
94+
9395 // If this file is an external module, then it is automatically in strict-mode according to
9496 // ES6. If it is not an external module, then we'll determine if it is in strict mode or
9597 // not depending on if we see "use strict" in certain places (or if we hit a class/namespace).
@@ -167,6 +169,10 @@ namespace ts {
167169 case SyntaxKind . FunctionDeclaration :
168170 case SyntaxKind . ClassDeclaration :
169171 return node . flags & NodeFlags . Default ? "default" : undefined ;
172+
173+ case SyntaxKind . BinaryExpression :
174+ Debug . assert ( isModuleExportsAssignment ( node ) ) ;
175+ return "__jsExports" ;
170176 }
171177 }
172178
@@ -779,7 +785,7 @@ namespace ts {
779785 return "__" + indexOf ( ( < SignatureDeclaration > node . parent ) . parameters , node ) ;
780786 }
781787
782- function bind ( node : Node ) {
788+ function bind ( node : Node ) : void {
783789 node . parent = parent ;
784790
785791 let savedInStrictMode = inStrictMode ;
@@ -851,9 +857,18 @@ namespace ts {
851857
852858 function bindWorker ( node : Node ) {
853859 switch ( node . kind ) {
860+ /* Strict mode checks */
854861 case SyntaxKind . Identifier :
855862 return checkStrictModeIdentifier ( < Identifier > node ) ;
856863 case SyntaxKind . BinaryExpression :
864+ if ( isJavaScriptFile ) {
865+ if ( isExportsPropertyAssignment ( node ) ) {
866+ bindExportsPropertyAssignment ( < BinaryExpression > node ) ;
867+ }
868+ else if ( isModuleExportsAssignment ( node ) ) {
869+ bindModuleExportsAssignment ( < BinaryExpression > node ) ;
870+ }
871+ }
857872 return checkStrictModeBinaryExpression ( < BinaryExpression > node ) ;
858873 case SyntaxKind . CatchClause :
859874 return checkStrictModeCatchClause ( < CatchClause > node ) ;
@@ -919,6 +934,16 @@ namespace ts {
919934 checkStrictModeFunctionName ( < FunctionExpression > node ) ;
920935 let bindingName = ( < FunctionExpression > node ) . name ? ( < FunctionExpression > node ) . name . text : "__function" ;
921936 return bindAnonymousDeclaration ( < FunctionExpression > node , SymbolFlags . Function , bindingName ) ;
937+
938+ case SyntaxKind . CallExpression :
939+ // We're only inspecting call expressions to detect CommonJS modules, so we can skip
940+ // this check if we've already seen the module indicator
941+ if ( isJavaScriptFile && ! file . commonJsModuleIndicator ) {
942+ bindCallExpression ( < CallExpression > node ) ;
943+ }
944+ break ;
945+
946+ // Members of classes, interfaces, and modules
922947 case SyntaxKind . ClassExpression :
923948 case SyntaxKind . ClassDeclaration :
924949 return bindClassLikeDeclaration ( < ClassLikeDeclaration > node ) ;
@@ -930,6 +955,8 @@ namespace ts {
930955 return bindEnumDeclaration ( < EnumDeclaration > node ) ;
931956 case SyntaxKind . ModuleDeclaration :
932957 return bindModuleDeclaration ( < ModuleDeclaration > node ) ;
958+
959+ // Imports and exports
933960 case SyntaxKind . ImportEqualsDeclaration :
934961 case SyntaxKind . NamespaceImport :
935962 case SyntaxKind . ImportSpecifier :
@@ -949,10 +976,14 @@ namespace ts {
949976 function bindSourceFileIfExternalModule ( ) {
950977 setExportContextFlag ( file ) ;
951978 if ( isExternalModule ( file ) ) {
952- bindAnonymousDeclaration ( file , SymbolFlags . ValueModule , `" ${ removeFileExtension ( file . fileName ) } "` ) ;
979+ bindSourceFileAsExternalModule ( ) ;
953980 }
954981 }
955982
983+ function bindSourceFileAsExternalModule ( ) {
984+ bindAnonymousDeclaration ( file , SymbolFlags . ValueModule , `"${ removeFileExtension ( file . fileName ) } "` ) ;
985+ }
986+
956987 function bindExportAssignment ( node : ExportAssignment ) {
957988 if ( ! container . symbol || ! container . symbol . exports ) {
958989 // Export assignment in some sort of block construct
@@ -985,6 +1016,32 @@ namespace ts {
9851016 }
9861017 }
9871018
1019+ function setCommonJsModuleIndicator ( node : Node ) {
1020+ if ( ! file . commonJsModuleIndicator ) {
1021+ file . commonJsModuleIndicator = node ;
1022+ bindSourceFileAsExternalModule ( ) ;
1023+ }
1024+ }
1025+
1026+ function bindExportsPropertyAssignment ( node : BinaryExpression ) {
1027+ // When we create a property via 'exports.foo = bar', the 'exports.foo' property access
1028+ // expression is the declaration
1029+ setCommonJsModuleIndicator ( node ) ;
1030+ declareSymbol ( file . symbol . exports , file . symbol , < PropertyAccessExpression > node . left , SymbolFlags . Property | SymbolFlags . Export , SymbolFlags . None ) ;
1031+ }
1032+
1033+ function bindModuleExportsAssignment ( node : BinaryExpression ) {
1034+ // 'module.exports = expr' assignment
1035+ setCommonJsModuleIndicator ( node ) ;
1036+ declareSymbol ( file . symbol . exports , file . symbol , node , SymbolFlags . None , SymbolFlags . None ) ;
1037+ }
1038+
1039+ function bindCallExpression ( node : CallExpression ) {
1040+ if ( isRequireCall ( node ) ) {
1041+ setCommonJsModuleIndicator ( node ) ;
1042+ }
1043+ }
1044+
9881045 function bindClassLikeDeclaration ( node : ClassLikeDeclaration ) {
9891046 if ( node . kind === SyntaxKind . ClassDeclaration ) {
9901047 bindBlockScopedDeclaration ( node , SymbolFlags . Class , SymbolFlags . ClassExcludes ) ;
0 commit comments