diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1f1ee7a694861..5af03481e731a 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4720,5 +4720,21 @@ "Generate types for all packages without types": { "category": "Message", "code": 95068 + }, + "Convert arrow function or function expression": { + "category": "Message", + "code": 95069 + }, + "Convert to anonymous function": { + "category": "Message", + "code": 95070 + }, + "Convert to named function": { + "category": "Message", + "code": 95071 + }, + "Convert to arrow function": { + "category": "Message", + "code": 95072 } } diff --git a/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts new file mode 100644 index 0000000000000..9bf16775f6c43 --- /dev/null +++ b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts @@ -0,0 +1,192 @@ +/* @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): ApplicableRefactorInfo[] | undefined { + const { file, startPosition } = context; + const info = getFunctionInfo(file, startPosition); + + if (!info) return undefined; + 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 } = context; + const info = getFunctionInfo(file, startPosition); + + if (!info) return undefined; + const { func } = info; + + switch (actionName) { + case toAnonymousFunctionActionName: + return getEditInfoForConvertToAnonymousFunction(context, func); + + case toNamedFunctionActionName: + return getEditInfoForConvertToNamedFunction(context, func); + + case toArrowFunctionActionName: + return getEditInfoForConvertToArrowFunction(context, func); + + default: + Debug.fail("invalid action"); + break; + } + + return undefined; + } + + function getFunctionInfo(file: SourceFile, startPosition: number): FunctionInfo | undefined { + const token = getTokenAtPosition(file, startPosition); + let maybeFunc; + + maybeFunc = getArrowFunctionFromVariableDeclaration(token.parent); + if (!!maybeFunc) return { selectedVariableDeclaration: true, func: maybeFunc }; + + maybeFunc = getContainingFunction(token); + if (!!maybeFunc && (isFunctionExpression(maybeFunc) || isArrowFunction(maybeFunc)) && !rangeContainsRange(maybeFunc.body, token)) { + 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): RefactorEditInfo { + const { file } = context; + const body = convertToBlock(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 }; + } + + function getEditInfoForConvertToNamedFunction(context: RefactorContext, func: FunctionExpression | ArrowFunction): RefactorEditInfo | undefined { + const { file } = context; + const body = convertToBlock(func.body); + const variableInfo = getVariableInfo(func); + if (!variableInfo) return undefined; + + const { variableDeclaration, variableDeclarationList, statement, name } = variableInfo; + const newNode = createFunctionDeclaration(func.decorators, statement.modifiers, func.asteriskToken, name, func.typeParameters, func.parameters, func.type, body); + let edits: FileTextChanges[]; + + if (variableDeclarationList.declarations.length === 1) { + edits = textChanges.ChangeTracker.with(context, t => t.replaceNode(file, statement, newNode)); + } + else { + edits = textChanges.ChangeTracker.with(context, t => { + t.delete(file, variableDeclaration); + t.insertNodeAfter(file, statement, newNode); + }); + } + return { renameFilename: undefined, renameLocation: undefined, edits }; + } + + function getEditInfoForConvertToArrowFunction(context: RefactorContext, func: FunctionExpression | ArrowFunction): RefactorEditInfo | undefined { + const { file } = context; + if (!isFunctionExpression(func)) return undefined; + + 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, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); + } + else { + body = func.body; + } + + const newNode = createArrowFunction(func.modifiers, func.typeParameters, func.parameters, func.type, /* equalsGreaterThanToken */ undefined, body); + const edits = textChanges.ChangeTracker.with(context, t => t.replaceNode(file, func, newNode)); + return { renameFilename: undefined, renameLocation: undefined, edits }; + } + + function canBeConvertedToExpression(body: Block, head: Statement): head is ReturnStatement | ExpressionStatement { + return body.statements.length === 1 && ((isReturnStatement(head) && !!head.expression) || isExpressionStatement(head)); + } +} diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 66b1977ddc573..134b28f854f64 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -80,6 +80,7 @@ "refactors/generateGetAccessorAndSetAccessor.ts", "refactors/moveToNewFile.ts", "refactors/addOrRemoveBracesToArrowFunction.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_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_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_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_RetType.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_RetType.ts new file mode 100644 index 0000000000000..d8f6a591d17ee --- /dev/null +++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToAnon_RetType.ts @@ -0,0 +1,13 @@ +/// + +//// const foo = /*x*/(/*y*/): 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 foo = function(): number { + 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_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_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_RetType.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_RetType.ts new file mode 100644 index 0000000000000..ce814984236a6 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_RetType.ts @@ -0,0 +1,13 @@ +/// + +//// const foo = /*x*/f/*y*/unction(): string { +//// return "foobar"; +//// }; + +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 = (): string => "foobar";`, +}); 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..453a3f701bc06 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_Assign.ts @@ -0,0 +1,15 @@ +/// + +//// 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..e9cced11640de --- /dev/null +++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToArrow_Single_FnCall.ts @@ -0,0 +1,15 @@ +/// + +//// 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_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_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_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_RetType.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_RetType.ts new file mode 100644 index 0000000000000..9fffa04149979 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_ToNamed_RetType.ts @@ -0,0 +1,13 @@ +/// + +//// let foo = /*x*/(/*y*/): number => 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 foo(): number { + return 42; +}`, +}); 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; +}`, +});