Skip to content

Commit ec00bb9

Browse files
Merge pull request #16697 from RyanCavanaugh/preserveMethodComments
Preserve method comments in JS->ES6 conversion.
2 parents ac72803 + 277f459 commit ec00bb9

File tree

2 files changed

+83
-8
lines changed

2 files changed

+83
-8
lines changed

src/services/refactors/convertFunctionToEs6Class.ts

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,15 @@ namespace ts.refactor {
164164
}
165165

166166
switch (assignmentBinaryExpression.right.kind) {
167-
case SyntaxKind.FunctionExpression:
167+
case SyntaxKind.FunctionExpression: {
168168
const functionExpression = assignmentBinaryExpression.right as FunctionExpression;
169-
return createMethod(/*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined,
169+
const method = createMethod(/*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined,
170170
/*typeParameters*/ undefined, functionExpression.parameters, /*type*/ undefined, functionExpression.body);
171+
copyComments(assignmentBinaryExpression, method);
172+
return method;
173+
}
171174

172-
case SyntaxKind.ArrowFunction:
175+
case SyntaxKind.ArrowFunction: {
173176
const arrowFunction = assignmentBinaryExpression.right as ArrowFunction;
174177
const arrowFunctionBody = arrowFunction.body;
175178
let bodyBlock: Block;
@@ -183,20 +186,42 @@ namespace ts.refactor {
183186
const expression = arrowFunctionBody as Expression;
184187
bodyBlock = createBlock([createReturn(expression)]);
185188
}
186-
return createMethod(/*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined,
189+
const method = createMethod(/*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined,
187190
/*typeParameters*/ undefined, arrowFunction.parameters, /*type*/ undefined, bodyBlock);
191+
copyComments(assignmentBinaryExpression, method);
192+
return method;
193+
}
188194

189-
default:
195+
default: {
190196
// Don't try to declare members in JavaScript files
191197
if (isSourceFileJavaScript(sourceFile)) {
192198
return;
193199
}
194-
return createProperty(/*decorators*/ undefined, modifiers, memberDeclaration.name, /*questionToken*/ undefined,
200+
const prop = createProperty(/*decorators*/ undefined, modifiers, memberDeclaration.name, /*questionToken*/ undefined,
195201
/*type*/ undefined, assignmentBinaryExpression.right);
202+
copyComments(assignmentBinaryExpression.parent, prop);
203+
return prop;
204+
}
196205
}
197206
}
198207
}
199208

209+
function copyComments(sourceNode: Node, targetNode: Node) {
210+
forEachLeadingCommentRange(sourceFile.text, sourceNode.pos, (pos, end, kind, htnl) => {
211+
if (kind === SyntaxKind.MultiLineCommentTrivia) {
212+
// Remove leading /*
213+
pos += 2;
214+
// Remove trailing */
215+
end -= 2;
216+
}
217+
else {
218+
// Remove leading //
219+
pos += 2;
220+
}
221+
addSyntheticLeadingComment(targetNode, kind, sourceFile.text.slice(pos, end), htnl);
222+
});
223+
}
224+
200225
function createClassFromVariableDeclaration(node: VariableDeclaration): ClassDeclaration {
201226
const initializer = node.initializer as FunctionExpression;
202227
if (!initializer || initializer.kind !== SyntaxKind.FunctionExpression) {
@@ -212,17 +237,22 @@ namespace ts.refactor {
212237
memberElements.unshift(createConstructor(/*decorators*/ undefined, /*modifiers*/ undefined, initializer.parameters, initializer.body));
213238
}
214239

215-
return createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, node.name,
240+
const cls = createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, node.name,
216241
/*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements);
242+
// Don't call copyComments here because we'll already leave them in place
243+
return cls;
217244
}
218245

219246
function createClassFromFunctionDeclaration(node: FunctionDeclaration): ClassDeclaration {
220247
const memberElements = createClassElementsFromSymbol(ctorSymbol);
221248
if (node.body) {
222249
memberElements.unshift(createConstructor(/*decorators*/ undefined, /*modifiers*/ undefined, node.parameters, node.body));
223250
}
224-
return createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, node.name,
251+
252+
const cls = createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, node.name,
225253
/*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements);
254+
// Don't call copyComments here because we'll already leave them in place
255+
return cls;
226256
}
227257
}
228258
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @allowNonTsExtensions: true
4+
// @Filename: test123.js
5+
//// function fn() {
6+
//// /** neat! */
7+
//// this.x = 100;
8+
//// }
9+
////
10+
//// /** awesome
11+
//// * stuff
12+
//// */
13+
//// fn.prototype.arr = () => { return ""; }
14+
//// /** great */
15+
//// fn.prototype.arr2 = () => [];
16+
////
17+
//// /**
18+
//// * This is a cool function!
19+
//// */
20+
//// /*1*/fn.prototype.bar = function (x, y, z) {
21+
//// this.x = y;
22+
//// };
23+
24+
verify.fileAfterApplyingRefactorAtMarker('1',
25+
`class fn {
26+
constructor() {
27+
/** neat! */
28+
this.x = 100;
29+
}
30+
/** awesome
31+
* stuff
32+
*/
33+
arr() { return ""; }
34+
/** great */
35+
arr2() { return []; }
36+
/**
37+
* This is a cool function!
38+
*/
39+
bar(x, y, z) {
40+
this.x = y;
41+
}
42+
}
43+
44+
45+
`, 'Convert to ES2015 class', 'convert');

0 commit comments

Comments
 (0)