@@ -273,9 +273,6 @@ namespace ts {
273273 return getEscapedTextOfIdentifierOrLiteral ( < Identifier | LiteralExpression > name ) ;
274274 }
275275 switch ( node . kind ) {
276- case SyntaxKind . Identifier :
277- // TODO: THIS IS WRONG
278- return ( node as any as Identifier ) . escapedText ;
279276 case SyntaxKind . Constructor :
280277 return InternalSymbolName . Constructor ;
281278 case SyntaxKind . FunctionType :
@@ -2014,8 +2011,7 @@ namespace ts {
20142011 node . flowNode = currentFlow ;
20152012 }
20162013 if ( isSpecialPropertyDeclaration ( node as PropertyAccessExpression ) ) {
2017- // TODO: this is wrong now that I allow it anywhere
2018- bindThisPropertyAssignment ( node as PropertyAccessExpression ) ;
2014+ bindSpecialPropertyDeclaration ( node as PropertyAccessExpression ) ;
20192015 }
20202016 break ;
20212017 case SyntaxKind . BinaryExpression :
@@ -2351,6 +2347,17 @@ namespace ts {
23512347 }
23522348 }
23532349
2350+ function bindSpecialPropertyDeclaration ( node : PropertyAccessExpression ) {
2351+ Debug . assert ( isInJavaScriptFile ( node ) ) ;
2352+ if ( node . expression . kind === SyntaxKind . ThisKeyword ) {
2353+ bindThisPropertyAssignment ( node ) ;
2354+ }
2355+ else if ( ( node . expression . kind === SyntaxKind . Identifier || node . expression . kind === SyntaxKind . PropertyAccessExpression ) &&
2356+ node . parent . parent . kind === SyntaxKind . SourceFile ) {
2357+ bindStaticPropertyAssignment ( node ) ;
2358+ }
2359+ }
2360+
23542361 function bindPrototypePropertyAssignment ( node : BinaryExpression ) {
23552362 // We saw a node of the form 'x.prototype.y = z'. Declare a 'member' y on x if x was a function.
23562363
@@ -2368,24 +2375,27 @@ namespace ts {
23682375 bindPropertyAssignment ( constructorFunction . escapedText , leftSideOfAssignment , /*isPrototypeProperty*/ true ) ;
23692376 }
23702377
2371- function bindStaticPropertyAssignment ( node : BinaryExpression ) {
2372- // We saw a node of the form 'x.y = z'. Declare a 'member' y on x if x was a function.
2373-
2374- // Look up the function in the local scope, since prototype assignments should
2378+ /**
2379+ * For nodes like `x.y = z`, declare a member 'y' on 'x' if x was a function.
2380+ * Also works for expression statements preceded by JSDoc, like / ** @type number * / x.y;
2381+ */
2382+ function bindStaticPropertyAssignment ( node : BinaryExpression | PropertyAccessExpression ) {
2383+ // Look up the function in the local scope, since static assignments should
23752384 // follow the function declaration
2376- const leftSideOfAssignment = node . left as PropertyAccessExpression ;
2385+ const leftSideOfAssignment = node . kind === SyntaxKind . PropertyAccessExpression ? node : node . left as PropertyAccessExpression ;
23772386 const target = leftSideOfAssignment . expression ;
23782387
23792388 if ( isIdentifier ( target ) ) {
23802389 // Fix up parent pointers since we're going to use these nodes before we bind into them
2381- leftSideOfAssignment . parent = node ;
23822390 target . parent = leftSideOfAssignment ;
2383-
2391+ if ( node . kind === SyntaxKind . BinaryExpression ) {
2392+ leftSideOfAssignment . parent = node ;
2393+ }
23842394 if ( isNameOfExportsOrModuleExportsAliasDeclaration ( target ) ) {
23852395 // This can be an alias for the 'exports' or 'module.exports' names, e.g.
23862396 // var util = module.exports;
23872397 // util.property = function ...
2388- bindExportsPropertyAssignment ( node ) ;
2398+ bindExportsPropertyAssignment ( node as BinaryExpression ) ;
23892399 }
23902400 else {
23912401 bindPropertyAssignment ( target . escapedText , leftSideOfAssignment , /*isPrototypeProperty*/ false ) ;
@@ -2403,14 +2413,19 @@ namespace ts {
24032413 if ( targetSymbol && isDeclarationOfFunctionOrClassExpression ( targetSymbol ) ) {
24042414 targetSymbol = ( targetSymbol . valueDeclaration as VariableDeclaration ) . initializer . symbol ;
24052415 }
2406- Debug . assert ( propertyAccessExpression . parent . kind === SyntaxKind . BinaryExpression ) ;
2407- if ( ! isPrototypeProperty &&
2408- ( ! targetSymbol || ! ( targetSymbol . flags & SymbolFlags . Namespace ) ) &&
2409- // TODO: Rewrite to be easier to read
2410- ( ( propertyAccessExpression . parent as BinaryExpression ) . right . kind === SyntaxKind . ClassExpression || ( propertyAccessExpression . parent as BinaryExpression ) . right . kind === SyntaxKind . FunctionExpression ) &&
2411- propertyAccessExpression . parent . parent . parent . kind === SyntaxKind . SourceFile ) {
2416+ Debug . assert ( propertyAccessExpression . parent . kind === SyntaxKind . BinaryExpression || propertyAccessExpression . parent . kind === SyntaxKind . ExpressionStatement ) ;
2417+ let isLegalPosition : boolean ;
2418+ if ( propertyAccessExpression . parent . kind === SyntaxKind . BinaryExpression ) {
2419+ const initializerKind = ( propertyAccessExpression . parent as BinaryExpression ) . right . kind ;
2420+ isLegalPosition = ( initializerKind === SyntaxKind . ClassExpression || initializerKind === SyntaxKind . FunctionExpression ) &&
2421+ propertyAccessExpression . parent . parent . parent . kind === SyntaxKind . SourceFile ;
2422+ }
2423+ else {
2424+ isLegalPosition = propertyAccessExpression . parent . parent . kind === SyntaxKind . SourceFile ;
2425+ }
2426+ if ( ! isPrototypeProperty && ( ! targetSymbol || ! ( targetSymbol . flags & SymbolFlags . Namespace ) ) && isLegalPosition ) {
24122427 // TODO: Update refactoring to understand that ES5 classes now have statics in a namespace instead
2413- const hasExportModifier = getCombinedModifierFlags ( targetSymbol . valueDeclaration ) & ModifierFlags . Export ;
2428+ const hasExportModifier = targetSymbol && getCombinedModifierFlags ( targetSymbol . valueDeclaration ) & ModifierFlags . Export ;
24142429 Debug . assert ( isIdentifier ( propertyAccessExpression . expression ) ) ;
24152430 Debug . assertEqual ( propertyAccessExpression . expression . kind , SyntaxKind . Identifier ) ;
24162431 targetSymbol = declareModuleMember ( propertyAccessExpression . expression as Identifier , SymbolFlags . NamespaceModule , SymbolFlags . NamespaceModuleExcludes , hasExportModifier ) ;
0 commit comments