-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Preserve method comments in JS->ES6 conversion. #16697
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
Changes from all commits
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 |
|---|---|---|
|
|
@@ -164,12 +164,15 @@ namespace ts.refactor { | |
| } | ||
|
|
||
| switch (assignmentBinaryExpression.right.kind) { | ||
| case SyntaxKind.FunctionExpression: | ||
| case SyntaxKind.FunctionExpression: { | ||
| const functionExpression = assignmentBinaryExpression.right as FunctionExpression; | ||
| return createMethod(/*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined, | ||
| const method = createMethod(/*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined, | ||
| /*typeParameters*/ undefined, functionExpression.parameters, /*type*/ undefined, functionExpression.body); | ||
| copyComments(assignmentBinaryExpression, method); | ||
| return method; | ||
| } | ||
|
|
||
| case SyntaxKind.ArrowFunction: | ||
| case SyntaxKind.ArrowFunction: { | ||
| const arrowFunction = assignmentBinaryExpression.right as ArrowFunction; | ||
| const arrowFunctionBody = arrowFunction.body; | ||
| let bodyBlock: Block; | ||
|
|
@@ -183,20 +186,42 @@ namespace ts.refactor { | |
| const expression = arrowFunctionBody as Expression; | ||
| bodyBlock = createBlock([createReturn(expression)]); | ||
| } | ||
| return createMethod(/*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined, | ||
| const method = createMethod(/*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined, | ||
| /*typeParameters*/ undefined, arrowFunction.parameters, /*type*/ undefined, bodyBlock); | ||
| copyComments(assignmentBinaryExpression, method); | ||
| return method; | ||
| } | ||
|
|
||
| default: | ||
| default: { | ||
| // Don't try to declare members in JavaScript files | ||
| if (isSourceFileJavaScript(sourceFile)) { | ||
| return; | ||
| } | ||
| return createProperty(/*decorators*/ undefined, modifiers, memberDeclaration.name, /*questionToken*/ undefined, | ||
| const prop = createProperty(/*decorators*/ undefined, modifiers, memberDeclaration.name, /*questionToken*/ undefined, | ||
|
Contributor
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. Can you add a test for this?
Member
Author
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.
Contributor
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. That only hits the code path on L167. It doesn't cover the cases on L186 and L189.
Member
Author
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. This is actually currently unreachable since this refactor doesn't light up in non-JS files
Contributor
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. Fair point regarding the property declaration, but arrow functions are still fair game. |
||
| /*type*/ undefined, assignmentBinaryExpression.right); | ||
| copyComments(assignmentBinaryExpression.parent, prop); | ||
| return prop; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| function copyComments(sourceNode: Node, targetNode: Node) { | ||
| 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, kind, sourceFile.text.slice(pos, end), htnl); | ||
| }); | ||
| } | ||
|
|
||
| function createClassFromVariableDeclaration(node: VariableDeclaration): ClassDeclaration { | ||
| const initializer = node.initializer as FunctionExpression; | ||
| if (!initializer || initializer.kind !== SyntaxKind.FunctionExpression) { | ||
|
|
@@ -212,17 +237,22 @@ namespace ts.refactor { | |
| memberElements.unshift(createConstructor(/*decorators*/ undefined, /*modifiers*/ undefined, initializer.parameters, initializer.body)); | ||
| } | ||
|
|
||
| return createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, node.name, | ||
| const cls = createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, node.name, | ||
| /*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements); | ||
| // Don't call copyComments here because we'll already leave them in place | ||
| return cls; | ||
| } | ||
|
|
||
| function createClassFromFunctionDeclaration(node: FunctionDeclaration): ClassDeclaration { | ||
| const memberElements = createClassElementsFromSymbol(ctorSymbol); | ||
| if (node.body) { | ||
| memberElements.unshift(createConstructor(/*decorators*/ undefined, /*modifiers*/ undefined, node.parameters, node.body)); | ||
| } | ||
| return createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, node.name, | ||
|
|
||
| const cls = createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, node.name, | ||
| /*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements); | ||
| // Don't call copyComments here because we'll already leave them in place | ||
| return cls; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| /// <reference path='fourslash.ts' /> | ||
|
|
||
| // @allowNonTsExtensions: true | ||
| // @Filename: test123.js | ||
| //// function fn() { | ||
| //// /** neat! */ | ||
| //// this.x = 100; | ||
| //// } | ||
| //// | ||
| //// /** awesome | ||
| //// * stuff | ||
| //// */ | ||
| //// fn.prototype.arr = () => { return ""; } | ||
| //// /** great */ | ||
| //// fn.prototype.arr2 = () => []; | ||
| //// | ||
| //// /** | ||
| //// * This is a cool function! | ||
| //// */ | ||
| //// /*1*/fn.prototype.bar = function (x, y, z) { | ||
| //// this.x = y; | ||
| //// }; | ||
|
|
||
| verify.fileAfterApplyingRefactorAtMarker('1', | ||
| `class fn { | ||
| constructor() { | ||
| /** neat! */ | ||
| this.x = 100; | ||
| } | ||
| /** awesome | ||
| * stuff | ||
| */ | ||
| arr() { return ""; } | ||
| /** great */ | ||
| arr2() { return []; } | ||
| /** | ||
| * This is a cool function! | ||
| */ | ||
| bar(x, y, z) { | ||
| this.x = y; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| `, 'Convert to ES2015 class', 'convert'); |
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.
Can you add a test for this?
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.
Not related to comments, but do we preserve the binding to the
thisof the outer scope if the arrow contains athis? What happens if we refactor: