diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index be27a8ecc1cc1..1d98e2e6f19a4 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -5717,6 +5717,22 @@
"category": "Message",
"code": 95121
},
+ "Convert arrow function or function expression": {
+ "category": "Message",
+ "code": 95122
+ },
+ "Convert to anonymous function": {
+ "category": "Message",
+ "code": 95123
+ },
+ "Convert to named function": {
+ "category": "Message",
+ "code": 95124
+ },
+ "Convert to arrow function": {
+ "category": "Message",
+ "code": 95125
+ },
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
"category": "Error",
diff --git a/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts
new file mode 100644
index 0000000000000..e469e2eccad89
--- /dev/null
+++ b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts
@@ -0,0 +1,216 @@
+/* @internal */
+namespace ts.refactor.convertArrowFunctionOrFunctionExpression {
+ const refactorName = "Convert arrow function or function expression";
+ const refactorDescription = getLocaleSpecificMessage(Diagnostics.Convert_arrow_function_or_function_expression);
+
+ const toAnonymousFunctionActionName = "Convert to anonymous function";
+ const toNamedFunctionActionName = "Convert to named function";
+ const toArrowFunctionActionName = "Convert to arrow function";
+
+ const toAnonymousFunctionActionDescription = getLocaleSpecificMessage(Diagnostics.Convert_to_anonymous_function);
+ const toNamedFunctionActionDescription = getLocaleSpecificMessage(Diagnostics.Convert_to_named_function);
+ const toArrowFunctionActionDescription = getLocaleSpecificMessage(Diagnostics.Convert_to_arrow_function);
+
+ registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
+
+ interface FunctionInfo {
+ readonly selectedVariableDeclaration: boolean;
+ readonly func: FunctionExpression | ArrowFunction;
+ }
+
+ interface VariableInfo {
+ readonly variableDeclaration: VariableDeclaration;
+ readonly variableDeclarationList: VariableDeclarationList;
+ readonly statement: VariableStatement;
+ readonly name: Identifier;
+ }
+
+ function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] {
+ const { file, startPosition, program } = context;
+ const info = getFunctionInfo(file, startPosition, program);
+
+ if (!info) return emptyArray;
+ const { selectedVariableDeclaration, func } = info;
+ const possibleActions: RefactorActionInfo[] = [];
+
+ if (selectedVariableDeclaration || (isArrowFunction(func) && isVariableDeclaration(func.parent))) {
+ possibleActions.push({
+ name: toNamedFunctionActionName,
+ description: toNamedFunctionActionDescription
+ });
+ }
+
+ if (!selectedVariableDeclaration && isArrowFunction(func)) {
+ possibleActions.push({
+ name: toAnonymousFunctionActionName,
+ description: toAnonymousFunctionActionDescription
+ });
+ }
+
+ if (isFunctionExpression(func)) {
+ possibleActions.push({
+ name: toArrowFunctionActionName,
+ description: toArrowFunctionActionDescription
+ });
+ }
+
+ return [{
+ name: refactorName,
+ description: refactorDescription,
+ actions: possibleActions
+ }];
+ }
+
+ function getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined {
+ const { file, startPosition, program } = context;
+ const info = getFunctionInfo(file, startPosition, program);
+
+ if (!info) return undefined;
+ const { func } = info;
+ const edits: FileTextChanges[] = [];
+
+ switch (actionName) {
+ case toAnonymousFunctionActionName:
+ edits.push(...getEditInfoForConvertToAnonymousFunction(context, func));
+ break;
+
+ case toNamedFunctionActionName:
+ const variableInfo = getVariableInfo(func);
+ if (!variableInfo) return undefined;
+
+ edits.push(...getEditInfoForConvertToNamedFunction(context, func, variableInfo));
+ break;
+
+ case toArrowFunctionActionName:
+ if (!isFunctionExpression(func)) return undefined;
+ edits.push(...getEditInfoForConvertToArrowFunction(context, func));
+ break;
+
+ default:
+ return Debug.fail("invalid action");
+ }
+
+ return { renameFilename: undefined, renameLocation: undefined, edits };
+ }
+
+ function containingThis(node: Node): boolean {
+ let containsThis = false;
+ node.forEachChild(function checkThis(child) {
+
+ if (isThis(child)) {
+ containsThis = true;
+ return;
+ }
+
+ if (!isClassLike(child) && !isFunctionDeclaration(child) && !isFunctionExpression(child)) {
+ forEachChild(child, checkThis);
+ }
+ });
+
+ return containsThis;
+ }
+
+ function getFunctionInfo(file: SourceFile, startPosition: number, program: Program): FunctionInfo | undefined {
+ const token = getTokenAtPosition(file, startPosition);
+
+ const arrowFunc = getArrowFunctionFromVariableDeclaration(token.parent);
+ if (arrowFunc && !containingThis(arrowFunc.body)) return { selectedVariableDeclaration: true, func: arrowFunc };
+
+ const maybeFunc = getContainingFunction(token);
+ const typeChecker = program.getTypeChecker();
+
+ if (
+ maybeFunc &&
+ (isFunctionExpression(maybeFunc) || isArrowFunction(maybeFunc)) &&
+ !rangeContainsRange(maybeFunc.body, token) &&
+ !containingThis(maybeFunc.body)
+ ) {
+ if ((isFunctionExpression(maybeFunc) && maybeFunc.name && FindAllReferences.Core.isSymbolReferencedInFile(maybeFunc.name, typeChecker, file))) return undefined;
+ return { selectedVariableDeclaration: false, func: maybeFunc };
+ }
+
+ return undefined;
+ }
+
+ function isSingleVariableDeclaration(parent: Node): parent is VariableDeclarationList {
+ return isVariableDeclaration(parent) || (isVariableDeclarationList(parent) && parent.declarations.length === 1);
+ }
+
+ function getArrowFunctionFromVariableDeclaration(parent: Node): ArrowFunction | undefined {
+ if (!isSingleVariableDeclaration(parent)) return undefined;
+ const variableDeclaration = isVariableDeclaration(parent) ? parent : parent.declarations[0];
+
+ const initializer = variableDeclaration.initializer;
+ if (!initializer || !isArrowFunction(initializer)) return undefined;
+ return initializer;
+ }
+
+ function convertToBlock(body: ConciseBody): Block {
+ if (isExpression(body)) {
+ return createBlock([createReturn(body)], /* multiLine */ true);
+ }
+ else {
+ return body;
+ }
+ }
+
+ function getVariableInfo(func: FunctionExpression | ArrowFunction): VariableInfo | undefined {
+ const variableDeclaration = func.parent;
+ if (!isVariableDeclaration(variableDeclaration) || !isVariableDeclarationInVariableStatement(variableDeclaration)) return undefined;
+
+ const variableDeclarationList = variableDeclaration.parent;
+ const statement = variableDeclarationList.parent;
+ if (!isVariableDeclarationList(variableDeclarationList) || !isVariableStatement(statement) || !isIdentifier(variableDeclaration.name)) return undefined;
+
+ return { variableDeclaration, variableDeclarationList, statement, name: variableDeclaration.name };
+ }
+
+ function getEditInfoForConvertToAnonymousFunction(context: RefactorContext, func: FunctionExpression | ArrowFunction): FileTextChanges[] {
+ const { file } = context;
+ const body = convertToBlock(func.body);
+ const newNode = createFunctionExpression(func.modifiers, func.asteriskToken, /* name */ undefined, func.typeParameters, func.parameters, func.type, body);
+ return textChanges.ChangeTracker.with(context, t => t.replaceNode(file, func, newNode));
+ }
+
+ function getEditInfoForConvertToNamedFunction(context: RefactorContext, func: FunctionExpression | ArrowFunction, variableInfo: VariableInfo): FileTextChanges[] {
+ const { file } = context;
+ const body = convertToBlock(func.body);
+
+ const { variableDeclaration, variableDeclarationList, statement, name } = variableInfo;
+ suppressLeadingTrivia(statement);
+ const newNode = createFunctionDeclaration(func.decorators, statement.modifiers, func.asteriskToken, name, func.typeParameters, func.parameters, func.type, body);
+
+ if (variableDeclarationList.declarations.length === 1) {
+ return textChanges.ChangeTracker.with(context, t => t.replaceNode(file, statement, newNode));
+ }
+ else {
+ return textChanges.ChangeTracker.with(context, t => {
+ t.delete(file, variableDeclaration);
+ t.insertNodeAfter(file, statement, newNode);
+ });
+ }
+ }
+
+ function getEditInfoForConvertToArrowFunction(context: RefactorContext, func: FunctionExpression): FileTextChanges[] {
+ const { file } = context;
+ const statements = func.body.statements;
+ const head = statements[0];
+ let body: ConciseBody;
+
+ if (canBeConvertedToExpression(func.body, head)) {
+ body = head.expression!;
+ suppressLeadingAndTrailingTrivia(body);
+ copyComments(head, body);
+ }
+ else {
+ body = func.body;
+ }
+
+ const newNode = createArrowFunction(func.modifiers, func.typeParameters, func.parameters, func.type, createToken(SyntaxKind.EqualsGreaterThanToken), body);
+ return textChanges.ChangeTracker.with(context, t => t.replaceNode(file, func, newNode));
+ }
+
+ function canBeConvertedToExpression(body: Block, head: Statement): head is ReturnStatement {
+ return body.statements.length === 1 && ((isReturnStatement(head) && !!head.expression));
+ }
+}
diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json
index dafc056d338ef..1fd5ba3058165 100644
--- a/src/services/tsconfig.json
+++ b/src/services/tsconfig.json
@@ -113,6 +113,7 @@
"refactors/addOrRemoveBracesToArrowFunction.ts",
"refactors/convertParamsToDestructuredObject.ts",
"refactors/convertStringOrTemplateLiteral.ts",
+ "refactors/convertArrowFunctionOrFunctionExpression.ts",
"services.ts",
"breakpoints.ts",
"transform.ts",
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon.ts
new file mode 100644
index 0000000000000..0fa3222617c1b
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon.ts
@@ -0,0 +1,28 @@
+///
+
+//// /*z*/c/*y*/onst /*x*/f/*w*/oo = /*v*/f/*u*/unction() /*t*/{/*s*/ /*r*/r/*q*/eturn 42;};
+
+goTo.select("z", "y");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("x", "w");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("v", "u");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("t", "s");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("r", "q");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_FnArgument.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_FnArgument.ts
new file mode 100644
index 0000000000000..6c017aeeb739a
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_FnArgument.ts
@@ -0,0 +1,34 @@
+///
+
+//// function foo(a){}
+//// /*z*/f/*y*/oo/*x*/(/*w*//*v*/f/*u*/unction/*t*/(/*s*//*r*/b/*q*/,c){/*p*/r/*o*/eturn 42;})
+
+goTo.select("z", "y");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("x", "w");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("v", "u");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("t", "s");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("r", "q");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("p", "o");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_nested_this.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_nested_this.ts
new file mode 100644
index 0000000000000..cbf57122526e8
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_nested_this.ts
@@ -0,0 +1,19 @@
+///
+
+//// const zoo = /*x*/f/*w*/unction () {
+//// class Animal {
+//// weight = 42
+//// askWeight() { return this.weight }
+//// }
+//// const Insect = class {
+//// weight = 42
+//// askWeight() { return this.weight }
+//// }
+//// function callTaxi() { this.no = "054 xxx xx xx" }
+//// const callPizzaDelivery = function() { this.phone = "064 yyy yy yy"}
+//// };
+
+goTo.select("x", "w");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_this.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_this.ts
new file mode 100644
index 0000000000000..a895fea432d74
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_this.ts
@@ -0,0 +1,11 @@
+///
+
+//// const foo = /*x*/f/*w*/unction() {
+//// this.bar = "F-Express";
+//// return this.bar;
+//// };
+
+goTo.select("x", "w");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_unusedName.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_unusedName.ts
new file mode 100644
index 0000000000000..480dd466ec24a
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_unusedName.ts
@@ -0,0 +1,28 @@
+///
+
+//// /*z*/c/*y*/onst /*x*/f/*w*/oo = /*v*/f/*u*/unction bar() /*t*/{/*s*/ /*r*/r/*q*/eturn 42;};
+
+goTo.select("z", "y");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("x", "w");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("v", "u");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("t", "s");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("r", "q");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_usedName.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_usedName.ts
new file mode 100644
index 0000000000000..ff87ca84714c5
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_usedName.ts
@@ -0,0 +1,28 @@
+///
+
+//// /*z*/c/*y*/onst /*x*/f/*w*/oo = /*v*/f/*u*/unction isEven(n) /*t*/{/*s*/ /*r*/r/*q*/eturn n === 0 ? true : n === 1 ? false : isEven(n - 2);};
+
+goTo.select("z", "y");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("x", "w");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("v", "u");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("t", "s");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("r", "q");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow.ts
new file mode 100644
index 0000000000000..619b2af822c5d
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow.ts
@@ -0,0 +1,33 @@
+///
+
+//// /*z*/c/*y*/onst /*x*/f/*w*/oo = /*v*/(/*u*//*t*/a/*s*/, b) /*r*/=/*q*/> /*p*/4/*o*/2;
+
+goTo.select("z", "y");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("x", "w");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("v", "u");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("t", "s");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("r", "q");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("p", "o");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_FnArgument.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_FnArgument.ts
new file mode 100644
index 0000000000000..6d309494da9f1
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_FnArgument.ts
@@ -0,0 +1,30 @@
+///
+
+//// function foo(a){}
+//// /*z*/f/*y*/oo/*x*/(/*w*//*v*/(/*u*//*t*/a/*s*/, b) => /*r*/a/*q*/ + b)
+
+
+goTo.select("z", "y");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("x", "w");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("v", "u");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("t", "s");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("r", "q");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_MultiDecl.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_MultiDecl.ts
new file mode 100644
index 0000000000000..1e87f8bc0c30a
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_MultiDecl.ts
@@ -0,0 +1,23 @@
+///
+
+//// /*z*/l/*y*/et /*x*/f/*w*/oo, /*v*/b/*u*/ar = /*t*/(/*s*/) => 42;
+
+goTo.select("z", "y");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("x", "w");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("v", "u");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
+
+goTo.select("t", "s");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_nested_this.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_nested_this.ts
new file mode 100644
index 0000000000000..4b5985b9a85f5
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_nested_this.ts
@@ -0,0 +1,19 @@
+///
+
+//// const zoo = /*x*/(/*w*/) => {
+//// class Animal {
+//// weight = 42
+//// askWeight() { return this.weight }
+//// }
+//// const Insect = class {
+//// weight = 42
+//// askWeight() { return this.weight }
+//// }
+//// function callTaxi() { this.no = "054 xxx xx xx" }
+//// const callPizzaDelivery = function() { this.phone = "064 yyy yy yy"}
+//// };
+
+goTo.select("x", "w");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_this.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_this.ts
new file mode 100644
index 0000000000000..d1905c48f3511
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Arrow_this.ts
@@ -0,0 +1,9 @@
+///
+
+//// const bar = 42;
+//// const foo = /*x*/(/*w*/) => this.bar;
+
+goTo.select("x", "w");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
+verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_Comment.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_Comment.ts
new file mode 100644
index 0000000000000..c3a65cbf0550a
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_Comment.ts
@@ -0,0 +1,23 @@
+///
+
+//// const foo = /*x*/a/*y*/ => {
+//// // secret word
+//// return a + 1;
+//// /*
+//// hidden msg
+//// */
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to anonymous function",
+ actionDescription: "Convert to anonymous function",
+ newContent: `const foo = function(a) {
+ // secret word
+ return a + 1;
+ /*
+ hidden msg
+ */
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_FnArgument.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_FnArgument.ts
new file mode 100644
index 0000000000000..c07a741f1ab1d
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_FnArgument.ts
@@ -0,0 +1,15 @@
+///
+
+//// function doSomething(a){}
+//// doSomething(/*x*/(/*y*/) => 1 + 1);
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to anonymous function",
+ actionDescription: "Convert to anonymous function",
+ newContent: `function doSomething(a){}
+doSomething(function() {
+ return 1 + 1;
+ });`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_MapArgument.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_MapArgument.ts
new file mode 100644
index 0000000000000..8d53517d7eac5
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_MapArgument.ts
@@ -0,0 +1,13 @@
+///
+
+//// [9,8,7].map(/*x*/n/*y*/ => n + 418);
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to anonymous function",
+ actionDescription: "Convert to anonymous function",
+ newContent: `[9,8,7].map(function(n) {
+ return n + 418;
+ });`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_MultiLine.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_MultiLine.ts
new file mode 100644
index 0000000000000..cbaadbf6a8587
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_MultiLine.ts
@@ -0,0 +1,17 @@
+///
+
+//// const foo = /*x*/a/*y*/ => {
+//// let b = 1;
+//// return a + b;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to anonymous function",
+ actionDescription: "Convert to anonymous function",
+ newContent: `const foo = function(a) {
+ let b = 1;
+ return a + b;
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_MultiParam.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_MultiParam.ts
new file mode 100644
index 0000000000000..38953dbf248e7
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_MultiParam.ts
@@ -0,0 +1,13 @@
+///
+
+//// const foo = /*x*/(/*y*/a,b,c) => a + 1;
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to anonymous function",
+ actionDescription: "Convert to anonymous function",
+ newContent: `const foo = function(a, b, c) {
+ return a + 1;
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_SingleLine.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_SingleLine.ts
new file mode 100644
index 0000000000000..9870104eb162d
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_SingleLine.ts
@@ -0,0 +1,13 @@
+///
+
+//// const foo = /*x*/(/*y*/) => 1 + 1;
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to anonymous function",
+ actionDescription: "Convert to anonymous function",
+ newContent: `const foo = function() {
+ return 1 + 1;
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_Typed.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_Typed.ts
new file mode 100644
index 0000000000000..0fbea66be0e3d
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_Typed.ts
@@ -0,0 +1,13 @@
+///
+
+//// const increment = /*x*/(/*y*/a: number): number => a + 1;
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to anonymous function",
+ actionDescription: "Convert to anonymous function",
+ newContent: `const increment = function(a: number): number {
+ return a + 1;
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_EmptyReturn.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_EmptyReturn.ts
new file mode 100644
index 0000000000000..e77adca0eb8ae
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_EmptyReturn.ts
@@ -0,0 +1,15 @@
+///
+
+//// const foo = /*x*/f/*y*/unction() {
+//// return;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `const foo = () => {
+ return;
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_FnArgument.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_FnArgument.ts
new file mode 100644
index 0000000000000..3dc442e4e5da0
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_FnArgument.ts
@@ -0,0 +1,15 @@
+///
+
+//// function foo(lambda){}
+//// foo(function /*x*/is/*y*/Even(n) {
+//// return n % 2 === 0;
+//// });
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `function foo(lambda){}
+foo((n) => n % 2 === 0);`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_MapArgument.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_MapArgument.ts
new file mode 100644
index 0000000000000..4e1c0b2f9f5a9
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_MapArgument.ts
@@ -0,0 +1,13 @@
+///
+
+//// [4,5,6,7].map(function /*x*/is/*y*/Even(n) {
+//// return n % 2 === 0;
+//// });
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `[4,5,6,7].map((n) => n % 2 === 0);`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_MultiLine.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_MultiLine.ts
new file mode 100644
index 0000000000000..71855947b36cd
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_MultiLine.ts
@@ -0,0 +1,17 @@
+///
+
+//// const foo = /*x*/f/*y*/unction() {
+//// let a = 41;
+//// return a + 1;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `const foo = () => {
+ let a = 41;
+ return a + 1;
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_MultiLine_Comment.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_MultiLine_Comment.ts
new file mode 100644
index 0000000000000..470cae1c446c1
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_MultiLine_Comment.ts
@@ -0,0 +1,25 @@
+///
+
+//// const foo = /*x*/f/*y*/unction() {
+//// // secret
+//// let a = 41;
+//// /*
+//// msg
+//// */
+//// return a + 1;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `const foo = () => {
+ // secret
+ let a = 41;
+ /*
+ msg
+ */
+ return a + 1;
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Param.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Param.ts
new file mode 100644
index 0000000000000..a7659080998a6
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Param.ts
@@ -0,0 +1,13 @@
+///
+
+//// const foo = /*x*/f/*y*/unction(a, b, c) {
+//// return a + b + c;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `const foo = (a, b, c) => a + b + c;`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_Assign.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_Assign.ts
new file mode 100644
index 0000000000000..f5e15ab8ac9e4
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_Assign.ts
@@ -0,0 +1,17 @@
+///
+
+//// let bar;
+//// const foo = /*x*/f/*y*/unction() {
+//// bar = 42;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `let bar;
+const foo = () => {
+ bar = 42;
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_Decl.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_Decl.ts
new file mode 100644
index 0000000000000..e1f15b78f3dd6
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_Decl.ts
@@ -0,0 +1,15 @@
+///
+
+//// const foo = /*x*/f/*y*/unction() {
+//// let bar;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `const foo = () => {
+ let bar;
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_FnCall.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_FnCall.ts
new file mode 100644
index 0000000000000..af8068699df69
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_FnCall.ts
@@ -0,0 +1,17 @@
+///
+
+//// function s(){}
+//// const foo = /*x*/f/*y*/unction() {
+//// s();
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `function s(){}
+const foo = () => {
+ s();
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_For.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_For.ts
new file mode 100644
index 0000000000000..a0da4868b0ec1
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_For.ts
@@ -0,0 +1,15 @@
+///
+
+//// const foo = /*x*/f/*y*/unction() {
+//// for (let i = 0; i < 5; i++) { }
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `const foo = () => {
+ for (let i = 0; i < 5; i++) { }
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_If.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_If.ts
new file mode 100644
index 0000000000000..65084f0f3a973
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_If.ts
@@ -0,0 +1,15 @@
+///
+
+//// const foo = /*x*/f/*y*/unction() {
+//// if (true) { }
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `const foo = () => {
+ if (true) { }
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_Return.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_Return.ts
new file mode 100644
index 0000000000000..c901046de3e7f
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_Return.ts
@@ -0,0 +1,13 @@
+///
+
+//// const foo = /*x*/f/*y*/unction() {
+//// return 42;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `const foo = () => 42;`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_While.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_While.ts
new file mode 100644
index 0000000000000..830a9b4933b58
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_While.ts
@@ -0,0 +1,15 @@
+///
+
+//// const foo = /*x*/f/*y*/unction() {
+//// while (true) { }
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `const foo = () => {
+ while (true) { }
+};`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Typed.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Typed.ts
new file mode 100644
index 0000000000000..01d30d1f08099
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Typed.ts
@@ -0,0 +1,13 @@
+///
+
+//// const concat = /*x*/f/*y*/unction(a: string, b: string): string {
+//// return a + b;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to arrow function",
+ actionDescription: "Convert to arrow function",
+ newContent: `const concat = (a: string, b: string): string => a + b;`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Comment.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Comment.ts
new file mode 100644
index 0000000000000..8f615da85ef45
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Comment.ts
@@ -0,0 +1,23 @@
+///
+
+//// const foo = /*x*/a/*y*/ => {
+//// // secret word
+//// return a + 1;
+//// /*
+//// hidden msg
+//// */
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `function foo(a) {
+ // secret word
+ return a + 1;
+ /*
+ hidden msg
+ */
+}`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Modifier.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Modifier.ts
new file mode 100644
index 0000000000000..9d60d172397be
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Modifier.ts
@@ -0,0 +1,17 @@
+///
+
+//// export let foo = /*x*/a/*y*/ => {
+//// let b = 1;
+//// return a + b;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `export function foo(a) {
+ let b = 1;
+ return a + b;
+}`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Modifier_Comment.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Modifier_Comment.ts
new file mode 100644
index 0000000000000..20bb38855900c
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Modifier_Comment.ts
@@ -0,0 +1,19 @@
+///
+
+//// // Do not add me second time
+//// export let foo = /*x*/a/*y*/ => {
+//// let b = 1;
+//// return a + b;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `// Do not add me second time
+export function foo(a) {
+ let b = 1;
+ return a + b;
+}`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl.ts
new file mode 100644
index 0000000000000..789eb98141db7
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl.ts
@@ -0,0 +1,15 @@
+///
+
+//// let foo, bar = /*x*/(/*y*/) => 1 + 1, magicNo;
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `let foo, magicNo;
+function bar() {
+ return 1 + 1;
+}
+`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl_Modifier.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl_Modifier.ts
new file mode 100644
index 0000000000000..4044d76ad2aff
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl_Modifier.ts
@@ -0,0 +1,15 @@
+///
+
+//// export let foo, bar = /*x*/(/*y*/) => 1 + 1;
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `export let foo;
+export function bar() {
+ return 1 + 1;
+}
+`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl_Modifier_Comment.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl_Modifier_Comment.ts
new file mode 100644
index 0000000000000..46fc080ebda3d
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl_Modifier_Comment.ts
@@ -0,0 +1,17 @@
+///
+
+//// // Do not add me second time
+//// export let foo, bar = /*x*/(/*y*/) => 1 + 1;
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `// Do not add me second time
+export let foo;
+export function bar() {
+ return 1 + 1;
+}
+`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl_VarSelection.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl_VarSelection.ts
new file mode 100644
index 0000000000000..6757cb15609c4
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiDecl_VarSelection.ts
@@ -0,0 +1,15 @@
+///
+
+//// let foo, /*x*/b/*y*/ar = a => 1 + a;
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `let foo;
+function bar(a) {
+ return 1 + a;
+}
+`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiLine.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiLine.ts
new file mode 100644
index 0000000000000..ef2866f783e36
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiLine.ts
@@ -0,0 +1,17 @@
+///
+
+//// let foo = /*x*/a/*y*/ => {
+//// let b = 1;
+//// return a + b;
+//// };
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `function foo(a) {
+ let b = 1;
+ return a + b;
+}`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiParam.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiParam.ts
new file mode 100644
index 0000000000000..0036f11136d9e
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_MultiParam.ts
@@ -0,0 +1,13 @@
+///
+
+//// let foo = /*x*/(/*y*/a,b,c) => a + 1;
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `function foo(a, b, c) {
+ return a + 1;
+}`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_SingleLine.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_SingleLine.ts
new file mode 100644
index 0000000000000..4952856d87f11
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_SingleLine.ts
@@ -0,0 +1,13 @@
+///
+
+//// let foo = /*x*/(/*y*/) => 1 + 1;
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `function foo() {
+ return 1 + 1;
+}`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Typed.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Typed.ts
new file mode 100644
index 0000000000000..6a67c390bd4e8
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_Typed.ts
@@ -0,0 +1,13 @@
+///
+
+//// let isFoo = /*x*/(/*y*/n: number): boolean => n === 42;
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `function isFoo(n: number): boolean {
+ return n === 42;
+}`,
+});
diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_keywordSelection.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_keywordSelection.ts
new file mode 100644
index 0000000000000..2e2f1b2b14dfa
--- /dev/null
+++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_keywordSelection.ts
@@ -0,0 +1,13 @@
+///
+
+//// /*x*/let/*y*/ foo = a => 1 + a;
+
+goTo.select("x", "y");
+edit.applyRefactor({
+ refactorName: "Convert arrow function or function expression",
+ actionName: "Convert to named function",
+ actionDescription: "Convert to named function",
+ newContent: `function foo(a) {
+ return 1 + a;
+}`,
+});