Skip to content

Commit 6b754a9

Browse files
committed
Add quickfix for labeled tuple syntax mistakes
1 parent c7e115a commit 6b754a9

File tree

5 files changed

+77
-0
lines changed

5 files changed

+77
-0
lines changed

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -5693,6 +5693,10 @@
56935693
"category": "Message",
56945694
"code": 95116
56955695
},
5696+
"Move labeled tuple element modifiers to labels": {
5697+
"category": "Message",
5698+
"code": 95117
5699+
},
56965700

56975701
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
56985702
"category": "Error",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* @internal */
2+
namespace ts.codefix {
3+
const fixId = "fixIncorrectNamedTupleSyntax";
4+
const errorCodes = [
5+
Diagnostics.A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type.code,
6+
Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type.code
7+
];
8+
9+
registerCodeFix({
10+
errorCodes,
11+
getCodeActions: context => {
12+
const { sourceFile, span } = context;
13+
const namedTupleMember = getNamedTupleMember(sourceFile, span.start);
14+
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, namedTupleMember));
15+
return [createCodeFixAction(fixId, changes, Diagnostics.Move_labeled_tuple_element_modifiers_to_labels, fixId, Diagnostics.Move_labeled_tuple_element_modifiers_to_labels)];
16+
},
17+
fixIds: [fixId]
18+
});
19+
20+
function getNamedTupleMember(sourceFile: SourceFile, pos: number) {
21+
const token = getTokenAtPosition(sourceFile, pos);
22+
return findAncestor(token, t => t.kind === SyntaxKind.NamedTupleMember) as NamedTupleMember | undefined;
23+
}
24+
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, namedTupleMember?: NamedTupleMember) {
25+
if (!namedTupleMember) {
26+
return;
27+
}
28+
let unwrappedType = namedTupleMember.type;
29+
let sawOptional = false;
30+
let sawRest = false;
31+
while (unwrappedType.kind === SyntaxKind.OptionalType || unwrappedType.kind === SyntaxKind.RestType || unwrappedType.kind === SyntaxKind.ParenthesizedType) {
32+
if (unwrappedType.kind === SyntaxKind.OptionalType) {
33+
sawOptional = true;
34+
}
35+
else if (unwrappedType.kind === SyntaxKind.RestType) {
36+
sawRest = true;
37+
}
38+
unwrappedType = (unwrappedType as OptionalTypeNode | RestTypeNode | ParenthesizedTypeNode).type;
39+
}
40+
const updated = updateNamedTupleMember(
41+
namedTupleMember,
42+
namedTupleMember.dotDotDotToken || (sawRest ? createToken(SyntaxKind.DotDotDotToken) : undefined),
43+
namedTupleMember.name,
44+
namedTupleMember.questionToken || (sawOptional ? createToken(SyntaxKind.QuestionToken) : undefined),
45+
unwrappedType
46+
);
47+
if (updated === namedTupleMember) {
48+
return;
49+
}
50+
changes.replaceNode(sourceFile, namedTupleMember, updated);
51+
}
52+
}

src/services/tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"codefixes/fixClassIncorrectlyImplementsInterface.ts",
6565
"codefixes/importFixes.ts",
6666
"codefixes/fixImplicitThis.ts",
67+
"codefixes/fixIncorrectNamedTupleSyntax.ts",
6768
"codefixes/fixSpelling.ts",
6869
"codefixes/returnValueCorrect.ts",
6970
"codefixes/fixAddMissingMember.ts",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////type Tup = [first: string, elem: ...any[]];
4+
5+
verify.codeFix({
6+
description: "Move labeled tuple element modifiers to labels",
7+
index: 0,
8+
newFileContent:
9+
`type Tup = [first: string, ...elem: any[]];`
10+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////type Tup = [first: string, elem: any[]?];
4+
5+
verify.codeFix({
6+
description: "Move labeled tuple element modifiers to labels",
7+
index: 0,
8+
newFileContent:
9+
`type Tup = [first: string, elem?: any[]];`
10+
});

0 commit comments

Comments
 (0)