Skip to content

Commit 1a05f13

Browse files
author
Andy
authored
moveToNewFile: Don't remove empty named imports (#26265)
1 parent 794f3a5 commit 1a05f13

File tree

3 files changed

+25
-17
lines changed

3 files changed

+25
-17
lines changed

src/harness/fourslash.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2985,7 +2985,7 @@ Actual: ${stringify(fullActual)}`);
29852985
}
29862986

29872987
public verifyApplicableRefactorAvailableAtMarker(negative: boolean, markerName: string) {
2988-
const isAvailable = this.getApplicableRefactors(this.getMarkerByName(markerName).position).length > 0;
2988+
const isAvailable = this.getApplicableRefactors(this.getMarkerByName(markerName)).length > 0;
29892989
if (negative && isAvailable) {
29902990
this.raiseError(`verifyApplicableRefactorAvailableAtMarker failed - expected no refactor at marker ${markerName} but found some.`);
29912991
}
@@ -3002,7 +3002,7 @@ Actual: ${stringify(fullActual)}`);
30023002
}
30033003

30043004
public verifyRefactorAvailable(negative: boolean, name: string, actionName?: string) {
3005-
let refactors = this.getApplicableRefactors(this.getSelection());
3005+
let refactors = this.getApplicableRefactorsAtSelection();
30063006
refactors = refactors.filter(r => r.name === name && (actionName === undefined || r.actions.some(a => a.name === actionName)));
30073007
const isAvailable = refactors.length > 0;
30083008

@@ -3022,11 +3022,11 @@ Actual: ${stringify(fullActual)}`);
30223022
}
30233023

30243024
public verifyRefactorsAvailable(names: ReadonlyArray<string>): void {
3025-
assert.deepEqual(unique(this.getApplicableRefactors(this.getSelection()), r => r.name), names);
3025+
assert.deepEqual(unique(this.getApplicableRefactorsAtSelection(), r => r.name), names);
30263026
}
30273027

30283028
public verifyRefactor({ name, actionName, refactors }: FourSlashInterface.VerifyRefactorOptions) {
3029-
const actualRefactors = this.getApplicableRefactors(this.getSelection()).filter(r => r.name === name && r.actions.some(a => a.name === actionName));
3029+
const actualRefactors = this.getApplicableRefactorsAtSelection().filter(r => r.name === name && r.actions.some(a => a.name === actionName));
30303030
this.assertObjectsEqual(actualRefactors, refactors);
30313031
}
30323032

@@ -3047,7 +3047,7 @@ Actual: ${stringify(fullActual)}`);
30473047

30483048
public applyRefactor({ refactorName, actionName, actionDescription, newContent: newContentWithRenameMarker }: FourSlashInterface.ApplyRefactorOptions) {
30493049
const range = this.getSelection();
3050-
const refactors = this.getApplicableRefactors(range);
3050+
const refactors = this.getApplicableRefactorsAtSelection();
30513051
const refactorsWithName = refactors.filter(r => r.name === refactorName);
30523052
if (refactorsWithName.length === 0) {
30533053
this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.\nAvailable refactors: ${refactors.map(r => r.name)}`);
@@ -3125,7 +3125,7 @@ Actual: ${stringify(fullActual)}`);
31253125
const action = ts.first(refactor.actions);
31263126
assert(action.name === "Move to a new file" && action.description === "Move to a new file");
31273127

3128-
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.emptyOptions)!;
3128+
const editInfo = this.languageService.getEditsForRefactor(range.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.emptyOptions)!;
31293129
this.testNewFileContents(editInfo.edits, options.newFileContents, "move to new file");
31303130
}
31313131

@@ -3165,21 +3165,21 @@ Actual: ${stringify(fullActual)}`);
31653165
formattingOptions?: ts.FormatCodeSettings) {
31663166

31673167
formattingOptions = formattingOptions || this.formatCodeSettings;
3168-
const markerPos = this.getMarkerByName(markerName).position;
3168+
const marker = this.getMarkerByName(markerName);
31693169

3170-
const applicableRefactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, markerPos, ts.emptyOptions);
3170+
const applicableRefactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, marker.position, ts.emptyOptions);
31713171
const applicableRefactorToApply = ts.find(applicableRefactors, refactor => refactor.name === refactorNameToApply);
31723172

31733173
if (!applicableRefactorToApply) {
31743174
this.raiseError(`The expected refactor: ${refactorNameToApply} is not available at the marker location.`);
31753175
}
31763176

3177-
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply, actionName, ts.emptyOptions)!;
3177+
const editInfo = this.languageService.getEditsForRefactor(marker.fileName, formattingOptions, marker.position, refactorNameToApply, actionName, ts.emptyOptions)!;
31783178

31793179
for (const edit of editInfo.edits) {
31803180
this.applyEdits(edit.fileName, edit.textChanges, /*isFormattingEdit*/ false);
31813181
}
3182-
const actualContent = this.getFileContent(this.activeFile.fileName);
3182+
const actualContent = this.getFileContent(marker.fileName);
31833183

31843184
if (actualContent !== expectedContent) {
31853185
this.raiseError(`verifyFileAfterApplyingRefactors failed:\n${showTextDiff(expectedContent, actualContent)}`);
@@ -3381,8 +3381,14 @@ Actual: ${stringify(fullActual)}`);
33813381
test(renameKeys(newFileContents, key => pathUpdater(key) || key), "with file moved");
33823382
}
33833383

3384-
private getApplicableRefactors(positionOrRange: number | ts.TextRange, preferences = ts.emptyOptions): ReadonlyArray<ts.ApplicableRefactorInfo> {
3385-
return this.languageService.getApplicableRefactors(this.activeFile.fileName, positionOrRange, preferences) || ts.emptyArray;
3384+
private getApplicableRefactorsAtSelection() {
3385+
return this.getApplicableRefactorsWorker(this.getSelection(), this.activeFile.fileName);
3386+
}
3387+
private getApplicableRefactors(rangeOrMarker: Range | Marker, preferences = ts.emptyOptions): ReadonlyArray<ts.ApplicableRefactorInfo> {
3388+
return this.getApplicableRefactorsWorker("position" in rangeOrMarker ? rangeOrMarker.position : rangeOrMarker, rangeOrMarker.fileName, preferences);
3389+
}
3390+
private getApplicableRefactorsWorker(positionOrRange: number | ts.TextRange, fileName: string, preferences = ts.emptyOptions): ReadonlyArray<ts.ApplicableRefactorInfo> {
3391+
return this.languageService.getApplicableRefactors(fileName, positionOrRange, preferences) || ts.emptyArray;
33863392
}
33873393
}
33883394

src/services/refactors/moveToNewFile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ namespace ts.refactor {
340340
const { name, namedBindings } = importDecl.importClause;
341341
const defaultUnused = !name || isUnused(name);
342342
const namedBindingsUnused = !namedBindings ||
343-
(namedBindings.kind === SyntaxKind.NamespaceImport ? isUnused(namedBindings.name) : namedBindings.elements.every(e => isUnused(e.name)));
343+
(namedBindings.kind === SyntaxKind.NamespaceImport ? isUnused(namedBindings.name) : namedBindings.elements.length !== 0 && namedBindings.elements.every(e => isUnused(e.name)));
344344
if (defaultUnused && namedBindingsUnused) {
345345
changes.delete(sourceFile, importDecl);
346346
}

tests/cases/fourslash/moveToNewFile_updateUses.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66

77
// @Filename: /user.ts
88
////import { x, y } from "./a";
9-
////
10-
11-
// TODO: GH#23728 Shouldn't need `////` above
9+
////import { x as x2 } from "./a";
10+
////import { y as y2 } from "./a";
11+
////import {} from "./a";
1212

1313
verify.moveToNewFile({
1414
newFileContents: {
@@ -22,6 +22,8 @@ verify.moveToNewFile({
2222
"/user.ts":
2323
`import { x } from "./a";
2424
import { y } from "./y";
25-
`,
25+
import { x as x2 } from "./a";
26+
import { y as y2 } from "./y";
27+
import {} from "./a";`,
2628
},
2729
});

0 commit comments

Comments
 (0)