@@ -15,24 +15,24 @@ namespace ts.codefix {
1515 } ) ;
1616
1717 interface SynthIdentifier {
18- identifier : Identifier ;
19- types : Type [ ] ;
18+ readonly identifier : Identifier ;
19+ readonly types : Type [ ] ;
2020 numberOfAssignmentsOriginal : number ; // number of times the variable should be assigned in the refactor
2121 }
2222
2323 interface SymbolAndIdentifier {
24- identifier : Identifier ;
25- symbol : Symbol ;
24+ readonly identifier : Identifier ;
25+ readonly symbol : Symbol ;
2626 }
2727
2828 interface Transformer {
29- checker : TypeChecker ;
30- synthNamesMap : Map < SynthIdentifier > ; // keys are the symbol id of the identifier
31- allVarNames : SymbolAndIdentifier [ ] ;
32- setOfExpressionsToReturn : Map < true > ; // keys are the node ids of the expressions
33- constIdentifiers : Identifier [ ] ;
34- originalTypeMap : Map < Type > ; // keys are the node id of the identifier
35- isInJSFile : boolean ;
29+ readonly checker : TypeChecker ;
30+ readonly synthNamesMap : Map < SynthIdentifier > ; // keys are the symbol id of the identifier
31+ readonly allVarNames : ReadonlyArray < SymbolAndIdentifier > ;
32+ readonly setOfExpressionsToReturn : ReadonlyMap < true > ; // keys are the node ids of the expressions
33+ readonly constIdentifiers : Identifier [ ] ;
34+ readonly originalTypeMap : ReadonlyMap < Type > ; // keys are the node id of the identifier
35+ readonly isInJSFile : boolean ;
3636 }
3737
3838 function convertToAsyncFunction ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , position : number , checker : TypeChecker , context : CodeFixContextBase ) : void {
@@ -61,14 +61,14 @@ namespace ts.codefix {
6161 const functionToConvertRenamed : FunctionLikeDeclaration = renameCollidingVarNames ( functionToConvert , checker , synthNamesMap , context , setOfExpressionsToReturn , originalTypeMap , allVarNames ) ;
6262 const constIdentifiers = getConstIdentifiers ( synthNamesMap ) ;
6363 const returnStatements = getReturnStatementsWithPromiseHandlers ( functionToConvertRenamed ) ;
64- const transformer = { checker, synthNamesMap, allVarNames, setOfExpressionsToReturn, constIdentifiers, originalTypeMap, isInJSFile : isInJavascript } ;
64+ const transformer : Transformer = { checker, synthNamesMap, allVarNames, setOfExpressionsToReturn, constIdentifiers, originalTypeMap, isInJSFile : isInJavascript } ;
6565
6666 if ( ! returnStatements . length ) {
6767 return ;
6868 }
6969
7070 // add the async keyword
71- changes . insertModifierBefore ( sourceFile , SyntaxKind . AsyncKeyword , functionToConvert ) ;
71+ changes . insertLastModifierBefore ( sourceFile , SyntaxKind . AsyncKeyword , functionToConvert ) ;
7272
7373 function startTransformation ( node : CallExpression , nodeToReplace : Node ) {
7474 const newNodes = transformExpression ( node , transformer , node ) ;
@@ -88,7 +88,7 @@ namespace ts.codefix {
8888 }
8989
9090 // Returns the identifiers that are never reassigned in the refactor
91- function getConstIdentifiers ( synthNamesMap : Map < SynthIdentifier > ) : Identifier [ ] {
91+ function getConstIdentifiers ( synthNamesMap : ReadonlyMap < SynthIdentifier > ) : Identifier [ ] {
9292 const constIdentifiers : Identifier [ ] = [ ] ;
9393 synthNamesMap . forEach ( ( val ) => {
9494 if ( val . numberOfAssignmentsOriginal === 0 ) {
@@ -249,18 +249,18 @@ namespace ts.codefix {
249249 }
250250 }
251251
252- function getNewNameIfConflict ( name : Identifier , originalNames : Map < Symbol [ ] > ) : SynthIdentifier {
253- const numVarsSameName = ( originalNames . get ( name . text ) || [ ] ) . length ;
252+ function getNewNameIfConflict ( name : Identifier , originalNames : ReadonlyMap < Symbol [ ] > ) : SynthIdentifier {
253+ const numVarsSameName = ( originalNames . get ( name . text ) || emptyArray ) . length ;
254254 const numberOfAssignmentsOriginal = 0 ;
255255 const identifier = numVarsSameName === 0 ? name : createIdentifier ( name . text + "_" + numVarsSameName ) ;
256256 return { identifier, types : [ ] , numberOfAssignmentsOriginal } ;
257257 }
258258
259259 // dispatch function to recursively build the refactoring
260260 // should be kept up to date with isFixablePromiseHandler in suggestionDiagnostics.ts
261- function transformExpression ( node : Expression , transformer : Transformer , outermostParent : CallExpression , prevArgName ?: SynthIdentifier ) : Statement [ ] {
261+ function transformExpression ( node : Expression , transformer : Transformer , outermostParent : CallExpression , prevArgName ?: SynthIdentifier ) : ReadonlyArray < Statement > {
262262 if ( ! node ) {
263- return [ ] ;
263+ return emptyArray ;
264264 }
265265
266266 const originalType = isIdentifier ( node ) && transformer . originalTypeMap . get ( getNodeId ( node ) . toString ( ) ) ;
@@ -280,10 +280,10 @@ namespace ts.codefix {
280280 }
281281
282282 codeActionSucceeded = false ;
283- return [ ] ;
283+ return emptyArray ;
284284 }
285285
286- function transformCatch ( node : CallExpression , transformer : Transformer , prevArgName ?: SynthIdentifier ) : Statement [ ] {
286+ function transformCatch ( node : CallExpression , transformer : Transformer , prevArgName ?: SynthIdentifier ) : ReadonlyArray < Statement > {
287287 const func = node . arguments [ 0 ] ;
288288 const argName = getArgName ( func , transformer ) ;
289289 const shouldReturn = transformer . setOfExpressionsToReturn . get ( getNodeId ( node ) . toString ( ) ) ;
@@ -336,7 +336,7 @@ namespace ts.codefix {
336336 return newSynthName ;
337337 }
338338
339- function transformThen ( node : CallExpression , transformer : Transformer , outermostParent : CallExpression , prevArgName ?: SynthIdentifier ) : Statement [ ] {
339+ function transformThen ( node : CallExpression , transformer : Transformer , outermostParent : CallExpression , prevArgName ?: SynthIdentifier ) : ReadonlyArray < Statement > {
340340 const [ res , rej ] = node . arguments ;
341341
342342 if ( ! res ) {
@@ -356,18 +356,18 @@ namespace ts.codefix {
356356 const catchArg = argNameRej ? argNameRej . identifier . text : "e" ;
357357 const catchClause = createCatchClause ( catchArg , createBlock ( transformationBody2 ) ) ;
358358
359- return [ createTry ( tryBlock , catchClause , /* finallyBlock */ undefined ) as Statement ] ;
359+ return [ createTry ( tryBlock , catchClause , /* finallyBlock */ undefined ) ] ;
360360 }
361361
362362 return transformExpression ( node . expression , transformer , node , argNameRes ) . concat ( transformationBody ) ;
363363 }
364364
365- function getFlagOfIdentifier ( node : Identifier , constIdentifiers : Identifier [ ] ) : NodeFlags {
365+ function getFlagOfIdentifier ( node : Identifier , constIdentifiers : ReadonlyArray < Identifier > ) : NodeFlags {
366366 const inArr : boolean = constIdentifiers . some ( elem => elem . text === node . text ) ;
367367 return inArr ? NodeFlags . Const : NodeFlags . Let ;
368368 }
369369
370- function transformPromiseCall ( node : Expression , transformer : Transformer , prevArgName ?: SynthIdentifier ) : Statement [ ] {
370+ function transformPromiseCall ( node : Expression , transformer : Transformer , prevArgName ?: SynthIdentifier ) : ReadonlyArray < Statement > {
371371 const shouldReturn = transformer . setOfExpressionsToReturn . get ( getNodeId ( node ) . toString ( ) ) ;
372372 // the identifier is empty when the handler (.then()) ignores the argument - In this situation we do not need to save the result of the promise returning call
373373 const originalNodeParent = node . original ? node . original . parent : node . parent ;
@@ -381,23 +381,23 @@ namespace ts.codefix {
381381 return [ createReturn ( getSynthesizedDeepClone ( node ) ) ] ;
382382 }
383383
384- function createTransformedStatement ( prevArgName : SynthIdentifier | undefined , rightHandSide : Expression , transformer : Transformer ) : MutableNodeArray < Statement > {
384+ function createTransformedStatement ( prevArgName : SynthIdentifier | undefined , rightHandSide : Expression , transformer : Transformer ) : ReadonlyArray < Statement > {
385385 if ( ! prevArgName || prevArgName . identifier . text . length === 0 ) {
386386 // if there's no argName to assign to, there still might be side effects
387- return createNodeArray ( [ createStatement ( rightHandSide ) ] ) ;
387+ return [ createStatement ( rightHandSide ) ] ;
388388 }
389389
390390 if ( prevArgName . types . length < prevArgName . numberOfAssignmentsOriginal ) {
391391 // if the variable has already been declared, we don't need "let" or "const"
392- return createNodeArray ( [ createStatement ( createAssignment ( getSynthesizedDeepClone ( prevArgName . identifier ) , rightHandSide ) ) ] ) ;
392+ return [ createStatement ( createAssignment ( getSynthesizedDeepClone ( prevArgName . identifier ) , rightHandSide ) ) ] ;
393393 }
394394
395- return createNodeArray ( [ createVariableStatement ( /*modifiers*/ undefined ,
396- ( createVariableDeclarationList ( [ createVariableDeclaration ( getSynthesizedDeepClone ( prevArgName . identifier ) , /*type*/ undefined , rightHandSide ) ] , getFlagOfIdentifier ( prevArgName . identifier , transformer . constIdentifiers ) ) ) ) ] ) ;
395+ return [ createVariableStatement ( /*modifiers*/ undefined ,
396+ ( createVariableDeclarationList ( [ createVariableDeclaration ( getSynthesizedDeepClone ( prevArgName . identifier ) , /*type*/ undefined , rightHandSide ) ] , getFlagOfIdentifier ( prevArgName . identifier , transformer . constIdentifiers ) ) ) ) ] ;
397397 }
398398
399399 // should be kept up to date with isFixablePromiseArgument in suggestionDiagnostics.ts
400- function getTransformationBody ( func : Expression , prevArgName : SynthIdentifier | undefined , argName : SynthIdentifier | undefined , parent : CallExpression , transformer : Transformer ) : NodeArray < Statement > {
400+ function getTransformationBody ( func : Expression , prevArgName : SynthIdentifier | undefined , argName : SynthIdentifier | undefined , parent : CallExpression , transformer : Transformer ) : ReadonlyArray < Statement > {
401401
402402 const shouldReturn = transformer . setOfExpressionsToReturn . get ( getNodeId ( parent ) . toString ( ) ) ;
403403 switch ( func . kind ) {
@@ -410,9 +410,9 @@ namespace ts.codefix {
410410 break ;
411411 }
412412
413- const synthCall = createCall ( getSynthesizedDeepClone ( func ) as Identifier , /*typeArguments*/ undefined , argName ? [ argName . identifier ] : [ ] ) ;
413+ const synthCall = createCall ( getSynthesizedDeepClone ( func as Identifier ) , /*typeArguments*/ undefined , argName ? [ argName . identifier ] : emptyArray ) ;
414414 if ( shouldReturn ) {
415- return createNodeArray ( [ createReturn ( synthCall ) ] ) ;
415+ return [ createReturn ( synthCall ) ] ;
416416 }
417417
418418 const type = transformer . originalTypeMap . get ( getNodeId ( func ) . toString ( ) ) || transformer . checker . getTypeAtLocation ( func ) ;
@@ -450,15 +450,19 @@ namespace ts.codefix {
450450 }
451451 }
452452
453- return shouldReturn ? getSynthesizedDeepClones ( createNodeArray ( refactoredStmts ) ) :
454- removeReturns ( createNodeArray ( refactoredStmts ) , prevArgName ! . identifier , transformer , seenReturnStatement ) ;
453+ return shouldReturn ? refactoredStmts . map ( s => getSynthesizedDeepClone ( s ) ) :
454+ removeReturns (
455+ refactoredStmts ,
456+ prevArgName === undefined ? undefined : prevArgName . identifier ,
457+ transformer ,
458+ seenReturnStatement ) ;
455459 }
456460 else {
457461 const innerRetStmts = getReturnStatementsWithPromiseHandlers ( createReturn ( funcBody ) ) ;
458462 const innerCbBody = getInnerTransformationBody ( transformer , innerRetStmts , prevArgName ) ;
459463
460464 if ( innerCbBody . length > 0 ) {
461- return createNodeArray ( innerCbBody ) ;
465+ return innerCbBody ;
462466 }
463467
464468 if ( ! shouldReturn ) {
@@ -473,7 +477,7 @@ namespace ts.codefix {
473477 return transformedStatement ;
474478 }
475479 else {
476- return createNodeArray ( [ createReturn ( getSynthesizedDeepClone ( funcBody ) ) ] ) ;
480+ return [ createReturn ( getSynthesizedDeepClone ( funcBody ) ) ] ;
477481 }
478482 }
479483 }
@@ -482,7 +486,7 @@ namespace ts.codefix {
482486 codeActionSucceeded = false ;
483487 break ;
484488 }
485- return createNodeArray ( [ ] ) ;
489+ return emptyArray ;
486490 }
487491
488492 function getLastCallSignature ( type : Type , checker : TypeChecker ) : Signature | undefined {
@@ -491,14 +495,19 @@ namespace ts.codefix {
491495 }
492496
493497
494- function removeReturns ( stmts : NodeArray < Statement > , prevArgName : Identifier , transformer : Transformer , seenReturnStatement : boolean ) : NodeArray < Statement > {
498+ function removeReturns ( stmts : ReadonlyArray < Statement > , prevArgName : Identifier | undefined , transformer : Transformer , seenReturnStatement : boolean ) : ReadonlyArray < Statement > {
495499 const ret : Statement [ ] = [ ] ;
496500 for ( const stmt of stmts ) {
497501 if ( isReturnStatement ( stmt ) ) {
498502 if ( stmt . expression ) {
499503 const possiblyAwaitedExpression = isPromiseReturningExpression ( stmt . expression , transformer . checker ) ? createAwait ( stmt . expression ) : stmt . expression ;
500- ret . push ( createVariableStatement ( /*modifiers*/ undefined ,
501- ( createVariableDeclarationList ( [ createVariableDeclaration ( prevArgName , /*type*/ undefined , possiblyAwaitedExpression ) ] , getFlagOfIdentifier ( prevArgName , transformer . constIdentifiers ) ) ) ) ) ;
504+ if ( prevArgName === undefined ) {
505+ ret . push ( createExpressionStatement ( possiblyAwaitedExpression ) ) ;
506+ }
507+ else {
508+ ret . push ( createVariableStatement ( /*modifiers*/ undefined ,
509+ ( createVariableDeclarationList ( [ createVariableDeclaration ( prevArgName , /*type*/ undefined , possiblyAwaitedExpression ) ] , getFlagOfIdentifier ( prevArgName , transformer . constIdentifiers ) ) ) ) ) ;
510+ }
502511 }
503512 }
504513 else {
@@ -507,20 +516,20 @@ namespace ts.codefix {
507516 }
508517
509518 // if block has no return statement, need to define prevArgName as undefined to prevent undeclared variables
510- if ( ! seenReturnStatement ) {
519+ if ( ! seenReturnStatement && prevArgName !== undefined ) {
511520 ret . push ( createVariableStatement ( /*modifiers*/ undefined ,
512521 ( createVariableDeclarationList ( [ createVariableDeclaration ( prevArgName , /*type*/ undefined , createIdentifier ( "undefined" ) ) ] , getFlagOfIdentifier ( prevArgName , transformer . constIdentifiers ) ) ) ) ) ;
513522 }
514523
515- return createNodeArray ( ret ) ;
524+ return ret ;
516525 }
517526
518527
519- function getInnerTransformationBody ( transformer : Transformer , innerRetStmts : Node [ ] , prevArgName ?: SynthIdentifier ) {
528+ function getInnerTransformationBody ( transformer : Transformer , innerRetStmts : ReadonlyArray < Node > , prevArgName ?: SynthIdentifier ) {
520529
521530 let innerCbBody : Statement [ ] = [ ] ;
522531 for ( const stmt of innerRetStmts ) {
523- forEachChild ( stmt , function visit ( node : Node ) {
532+ forEachChild ( stmt , function visit ( node ) {
524533 if ( isCallExpression ( node ) ) {
525534 const temp = transformExpression ( node , transformer , node , prevArgName ) ;
526535 innerCbBody = innerCbBody . concat ( temp ) ;
0 commit comments