-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add support for add or remove braces to arrow function #23423
Changes from 10 commits
5a69d9c
32be0c7
bd9a8b5
0c06126
1a59eb3
b6669c9
de75f14
5497b42
d470f32
3d9a6ab
590476b
0d730c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/* @internal */ | ||
namespace ts.refactor.addOrRemoveBracesToArrowFunction { | ||
const refactorName = "Add or remove braces in an arrow function"; | ||
const refactorDescription = Diagnostics.Add_or_remove_braces_in_an_arrow_function.message; | ||
const addBracesActionName = "Add braces to arrow function"; | ||
const removeBracesActionName = "Remove braces from arrow function"; | ||
const addBracesActionDescription = Diagnostics.Add_braces_to_arrow_function.message; | ||
const removeBracesActionDescription = Diagnostics.Remove_braces_from_arrow_function.message; | ||
registerRefactor(refactorName, { getEditsForAction, getAvailableActions }); | ||
|
||
interface Info { | ||
func: ArrowFunction; | ||
expression: Expression | undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I understand why |
||
returnStatement?: ReturnStatement; | ||
addBraces: boolean; | ||
} | ||
|
||
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined { | ||
const { file, startPosition } = context; | ||
const info = getConvertibleArrowFunctionAtPosition(file, startPosition); | ||
if (!info) return undefined; | ||
|
||
return [{ | ||
name: refactorName, | ||
description: refactorDescription, | ||
actions: [ | ||
info.addBraces ? | ||
{ | ||
name: addBracesActionName, | ||
description: addBracesActionDescription | ||
} : { | ||
name: removeBracesActionName, | ||
description: removeBracesActionDescription | ||
} | ||
] | ||
}]; | ||
} | ||
|
||
function getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { | ||
const { file, startPosition } = context; | ||
const info = getConvertibleArrowFunctionAtPosition(file, startPosition); | ||
if (!info) return undefined; | ||
|
||
const { expression, returnStatement, func } = info; | ||
|
||
let body: ConciseBody; | ||
if (actionName === addBracesActionName) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it matter whether this agrees with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happened with this? |
||
const returnStatement = createReturn(expression); | ||
body = createBlock([returnStatement], /* multiLine */ true); | ||
suppressLeadingAndTrailingTrivia(body); | ||
copyComments(expression!, returnStatement, file, SyntaxKind.MultiLineCommentTrivia, /* explicitHtnl */ true); | ||
} | ||
else if (actionName === removeBracesActionName && returnStatement) { | ||
const actualExpression = expression || createVoidZero(); | ||
body = needsParentheses(actualExpression) ? createParen(actualExpression) : actualExpression; | ||
suppressLeadingAndTrailingTrivia(body); | ||
copyComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /* explicitHtnl */ false); | ||
} | ||
else { | ||
Debug.fail("invalid action"); | ||
} | ||
|
||
const edits = textChanges.ChangeTracker.with(context, t => updateBody(t, file, func, body)); | ||
return { renameFilename: undefined, renameLocation: undefined, edits }; | ||
} | ||
|
||
function needsParentheses(expression: Expression) { | ||
return isBinaryExpression(expression) && expression.operatorToken.kind === SyntaxKind.CommaToken || isObjectLiteralExpression(expression); | ||
} | ||
|
||
function updateBody(changeTracker: textChanges.ChangeTracker, file: SourceFile, container: ArrowFunction, body: ConciseBody) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason not to inline this? |
||
changeTracker.replaceNode(file, container.body, body); | ||
} | ||
|
||
function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number): Info | undefined { | ||
const node = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false); | ||
const func = getContainingFunction(node); | ||
if (!func || !isArrowFunction(func)) return undefined; | ||
|
||
if (isExpression(func.body)) { | ||
return { | ||
func, | ||
addBraces: true, | ||
expression: func.body | ||
}; | ||
} | ||
else if (func.body.statements.length === 1) { | ||
const firstStatement = first(func.body.statements); | ||
if (isReturnStatement(firstStatement)) { | ||
return { | ||
func, | ||
addBraces: false, | ||
expression: firstStatement.expression, | ||
returnStatement: firstStatement | ||
}; | ||
} | ||
} | ||
return undefined; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1649,4 +1649,20 @@ namespace ts { | |
Debug.assert(lastPos >= 0); | ||
return lastPos; | ||
} | ||
|
||
export function copyComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, explicitKind?: CommentKind, explicitHtnl?: boolean) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is "htnl"? |
||
forEachLeadingCommentRange(sourceFile.text, sourceNode.pos, (pos, end, kind, htnl) => { | ||
if (kind === SyntaxKind.MultiLineCommentTrivia) { | ||
// Remove leading /* | ||
pos += 2; | ||
// Remove trailing */ | ||
end -= 2; | ||
} | ||
else { | ||
// Remove leading // | ||
pos += 2; | ||
} | ||
addSyntheticLeadingComment(targetNode, explicitKind || kind, sourceFile.text.slice(pos, end), explicitHtnl !== undefined ? explicitHtnl : htnl); | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => a + 1; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Add braces to arrow function", | ||
actionDescription: "Add braces to arrow function", | ||
newContent: `const foo = a => { | ||
return a + 1; | ||
};`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { return (1, 2, 3); }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => (1, 2, 3);`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { return 1, 2, 3; }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => (1, 2, 3);`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { return "foo"; }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => "foo";`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { return null; }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => null;`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { return undefined; }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => undefined;`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { return void 0; }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => void 0;`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { return {}; }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => ({});`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { return `abc{a}`; }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => \`abc{a}\`;`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { return `abc`; }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => \`abc\`;`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { return a; }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => a;`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => ({ a: 1 }); | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Add braces to arrow function", | ||
actionDescription: "Add braces to arrow function", | ||
newContent: `const foo = a => { | ||
return ({ a: 1 }); | ||
};`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { | ||
//// // return comment | ||
//// return a; | ||
//// }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => /* return comment*/ a;`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => 1; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Add braces to arrow function", | ||
actionDescription: "Add braces to arrow function", | ||
newContent: `const foo = a => { | ||
return 1; | ||
};`, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
//// const foo = /*a*/a/*b*/ => { return a + 1; }; | ||
|
||
goTo.select("a", "b"); | ||
edit.applyRefactor({ | ||
refactorName: "Add or remove braces in an arrow function", | ||
actionName: "Remove braces from arrow function", | ||
actionDescription: "Remove braces from arrow function", | ||
newContent: `const foo = a => a + 1;`, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What changed here? Is this a merge artifact?