From f558f2f6cdfcd416cc2672d8ddb6432e617f5bb9 Mon Sep 17 00:00:00 2001 From: BigAru Date: Wed, 17 Oct 2018 15:13:03 +0200 Subject: [PATCH] add working getEditsForAction --- .../convertArrowFunctionOrFunction.ts | 105 ++++++++++++++++-- 1 file changed, 93 insertions(+), 12 deletions(-) diff --git a/src/services/refactors/convertArrowFunctionOrFunction.ts b/src/services/refactors/convertArrowFunctionOrFunction.ts index b9ede66fe5c..5ee7a3918dc 100644 --- a/src/services/refactors/convertArrowFunctionOrFunction.ts +++ b/src/services/refactors/convertArrowFunctionOrFunction.ts @@ -13,28 +13,32 @@ namespace ts.refactor.convertArrowFunctionOrFunction { registerRefactor(refactorName, { getEditsForAction, getAvailableActions }); + interface Info { + func: FunctionExpression | ArrowFunction; + } + function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined { const { file, startPosition } = context; + const info = getInfo(file, startPosition); - const node = getTokenAtPosition(file, startPosition); - const func = getContainingFunction(node); - if (!func || !(isFunctionExpression(func) || isArrowFunction(func)) || rangeContainsRange(func.body, node)) return undefined; + if (!info) return undefined; + const { func } = info; const possibleActions: RefactorActionInfo[] = []; if (isArrowFunction(func)) { if (isVariableDeclaration(func.parent)) { possibleActions.push({ - name: toNamedFunctionActionName, - description: toNamedFunctionActionDescription - }); + name: toNamedFunctionActionName, + description: toNamedFunctionActionDescription + }); } possibleActions.push({ - name: toAnonymousFunctionActionName, - description: toAnonymousFunctionActionDescription - }); + name: toAnonymousFunctionActionName, + description: toAnonymousFunctionActionDescription + }); } else { possibleActions.push({ @@ -51,9 +55,86 @@ namespace ts.refactor.convertArrowFunctionOrFunction { } function getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { - context; - actionName; - return undefined; + const { file, startPosition } = context; + const info = getInfo(file, startPosition); + + if (!info) return undefined; + const { func } = info; + + switch (actionName) { + case toAnonymousFunctionActionName: + let body: Block; + + if (isExpression(func.body)) { + const statements: Statement[] = [createReturn(func.body)]; + body = createBlock(statements, /* multiLine */ true); + } + else { + body = func.body; + } + + const newNode = createFunctionExpression(func.modifiers, func.asteriskToken, /* name */ undefined, func.typeParameters, func.parameters, func.type, body); + const edits = textChanges.ChangeTracker.with(context, t => t.replaceNode(file, func, newNode)); + return { renameFilename: undefined, renameLocation: undefined, edits }; + + case toNamedFunctionActionName: + let body2: Block; + + if (isExpression(func.body)) { + const statements: Statement[] = [createReturn(func.body)]; + body2 = createBlock(statements, /* multiLine */ true); + } + else { + body2 = func.body; + } + + const variableDeclaration = func.parent; + if (isVariableDeclaration(variableDeclaration) && isVariableDeclarationInVariableStatement(variableDeclaration) && isIdentifier(variableDeclaration.name)) { + const statement = findAncestor(variableDeclaration, n => n.kind === SyntaxKind.VariableStatement); + + const newNode1 = createFunctionDeclaration(func.decorators, func.modifiers, func.asteriskToken, variableDeclaration.name, func.typeParameters, func.parameters, func.type, body2); + const edits1 = textChanges.ChangeTracker.with(context, t => t.replaceNode(file, statement!, newNode1)); + return { renameFilename: undefined, renameLocation: undefined, edits: edits1 }; + } + + return undefined; + + case toArrowFunctionActionName: + let body1: ConciseBody; + + if (isFunctionExpression(func)) { + const statements = func.body.statements; + const head = statements[0]; + if (func.body.statements.length === 1 && (isReturnStatement(head) || isExpressionStatement(head))) { + body1 = head.expression!; + + suppressLeadingAndTrailingTrivia(body1); + copyComments(head, body1, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); + } + else { + body1 = func.body; + } + + const newNode = createArrowFunction(func.modifiers, func.typeParameters, func.parameters, func.type, /* equalsGreaterThanToken */ undefined, body1); + const edits = textChanges.ChangeTracker.with(context, t => t.replaceNode(file, func, newNode)); + return { renameFilename: undefined, renameLocation: undefined, edits }; + } + + return undefined; + + default: + Debug.fail("invalid action"); + break; + } + + } + + function getInfo(file: SourceFile, startPosition: number): Info | undefined { + const node = getTokenAtPosition(file, startPosition); + const func = getContainingFunction(node); + if (!func || !(isFunctionExpression(func) || isArrowFunction(func)) || rangeContainsRange(func.body, node)) return undefined; + + return { func }; } }