Skip to content

Commit 71a587f

Browse files
committed
More refactoring tests, some comment preservation and some fixed formatting of multiline tuples
1 parent cc8d392 commit 71a587f

13 files changed

+220
-34
lines changed

src/compiler/emitter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4980,7 +4980,7 @@ namespace ts {
49804980
}
49814981

49824982
function emitLeadingSynthesizedComment(comment: SynthesizedComment) {
4983-
if (comment.kind === SyntaxKind.SingleLineCommentTrivia) {
4983+
if (comment.hasLeadingNewline || comment.kind === SyntaxKind.SingleLineCommentTrivia) {
49844984
writer.writeLine();
49854985
}
49864986
writeSynthesizedComment(comment);

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2600,6 +2600,7 @@ namespace ts {
26002600
text: string;
26012601
pos: -1;
26022602
end: -1;
2603+
hasLeadingNewline?: boolean;
26032604
}
26042605

26052606
// represents a top level: { type } expression in a JSDoc comment.

src/services/formatting/smartIndenter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ namespace ts.formatting {
574574
return childKind !== SyntaxKind.JsxClosingFragment;
575575
case SyntaxKind.IntersectionType:
576576
case SyntaxKind.UnionType:
577-
if (childKind === SyntaxKind.TypeLiteral) {
577+
if (childKind === SyntaxKind.TypeLiteral || childKind === SyntaxKind.TupleType) {
578578
return false;
579579
}
580580
// falls through

src/services/refactors/convertOverloadListToSingleSignature.ts

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
2525
const signatureDecls = getConvertableOverloadListAtPosition(file, startPosition, program);
2626
if (!signatureDecls) return undefined;
2727

28+
const checker = program.getTypeChecker();
29+
2830
const lastDeclaration = signatureDecls[signatureDecls.length - 1];
2931
let updated = lastDeclaration;
3032
switch (lastDeclaration.kind) {
@@ -39,6 +41,21 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
3941
);
4042
break;
4143
}
44+
case SyntaxKind.MethodDeclaration: {
45+
updated = updateMethod(
46+
lastDeclaration,
47+
lastDeclaration.decorators,
48+
lastDeclaration.modifiers,
49+
lastDeclaration.asteriskToken,
50+
lastDeclaration.name,
51+
lastDeclaration.questionToken,
52+
lastDeclaration.typeParameters,
53+
getNewParametersForCombinedSignature(signatureDecls),
54+
lastDeclaration.type,
55+
lastDeclaration.body
56+
);
57+
break;
58+
}
4259
case SyntaxKind.CallSignature: {
4360
updated = updateCallSignature(
4461
lastDeclaration,
@@ -48,6 +65,16 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
4865
);
4966
break;
5067
}
68+
case SyntaxKind.Constructor: {
69+
updated = updateConstructor(
70+
lastDeclaration,
71+
lastDeclaration.decorators,
72+
lastDeclaration.modifiers,
73+
getNewParametersForCombinedSignature(signatureDecls),
74+
lastDeclaration.body
75+
);
76+
break;
77+
}
5178
case SyntaxKind.ConstructSignature: {
5279
updated = updateConstructSignature(
5380
lastDeclaration,
@@ -84,7 +111,12 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
84111

85112
return { renameFilename: undefined, renameLocation: undefined, edits };
86113

87-
function getNewParametersForCombinedSignature(signatureDeclarations: (MethodSignature | CallSignatureDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[]): NodeArray<ParameterDeclaration> {
114+
function getNewParametersForCombinedSignature(signatureDeclarations: (MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[]): NodeArray<ParameterDeclaration> {
115+
const lastSig = signatureDeclarations[signatureDeclarations.length - 1];
116+
if (isFunctionLikeDeclaration(lastSig) && lastSig.body) {
117+
// Trim away implementation signature arguments (they should already be compatible with overloads, but are likely less precise to guarantee compatability with the overloads)
118+
signatureDeclarations = signatureDeclarations.slice(0, signatureDeclarations.length - 1);
119+
}
88120
return createNodeArray([
89121
createParameter(
90122
/*decorators*/ undefined,
@@ -97,24 +129,56 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
97129
]);
98130
}
99131

100-
function convertSignatureParametersToTuple(decl: MethodSignature | CallSignatureDeclaration | ConstructSignatureDeclaration | FunctionDeclaration): TupleTypeNode {
101-
return setEmitFlags(createTupleTypeNode(map(decl.parameters, convertParameterToNamedTupleMember)), EmitFlags.SingleLine);
132+
function convertSignatureParametersToTuple(decl: MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration): TupleTypeNode {
133+
const members = map(decl.parameters, convertParameterToNamedTupleMember);
134+
return setEmitFlags(createTupleTypeNode(members), some(members, m => !!length(getSyntheticLeadingComments(m))) ? EmitFlags.None : EmitFlags.SingleLine);
102135
}
103136

104137
function convertParameterToNamedTupleMember(p: ParameterDeclaration): NamedTupleMember {
105138
Debug.assert(isIdentifier(p.name)); // This is checked during refactoring applicability checking
106-
return setTextRange(createNamedTupleMember(
139+
const result = setTextRange(createNamedTupleMember(
107140
p.dotDotDotToken,
108141
p.name,
109142
p.questionToken,
110143
p.type || createKeywordTypeNode(SyntaxKind.AnyKeyword)
111144
), p);
145+
const parameterDocComment = p.symbol && p.symbol.getDocumentationComment(checker);
146+
if (parameterDocComment) {
147+
const newComment = displayPartsToString(parameterDocComment);
148+
if (newComment.length) {
149+
setSyntheticLeadingComments(result, [{
150+
text: `*
151+
${newComment.split("\n").map(c => ` * ${c}`).join("\n")}
152+
`,
153+
kind: SyntaxKind.MultiLineCommentTrivia,
154+
pos: -1,
155+
end: -1,
156+
hasTrailingNewLine: true,
157+
hasLeadingNewline: true,
158+
}]);
159+
}
160+
}
161+
return result;
112162
}
163+
164+
}
165+
166+
function isConvertableSignatureDeclaration(d: Node): d is MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration {
167+
switch (d.kind) {
168+
case SyntaxKind.MethodSignature:
169+
case SyntaxKind.MethodDeclaration:
170+
case SyntaxKind.CallSignature:
171+
case SyntaxKind.Constructor:
172+
case SyntaxKind.ConstructSignature:
173+
case SyntaxKind.FunctionDeclaration:
174+
return true;
175+
}
176+
return false;
113177
}
114178

115179
function getConvertableOverloadListAtPosition(file: SourceFile, startPosition: number, program: Program) {
116180
const node = getTokenAtPosition(file, startPosition);
117-
const containingDecl = findAncestor(node, n => isFunctionLikeDeclaration(n));
181+
const containingDecl = findAncestor(node, isConvertableSignatureDeclaration);
118182
if (!containingDecl) {
119183
return;
120184
}
@@ -130,14 +194,14 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
130194
if (!every(decls, d => getSourceFileOfNode(d) === file)) {
131195
return;
132196
}
133-
const kindOne = decls[0].kind;
134-
if (kindOne !== SyntaxKind.MethodSignature && kindOne !== SyntaxKind.CallSignature && kindOne !== SyntaxKind.ConstructSignature && kindOne !== SyntaxKind.FunctionDeclaration) {
197+
if (!isConvertableSignatureDeclaration(decls[0])) {
135198
return;
136199
}
200+
const kindOne = decls[0].kind;
137201
if (!every(decls, d => d.kind === kindOne)) {
138202
return;
139203
}
140-
const signatureDecls = decls as (MethodSignature | CallSignatureDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[];
204+
const signatureDecls = decls as (MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[];
141205
if (some(signatureDecls, d => !!d.typeParameters || some(d.parameters, p => !!p.decorators || !!p.modifiers || !isIdentifier(p.name)))) {
142206
return;
143207
}

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,6 +1586,7 @@ declare namespace ts {
15861586
text: string;
15871587
pos: -1;
15881588
end: -1;
1589+
hasLeadingNewline?: boolean;
15891590
}
15901591
export interface JSDocTypeExpression extends TypeNode {
15911592
kind: SyntaxKind.JSDocTypeExpression;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,6 +1586,7 @@ declare namespace ts {
15861586
text: string;
15871587
pos: -1;
15881588
end: -1;
1589+
hasLeadingNewline?: boolean;
15891590
}
15901591
export interface JSDocTypeExpression extends TypeNode {
15911592
kind: SyntaxKind.JSDocTypeExpression;

tests/cases/fourslash/refactorOverloadListToSingleSignature2.ts

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,30 @@ edit.applyRefactor({
2020
refactorName: "Convert overload list to single signature",
2121
actionName: "Convert overload list to single signature",
2222
actionDescription: ts.Diagnostics.Convert_overload_list_to_single_signature.message,
23-
// Aspirational:
24-
// newContent: `declare function foo(...args: [] | [
25-
// /**
26-
// * a string param doc
27-
// */
28-
// a: string
29-
//] | [
30-
// /**
31-
// * a number param doc
32-
// */
33-
// a: number,
34-
// /**
35-
// * b number param doc
36-
// */
37-
// b: number
38-
//] | [
39-
// /**
40-
// * rest param doc
41-
// */
42-
// ...rest: symbol[]
43-
//]): void;`,
44-
// Actual:
45-
newContent: `/**
23+
// we don't delete the param comment on the signature we update because deleting *part* of a comment is... hard
24+
// and we definitely don't want to delete the whole comment. This is probably a good argument for why jsdoc should
25+
// really be uniformly handled as AST nodes, and transformed as such :(
26+
newContent: `/**
4627
* @param rest rest param doc
4728
*/
48-
declare function foo(...args: [] | [a: string] | [a: number, b: number] | [...rest: symbol[]]): void;`
29+
declare function foo(...args: [] | [
30+
/**
31+
* a string param doc
32+
*/
33+
a: string
34+
] | [
35+
/**
36+
* a number param doc
37+
*/
38+
a: number,
39+
/**
40+
* b number param doc
41+
*/
42+
b: number
43+
] | [
44+
/**
45+
* rest param doc
46+
*/
47+
...rest: symbol[]
48+
]): void;`,
4949
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
/////*a*/function foo(): void;
4+
////function foo(a: string): void;
5+
////function foo(a: number, b: number): void;
6+
////function foo(...rest: symbol[]): void;/*b*/
7+
////function foo(...args: any[]): void {
8+
//// // body
9+
////}
10+
11+
goTo.select("a", "b");
12+
edit.applyRefactor({
13+
refactorName: "Convert overload list to single signature",
14+
actionName: "Convert overload list to single signature",
15+
actionDescription: ts.Diagnostics.Convert_overload_list_to_single_signature.message,
16+
newContent: `function foo(...args: [] | [a: string] | [a: number, b: number] | [...rest: symbol[]]): void {
17+
// body
18+
}`,
19+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////class A {
4+
//// /*a*/foo(): void;
5+
//// foo(a: string): void;
6+
//// foo(a: number, b: number): void;
7+
//// foo(...rest: symbol[]): void;/*b*/
8+
//// foo(...args: any[]): void {
9+
//// // body
10+
//// }
11+
////}
12+
13+
goTo.select("a", "b");
14+
edit.applyRefactor({
15+
refactorName: "Convert overload list to single signature",
16+
actionName: "Convert overload list to single signature",
17+
actionDescription: ts.Diagnostics.Convert_overload_list_to_single_signature.message,
18+
newContent: `class A {
19+
foo(...args: [] | [a: string] | [a: number, b: number] | [...rest: symbol[]]): void {
20+
// body
21+
}
22+
}`,
23+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////class A {
4+
//// /*a*/constructor();
5+
//// constructor(a: string);
6+
//// constructor(a: number, b: number);
7+
//// constructor(...rest: symbol[]);/*b*/
8+
//// constructor(...args: any[]) {
9+
//// // body
10+
//// }
11+
////}
12+
13+
goTo.select("a", "b");
14+
edit.applyRefactor({
15+
refactorName: "Convert overload list to single signature",
16+
actionName: "Convert overload list to single signature",
17+
actionDescription: ts.Diagnostics.Convert_overload_list_to_single_signature.message,
18+
newContent: `class A {
19+
constructor(...args: [] | [a: string] | [a: number, b: number] | [...rest: symbol[]]) {
20+
// body
21+
}
22+
}`,
23+
});

0 commit comments

Comments
 (0)