@@ -222,8 +222,21 @@ namespace ts {
222
222
case SyntaxKind . ExportAssignment :
223
223
return ( < ExportAssignment > node ) . isExportEquals ? "export=" : "default" ;
224
224
case SyntaxKind . BinaryExpression :
225
- // Binary expression case is for JS module 'module.exports = expr'
226
- return "export=" ;
225
+ switch ( getSpecialPropertyAssignmentKind ( node ) ) {
226
+ case SpecialPropertyAssignmentKind . ModuleExports :
227
+ // module.exports = ...
228
+ return "export=" ;
229
+ case SpecialPropertyAssignmentKind . ExportsProperty :
230
+ case SpecialPropertyAssignmentKind . ThisProperty :
231
+ // exports.x = ... or this.y = ...
232
+ return ( ( node as BinaryExpression ) . left as PropertyAccessExpression ) . name . text ;
233
+ case SpecialPropertyAssignmentKind . PrototypeProperty :
234
+ // className.prototype.methodName = ...
235
+ return ( ( ( node as BinaryExpression ) . left as PropertyAccessExpression ) . expression as PropertyAccessExpression ) . name . text ;
236
+ }
237
+ Debug . fail ( "Unknown binary declaration kind" ) ;
238
+ break ;
239
+
227
240
case SyntaxKind . FunctionDeclaration :
228
241
case SyntaxKind . ClassDeclaration :
229
242
return node . flags & NodeFlags . Default ? "default" : undefined ;
@@ -1166,11 +1179,25 @@ namespace ts {
1166
1179
return checkStrictModeIdentifier ( < Identifier > node ) ;
1167
1180
case SyntaxKind . BinaryExpression :
1168
1181
if ( isInJavaScriptFile ( node ) ) {
1169
- if ( isExportsPropertyAssignment ( node ) ) {
1170
- bindExportsPropertyAssignment ( < BinaryExpression > node ) ;
1171
- }
1172
- else if ( isModuleExportsAssignment ( node ) ) {
1173
- bindModuleExportsAssignment ( < BinaryExpression > node ) ;
1182
+ const specialKind = getSpecialPropertyAssignmentKind ( node ) ;
1183
+ switch ( specialKind ) {
1184
+ case SpecialPropertyAssignmentKind . ExportsProperty :
1185
+ bindExportsPropertyAssignment ( < BinaryExpression > node ) ;
1186
+ break ;
1187
+ case SpecialPropertyAssignmentKind . ModuleExports :
1188
+ bindModuleExportsAssignment ( < BinaryExpression > node ) ;
1189
+ break ;
1190
+ case SpecialPropertyAssignmentKind . PrototypeProperty :
1191
+ bindPrototypePropertyAssignment ( < BinaryExpression > node ) ;
1192
+ break ;
1193
+ case SpecialPropertyAssignmentKind . ThisProperty :
1194
+ bindThisPropertyAssignment ( < BinaryExpression > node ) ;
1195
+ break ;
1196
+ case SpecialPropertyAssignmentKind . None :
1197
+ // Nothing to do
1198
+ break ;
1199
+ default :
1200
+ Debug . fail ( "Unknown special property assignment kind" ) ;
1174
1201
}
1175
1202
}
1176
1203
return checkStrictModeBinaryExpression ( < BinaryExpression > node ) ;
@@ -1189,7 +1216,8 @@ namespace ts {
1189
1216
case SyntaxKind . ThisType :
1190
1217
seenThisKeyword = true ;
1191
1218
return ;
1192
-
1219
+ case SyntaxKind . TypePredicate :
1220
+ return checkTypePredicate ( node as TypePredicateNode ) ;
1193
1221
case SyntaxKind . TypeParameter :
1194
1222
return declareSymbolAndAddToSymbolTable ( < Declaration > node , SymbolFlags . TypeParameter , SymbolFlags . TypeParameterExcludes ) ;
1195
1223
case SyntaxKind . Parameter :
@@ -1275,6 +1303,17 @@ namespace ts {
1275
1303
}
1276
1304
}
1277
1305
1306
+ function checkTypePredicate ( node : TypePredicateNode ) {
1307
+ const { parameterName, type } = node ;
1308
+ if ( parameterName && parameterName . kind === SyntaxKind . Identifier ) {
1309
+ checkStrictModeIdentifier ( parameterName as Identifier ) ;
1310
+ }
1311
+ if ( parameterName && parameterName . kind === SyntaxKind . ThisType ) {
1312
+ seenThisKeyword = true ;
1313
+ }
1314
+ bind ( type ) ;
1315
+ }
1316
+
1278
1317
function bindSourceFileIfExternalModule ( ) {
1279
1318
setExportContextFlag ( file ) ;
1280
1319
if ( isExternalModule ( file ) ) {
@@ -1339,6 +1378,34 @@ namespace ts {
1339
1378
bindExportAssignment ( node ) ;
1340
1379
}
1341
1380
1381
+ function bindThisPropertyAssignment ( node : BinaryExpression ) {
1382
+ // Declare a 'member' in case it turns out the container was an ES5 class
1383
+ if ( container . kind === SyntaxKind . FunctionExpression || container . kind === SyntaxKind . FunctionDeclaration ) {
1384
+ container . symbol . members = container . symbol . members || { } ;
1385
+ declareSymbol ( container . symbol . members , container . symbol , node , SymbolFlags . Property , SymbolFlags . PropertyExcludes ) ;
1386
+ }
1387
+ }
1388
+
1389
+ function bindPrototypePropertyAssignment ( node : BinaryExpression ) {
1390
+ // We saw a node of the form 'x.prototype.y = z'. Declare a 'member' y on x if x was a function.
1391
+
1392
+ // Look up the function in the local scope, since prototype assignments should
1393
+ // follow the function declaration
1394
+ const classId = < Identifier > ( < PropertyAccessExpression > ( < PropertyAccessExpression > node . left ) . expression ) . expression ;
1395
+ const funcSymbol = container . locals [ classId . text ] ;
1396
+ if ( ! funcSymbol || ! ( funcSymbol . flags & SymbolFlags . Function ) ) {
1397
+ return ;
1398
+ }
1399
+
1400
+ // Set up the members collection if it doesn't exist already
1401
+ if ( ! funcSymbol . members ) {
1402
+ funcSymbol . members = { } ;
1403
+ }
1404
+
1405
+ // Declare the method/property
1406
+ declareSymbol ( funcSymbol . members , funcSymbol , < PropertyAccessExpression > node . left , SymbolFlags . Property , SymbolFlags . PropertyExcludes ) ;
1407
+ }
1408
+
1342
1409
function bindCallExpression ( node : CallExpression ) {
1343
1410
// We're only inspecting call expressions to detect CommonJS modules, so we can skip
1344
1411
// this check if we've already seen the module indicator
0 commit comments