Codefix for ?! pre/postfix JSDoc types
For ?, provide two code fixes, one for jsdoc/closure semantics (`?t -> t | null)` and one for flow semantics (`?t -> t | null | undefined`). The current way of doing this is the hackiest thing you can imagine, but it was easier than lifting everything into the list monad for a code fix that I might not actually keep.
This commit is contained in:
parent
3776b0b58b
commit
f9e5576d58
|
@ -11,41 +11,64 @@ namespace ts.codefix {
|
|||
const decl = ts.findAncestor(node, n => n.kind === SyntaxKind.VariableDeclaration);
|
||||
if (!decl) return;
|
||||
const jsdocType = (decl as VariableDeclaration).type;
|
||||
let cheesyHacks = false;
|
||||
|
||||
// TODO: Only if get(jsdoctype) !== jsdoctype
|
||||
// TODO: Create cheesy hacks to support | null | undefined -- just flip a boolean and rerun with that boolean set
|
||||
|
||||
const trk = textChanges.ChangeTracker.fromCodeFixContext(context);
|
||||
trk.replaceNode(sourceFile, jsdocType, getTypeFromJSDocType(jsdocType));
|
||||
return [{
|
||||
const changes = [{
|
||||
// TODO: This seems like the LEAST SAFE way to get the new text
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Change_0_to_1), [getTextOfNode(jsdocType), trk.getChanges()[0].textChanges[0].newText]),
|
||||
changes: trk.getChanges(),
|
||||
}];
|
||||
}
|
||||
|
||||
function getTypeFromJSDocType(type: TypeNode): TypeNode {
|
||||
switch (type.kind) {
|
||||
case SyntaxKind.JSDocUnknownType:
|
||||
case SyntaxKind.JSDocAllType:
|
||||
return createToken(SyntaxKind.AnyKeyword) as TypeNode;
|
||||
case SyntaxKind.JSDocVariadicType:
|
||||
return createArrayTypeNode(getTypeFromJSDocType((type as JSDocVariadicType).type));
|
||||
case SyntaxKind.ArrayType:
|
||||
// TODO: Only create an error if the get(type.type) !== type.type.
|
||||
return createArrayTypeNode(getTypeFromJSDocType((type as ArrayTypeNode).elementType));
|
||||
case SyntaxKind.TypeReference:
|
||||
return getTypeReferenceFromJSDocType(type as TypeReferenceNode);
|
||||
case SyntaxKind.Identifier:
|
||||
return type;
|
||||
if (cheesyHacks) {
|
||||
const trk = textChanges.ChangeTracker.fromCodeFixContext(context);
|
||||
trk.replaceNode(sourceFile, jsdocType, getTypeFromJSDocType(jsdocType));
|
||||
changes.push({
|
||||
// TODO: This seems like the LEAST SAFE way to get the new text
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Change_0_to_1), [getTextOfNode(jsdocType), trk.getChanges()[0].textChanges[0].newText]),
|
||||
changes: trk.getChanges(),
|
||||
});
|
||||
}
|
||||
// TODO: Need to recur on all relevant nodes. Is a call to visit enough?
|
||||
return type;
|
||||
}
|
||||
return changes;
|
||||
|
||||
function getTypeReferenceFromJSDocType(type: TypeReferenceNode) {
|
||||
if (type.typeArguments && type.typeName.jsdocDotPos) {
|
||||
return createTypeReferenceNode(type.typeName, map(type.typeArguments, getTypeFromJSDocType));
|
||||
function getTypeFromJSDocType(type: TypeNode): TypeNode {
|
||||
switch (type.kind) {
|
||||
case SyntaxKind.JSDocUnknownType:
|
||||
case SyntaxKind.JSDocAllType:
|
||||
return createToken(SyntaxKind.AnyKeyword) as TypeNode;
|
||||
case SyntaxKind.JSDocVariadicType:
|
||||
return createArrayTypeNode(getTypeFromJSDocType((type as JSDocVariadicType).type));
|
||||
case SyntaxKind.JSDocNullableType:
|
||||
if (cheesyHacks) {
|
||||
return createUnionTypeNode([getTypeFromJSDocType((type as JSDocNullableType).type), createNull(), createToken(SyntaxKind.UndefinedKeyword) as TypeNode]);
|
||||
}
|
||||
else {
|
||||
cheesyHacks = true;
|
||||
return createUnionTypeNode([getTypeFromJSDocType((type as JSDocNullableType).type), createNull()]);
|
||||
}
|
||||
case SyntaxKind.JSDocNonNullableType:
|
||||
return getTypeFromJSDocType((type as JSDocNullableType).type);
|
||||
case SyntaxKind.ArrayType:
|
||||
// TODO: Only create an error if the get(type.type) !== type.type.
|
||||
return createArrayTypeNode(getTypeFromJSDocType((type as ArrayTypeNode).elementType));
|
||||
case SyntaxKind.TypeReference:
|
||||
return getTypeReferenceFromJSDocType(type as TypeReferenceNode);
|
||||
case SyntaxKind.Identifier:
|
||||
return type;
|
||||
}
|
||||
// TODO: Need to recur on all relevant nodes. Is a call to visit enough?
|
||||
return type;
|
||||
}
|
||||
|
||||
function getTypeReferenceFromJSDocType(type: TypeReferenceNode) {
|
||||
if (type.typeArguments && type.typeName.jsdocDotPos) {
|
||||
return createTypeReferenceNode(type.typeName, map(type.typeArguments, getTypeFromJSDocType));
|
||||
}
|
||||
return getTypeFromJSDocType(type);
|
||||
}
|
||||
return getTypeFromJSDocType(type);
|
||||
}
|
||||
}
|
||||
|
|
4
tests/cases/fourslash/codeFixChangeJSDocSyntax5.ts
Normal file
4
tests/cases/fourslash/codeFixChangeJSDocSyntax5.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
//// var x: [|?number|] = 12;
|
||||
|
||||
verify.rangeAfterCodeFix("number | null", /*includeWhiteSpace*/ false, /*errorCode*/ 8020, 0);
|
4
tests/cases/fourslash/codeFixChangeJSDocSyntax6.ts
Normal file
4
tests/cases/fourslash/codeFixChangeJSDocSyntax6.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
//// var x: [|number?|] = 12;
|
||||
|
||||
verify.rangeAfterCodeFix("number | null | undefined", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, 1);
|
4
tests/cases/fourslash/codeFixChangeJSDocSyntax7.ts
Normal file
4
tests/cases/fourslash/codeFixChangeJSDocSyntax7.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
//// var x: [|!number|] = 12;
|
||||
|
||||
verify.rangeAfterCodeFix("number");
|
Loading…
Reference in a new issue