forked from microsoft/TypeScript
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathfixJSDocTypes.ts
More file actions
83 lines (79 loc) · 4.56 KB
/
fixJSDocTypes.ts
File metadata and controls
83 lines (79 loc) · 4.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/* @internal */
namespace ts.codefix {
const fixIdPlain = "fixJSDocTypes_plain";
const fixIdNullable = "fixJSDocTypes_nullable";
const errorCodes = [Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments.code];
registerCodeFix({
errorCodes,
getCodeActions(context) {
const { sourceFile } = context;
const checker = context.program.getTypeChecker();
const info = getInfo(sourceFile, context.span.start, checker);
if (!info) return undefined;
const { typeNode, type } = info;
const original = typeNode.getText(sourceFile);
const actions = [fix(type, fixIdPlain, Diagnostics.Change_all_jsdoc_style_types_to_TypeScript)];
if (typeNode.kind === SyntaxKind.JSDocNullableType) {
// for nullable types, suggest the flow-compatible `T | null | undefined`
// in addition to the jsdoc/closure-compatible `T | null`
actions.push(fix(checker.getNullableType(type, TypeFlags.Undefined), fixIdNullable, Diagnostics.Change_all_jsdoc_style_types_to_TypeScript_and_add_undefined_to_nullable_types));
}
return actions;
function fix(type: Type, fixId: string, fixAllDescription: DiagnosticMessage): CodeFixAction {
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, typeNode, type, checker));
return createCodeFixAction("jdocTypes", changes, [Diagnostics.Change_0_to_1, original, checker.typeToString(type)], fixId, fixAllDescription);
}
},
fixIds: [fixIdPlain, fixIdNullable],
getAllCodeActions(context) {
const { fixId, program, sourceFile } = context;
const checker = program.getTypeChecker();
return codeFixAll(context, errorCodes, (changes, err) => {
const info = getInfo(err.file, err.start, checker);
if (!info) return;
const { typeNode, type } = info;
const fixedType = typeNode.kind === SyntaxKind.JSDocNullableType && fixId === fixIdNullable ? checker.getNullableType(type, TypeFlags.Undefined) : type;
doChange(changes, sourceFile, typeNode, fixedType, checker);
});
}
});
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, oldTypeNode: TypeNode, newType: Type, checker: TypeChecker): void {
changes.replaceNode(sourceFile, oldTypeNode, checker.typeToTypeNode(newType, /*enclosingDeclaration*/ oldTypeNode, /*flags*/ undefined)!); // TODO: GH#18217
}
function getInfo(sourceFile: SourceFile, pos: number, checker: TypeChecker): { readonly typeNode: TypeNode, readonly type: Type } | undefined {
const decl = findAncestor(getTokenAtPosition(sourceFile, pos), isTypeContainer);
const typeNode = decl && decl.type;
return typeNode && { typeNode, type: checker.getTypeFromTypeNode(typeNode) };
}
// TODO: GH#19856 Node & { type: TypeNode }
type TypeContainer =
| AsExpression | CallSignatureDeclaration | ConstructSignatureDeclaration | FunctionDeclaration
| GetAccessorDeclaration | IndexSignatureDeclaration | MappedTypeNode | MethodDeclaration
| MethodSignature | ParameterDeclaration | PropertyDeclaration | PropertySignature | SetAccessorDeclaration
| TypeAliasDeclaration | TypeAssertion | VariableDeclaration;
function isTypeContainer(node: Node): node is TypeContainer {
// NOTE: Some locations are not handled yet:
// MappedTypeNode.typeParameters and SignatureDeclaration.typeParameters, as well as CallExpression.typeArguments
switch (node.kind) {
case SyntaxKind.AsExpression:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.IndexSignature:
case SyntaxKind.MappedType:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.Parameter:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.SetAccessor:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.VariableDeclaration:
return true;
default:
return false;
}
}
}