mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Fix "Extract to type alias" not available at end of span (#56467)
Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com>
This commit is contained in:
parent
e441420483
commit
b2c6a56e38
@ -23,6 +23,7 @@ import {
|
||||
getRefactorContextSpan,
|
||||
getRenameLocation,
|
||||
getTokenAtPosition,
|
||||
getTouchingToken,
|
||||
getUniqueName,
|
||||
ignoreSourceNewlines,
|
||||
isArray,
|
||||
@ -173,14 +174,9 @@ type ExtractInfo = TypeAliasInfo | InterfaceInfo;
|
||||
function getRangeToExtract(context: RefactorContext, considerEmptySpans = true): ExtractInfo | RefactorErrorInfo | undefined {
|
||||
const { file, startPosition } = context;
|
||||
const isJS = isSourceFileJS(file);
|
||||
const current = getTokenAtPosition(file, startPosition);
|
||||
const range = createTextRangeFromSpan(getRefactorContextSpan(context));
|
||||
const cursorRequest = range.pos === range.end && considerEmptySpans;
|
||||
const overlappingRange = nodeOverlapsWithStartEnd(current, file, range.pos, range.end);
|
||||
|
||||
const firstType = findAncestor(current, node =>
|
||||
node.parent && isTypeNode(node) && !rangeContainsSkipTrivia(range, node.parent, file) &&
|
||||
(cursorRequest || overlappingRange));
|
||||
const isCursorRequest = range.pos === range.end && considerEmptySpans;
|
||||
const firstType = getFirstTypeAt(file, startPosition, range, isCursorRequest);
|
||||
if (!firstType || !isTypeNode(firstType)) return { error: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_type_node) };
|
||||
|
||||
const checker = context.program.getTypeChecker();
|
||||
@ -209,6 +205,24 @@ function getRangeToExtract(context: RefactorContext, considerEmptySpans = true):
|
||||
return { isJS, selection, enclosingNode, typeParameters, typeElements };
|
||||
}
|
||||
|
||||
function getFirstTypeAt(file: SourceFile, startPosition: number, range: TextRange, isCursorRequest: boolean): Node | undefined {
|
||||
const currentNodes = [
|
||||
() => getTokenAtPosition(file, startPosition),
|
||||
() => getTouchingToken(file, startPosition, () => true),
|
||||
];
|
||||
for (const f of currentNodes) {
|
||||
const current = f();
|
||||
const overlappingRange = nodeOverlapsWithStartEnd(current, file, range.pos, range.end);
|
||||
const firstType = findAncestor(current, node =>
|
||||
node.parent && isTypeNode(node) && !rangeContainsSkipTrivia(range, node.parent, file) &&
|
||||
(isCursorRequest || overlappingRange));
|
||||
if (firstType) {
|
||||
return firstType;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function flattenTypeLiteralNodeReference(checker: TypeChecker, selection: TypeNode | TypeNode[] | undefined): readonly TypeElement[] | undefined {
|
||||
if (!selection) return undefined;
|
||||
if (isArray(selection)) {
|
||||
|
||||
61
tests/cases/fourslash/refactorExtractType89.ts
Normal file
61
tests/cases/fourslash/refactorExtractType89.ts
Normal file
@ -0,0 +1,61 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface Yadda<T> { x: T }
|
||||
////
|
||||
//// export let blah: Yadda/*a*/<string>/*b*/;
|
||||
////
|
||||
//// interface YaddaWithDefault<T = boolean/*c*/> { x: T/*d*/ }
|
||||
|
||||
goTo.marker("a");
|
||||
verify.refactorAvailableForTriggerReason("invoked", "Extract type", "Extract to type alias")
|
||||
|
||||
goTo.marker("b");
|
||||
edit.applyRefactor({
|
||||
triggerReason: "invoked",
|
||||
refactorName: "Extract type",
|
||||
actionName: "Extract to type alias",
|
||||
actionDescription: "Extract to type alias",
|
||||
newContent: `interface Yadda<T> { x: T }
|
||||
|
||||
type /*RENAME*/NewType = Yadda<string>;
|
||||
|
||||
export let blah: NewType;
|
||||
|
||||
interface YaddaWithDefault<T = boolean> { x: T }`,
|
||||
});
|
||||
|
||||
goTo.marker("c");
|
||||
edit.applyRefactor({
|
||||
triggerReason: "invoked",
|
||||
refactorName: "Extract type",
|
||||
actionName: "Extract to type alias",
|
||||
actionDescription: "Extract to type alias",
|
||||
newContent: `interface Yadda<T> { x: T }
|
||||
|
||||
type NewType = Yadda<string>;
|
||||
|
||||
export let blah: NewType;
|
||||
|
||||
type /*RENAME*/NewType_1 = boolean;
|
||||
|
||||
interface YaddaWithDefault<T = NewType_1> { x: T }`
|
||||
});
|
||||
|
||||
goTo.marker("d");
|
||||
edit.applyRefactor({
|
||||
triggerReason: "invoked",
|
||||
refactorName: "Extract type",
|
||||
actionName: "Extract to type alias",
|
||||
actionDescription: "Extract to type alias",
|
||||
newContent: `interface Yadda<T> { x: T }
|
||||
|
||||
type NewType = Yadda<string>;
|
||||
|
||||
export let blah: NewType;
|
||||
|
||||
type NewType_1 = boolean;
|
||||
|
||||
type /*RENAME*/NewType_2<T> = T;
|
||||
|
||||
interface YaddaWithDefault<T = NewType_1> { x: NewType_2<T> }`
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user