@@ -1359,60 +1359,139 @@ namespace ts {
1359
1359
} ;
1360
1360
}
1361
1361
1362
- /*
1363
- const classMembers: TypeElement[]; // TODO: this
1364
- const implementedInterfaceMembers: TypeElement[] = [];
1365
- const parentAbstractMembers: TypeElement[] = []
1366
- const missingMembers: TypeElement[] = [];
1367
- // const typeWiththis = checker.getTypeWithThisArgument(classType);
1368
- // const staticType = <ObjectType>checker.getTypeOfSymbol(symbol);
1369
- // const classType = <InterfaceType>checker.getTypeAtLocation(classDecl);
1370
- */
1371
-
1372
- export function getUnimplementedMemberChanges ( classDecl : ClassDeclaration , checker : TypeChecker ) : TextChange [ ] {
1362
+ /*
1363
+ const classMembers: TypeElement[]; // TODO: this
1364
+ const implementedInterfaceMembers: TypeElement[] = [];
1365
+ const parentAbstractMembers: TypeElement[] = []
1366
+ const missingMembers: TypeElement[] = [];
1367
+ // const typeWiththis = checker.getTypeWithThisArgument(classType);
1368
+ // const staticType = <ObjectType>checker.getTypeOfSymbol(symbol);
1369
+ // const classType = <InterfaceType>checker.getTypeAtLocation(classDecl);
1370
+ */
1371
+
1372
+ // TODO: (arozga) Get changes for interface as well.
1373
+ // const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
1374
+ export function getMissingAbstractMemberInsertion ( classDecl : ClassDeclaration , checker : TypeChecker , newlineChar : string ) : string {
1373
1375
const baseTypeNode : ExpressionWithTypeArguments = getClassExtendsHeritageClauseElement ( classDecl ) ;
1374
1376
1375
- if ( ! baseTypeNode )
1376
- {
1377
- return [ ] ;
1377
+ if ( ! baseTypeNode ) {
1378
+ return "" ; // TODO: (arozga) undefined?
1378
1379
}
1379
- const classSymbol = checker . getSymbolAtLocation ( classDecl ) ;
1380
- const classType = < InterfaceType > checker . getDeclaredTypeOfSymbol ( classSymbol ) ;
1381
-
1382
- const baseTypes = checker . getBaseTypes ( classType ) ;
1383
- Debug . assert ( baseTypes . length === 1 ) ;
1384
- const baseType = baseTypes [ 0 ] ;
1380
+ const classSymbol = checker . getSymbolOfNode ( classDecl ) ;
1381
+ // TODO: (arozga) Should this be getTypeOfSymbol?
1382
+ // We want the once that gets the members. I think that's the instance, so we want typeofsymbol.
1383
+ const classType = < InterfaceType > checker . getTypeOfSymbol ( classSymbol ) ;
1384
+
1385
+ const baseTypes = checker . getBaseTypes ( classType ) ;
1386
+ Debug . assert ( baseTypes . length === 1 ) ;
1387
+ const baseType = baseTypes [ 0 ] ;
1388
+
1389
+ // TODO: (arozga) Does this give us the correct instantiations for generics?
1390
+ // TODO: (arozga) If not, how do we get them?
1391
+ const resolvedClassType = checker . resolveStructuredTypeMembers ( classType ) ;
1392
+ const resolvedBaseType = checker . resolveStructuredTypeMembers ( baseType ) ;
1385
1393
1386
- const resolvedClassType = checker . resolveStructuredTypeMembers ( classType ) ;
1387
- const resolvedBaseType = checker . resolveStructuredTypeMembers ( baseType ) ;
1394
+ // TODO: (arozga) handle private members as well.
1395
+ const missingMembers = filterMissingMembers ( filterAbstract ( resolvedBaseType . members ) , resolvedClassType . members ) ;
1388
1396
1389
- const missingMembers = filterMissingMembers ( resolvedClassType . members , resolvedBaseType . members ) ;
1390
- return insertionsForMembers ( missingMembers ) ;
1397
+ return insertionsForMembers ( missingMembers , newlineChar ) ;
1398
+ }
1399
+
1400
+ function filterSymbolMapByDecl ( symbolMap : Map < Symbol > , pred : ( decl : Declaration ) => boolean ) : Map < Symbol > {
1401
+ let result = createMap < Symbol > ( ) ;
1402
+ for ( const key in symbolMap ) {
1403
+ const decl = symbolMap [ key ] . getDeclarations ( ) ;
1404
+ Debug . assert ( ! ! ( decl && decl . length ) ) ;
1405
+ if ( pred ( decl [ 0 ] ) ) {
1406
+ result [ key ] = symbolMap [ key ] ;
1407
+ }
1391
1408
}
1409
+ return result ;
1410
+ }
1411
+
1412
+ function filterAbstract ( symbolMap : Map < Symbol > ) {
1413
+ return filterSymbolMapByDecl ( symbolMap , decl => ! ! ( getModifierFlags ( decl ) & ModifierFlags . Abstract ) ) ;
1414
+ }
1392
1415
1393
- // TODO: (arozga) Get changes for interface as well.
1394
- // const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl );
1416
+ function filterNonPrivate ( symbolMap : Map < Symbol > ) {
1417
+ return filterSymbolMapByDecl ( symbolMap , decl => ! ( getModifierFlags ( decl ) & ModifierFlags . Private ) ) ;
1395
1418
}
1396
1419
1397
- function insertionsForMembers ( symbols : Symbol [ ] ) : TextChange [ ] {
1398
- let changes : TextChange [ ] = [ ] ;
1420
+ function insertionsForMembers ( symbols : Symbol [ ] , newlineChar : string ) : string {
1421
+ let insertion = "" ;
1399
1422
for ( const symbol of symbols ) {
1400
- const decl = getdeclaration
1401
- switch ( member . kind ) {
1402
- case SyntaxKind . PropertySignature :
1403
- case SyntaxKind . PropertyDeclaration :
1404
- break ;
1405
- case SyntaxKind . MethodSignature :
1406
- case SyntaxKind . MethodDeclaration :
1407
- break ;
1408
- default :
1409
- break ;
1423
+ const decls = symbol . getDeclarations ( ) ;
1424
+ if ( ! ( decls && decls . length ) ) {
1425
+ return "" ;
1426
+ }
1427
+ insertion = insertion . concat ( getInsertion ( decls [ 0 ] , newlineChar ) ) ;
1428
+ }
1429
+ return insertion ;
1430
+ }
1431
+
1432
+ const stubMethodBody = "{\nthrow new Error('Method not Implemented');\n}" ;
1433
+ const functionPrefix = "function " ;
1434
+
1435
+ // TODO: (arozga) needs a re-write that takes the symbol and type (with type parameter instantiations)
1436
+ // and figures out how to print it.
1437
+ function getInsertion ( decl : Declaration , newlineChar : string ) : string {
1438
+ let insertion = "" ;
1439
+ switch ( decl . kind ) {
1440
+ case SyntaxKind . PropertySignature :
1441
+ case SyntaxKind . PropertyDeclaration :
1442
+ insertion = decl . getText ( ) ;
1443
+
1444
+ // TODO: (arozga) need to remove trailing comma
1445
+ if ( insertion . length && insertion . charAt ( insertion . length - 1 ) !== ";" ) {
1446
+ insertion += ";" ;
1447
+ }
1448
+ return insertion ;
1449
+ case SyntaxKind . MethodSignature :
1450
+ case SyntaxKind . MethodDeclaration :
1451
+ const method = decl as MethodSignature | MethodDeclaration ;
1452
+ // TODO: (arozga) figure out how to do proper instantiation of generic values based on heritage clause.
1453
+ const typeParameters = method . typeParameters && method . typeParameters . length > 0 ?
1454
+ getCommaSeparatedString ( method . typeParameters . map ( param => param . getText ( ) ) , "<" , ">" ) : "" ;
1455
+ const parameters = getCommaSeparatedString ( method . parameters . map ( param => param . getText ( ) ) , "(" , ")" ) ;
1456
+ insertion += functionPrefix + method . name + typeParameters + parameters + stubMethodBody ;
1457
+ break ;
1458
+ default :
1459
+ break ;
1460
+ }
1461
+
1462
+ return insertion += newlineChar ;
1463
+
1464
+ /**
1465
+ * Flattens params into a comma-separated list, sandwiched by prefix
1466
+ * and suffix on either end.
1467
+ */
1468
+ function getCommaSeparatedString ( params : string [ ] , prefix : string , suffix : string ) {
1469
+ let result = prefix ;
1470
+ for ( let i = 0 ; params && i < params . length ; ++ i ) {
1471
+ result += ( i > 0 ? "," : "" ) + params [ i ] ;
1472
+ }
1473
+ return result + suffix ;
1474
+ }
1475
+ }
1476
+
1477
+ /**
1478
+ * Finds the symbols in source but not target.
1479
+ */
1480
+ function filterMissingMembers ( sourceSymbols : Map < Symbol > , targetSymbols : Map < Symbol > ) : Symbol [ ] {
1481
+ let result : Symbol [ ] = [ ] ;
1482
+ outer:
1483
+ for ( const sourceName in sourceSymbols ) {
1484
+ for ( const targetName in targetSymbols ) {
1485
+ if ( sourceName === targetName ) {
1486
+ continue outer;
1487
+ }
1410
1488
}
1489
+ result . push ( sourceSymbols [ sourceName ] ) ;
1411
1490
}
1412
- return changes ;
1491
+ return result ;
1413
1492
}
1414
1493
1415
- // TODO: (arozga) simplify to quadratic time solution.
1494
+ /*
1416
1495
function filterMissingMembers(sourceSymbols: Map<Symbol>, targetSymbols: Map<Symbol>): Symbol[] {
1417
1496
let missingMembers: Symbol[] = [];
1418
1497
const sortedSourceKeys = Object.keys(sourceSymbols).sort();
@@ -1439,6 +1518,7 @@ namespace ts {
1439
1518
1440
1519
return missingMembers;
1441
1520
}
1521
+ */
1442
1522
1443
1523
/**
1444
1524
* Generates codefix changes to insert
@@ -1456,19 +1536,22 @@ namespace ts {
1456
1536
for ( const member of missingMembers ) {
1457
1537
if ( member . kind === SyntaxKind . PropertySignature || member . kind === SyntaxKind . PropertyDeclaration ) {
1458
1538
const interfaceProperty = < PropertySignature > member ;
1459
- if ( trackingAddedMembers . indexOf ( interfaceProperty . name . getText ( ) ) === - 1 ) {
1460
- let propertyText = "" ;
1461
- if ( reference ) {
1462
- propertyText = `${ interfaceProperty . name . getText ( ) } : ${ getDefaultValue ( interfaceProperty . type . kind ) } ,${ newLineCharacter } ` ;
1463
- }
1464
- else {
1465
- propertyText = interfaceProperty . getText ( ) ;
1466
- const stringToAdd = ! ( propertyText . match ( / ; $ / ) ) ? `;${ newLineCharacter } ` : newLineCharacter ;
1467
- propertyText += stringToAdd ;
1468
- }
1469
- changesArray . push ( { newText : propertyText , span : { start : startPos , length : 0 } } ) ;
1470
- trackingAddedMembers . push ( interfaceProperty . name . getText ( ) ) ;
1539
+ if ( trackingAddedMembers . indexOf ( interfaceProperty . name . getText ( ) ) !== - 1 ) {
1540
+ continue ;
1541
+ }
1542
+
1543
+ let propertyText = "" ;
1544
+ if ( reference ) {
1545
+ propertyText = `${ interfaceProperty . name . getText ( ) } : ${ getDefaultValue ( interfaceProperty . type . kind ) } ,${ newLineCharacter } ` ;
1471
1546
}
1547
+ else {
1548
+ propertyText = interfaceProperty . getText ( ) ;
1549
+ const stringToAdd = ! ( propertyText . match ( / ; $ / ) ) ? `;${ newLineCharacter } ` : newLineCharacter ;
1550
+ propertyText += stringToAdd ;
1551
+ }
1552
+ changesArray . push ( { newText : propertyText , span : { start : startPos , length : 0 } } ) ;
1553
+ trackingAddedMembers . push ( interfaceProperty . name . getText ( ) ) ;
1554
+
1472
1555
}
1473
1556
else if ( member . kind === SyntaxKind . MethodSignature || member . kind === SyntaxKind . MethodDeclaration ) {
1474
1557
const interfaceMethod = < MethodSignature > member ;
0 commit comments