Skip to content

Commit 1e01c99

Browse files
feat: implement 'source.removeUnusedImports' code action (#2875)
* feat: implement 'source.removeUnusedImports' code action * add source action kind to server capability; revert code action removal * add changeset
1 parent cadf62e commit 1e01c99

File tree

4 files changed

+138
-15
lines changed

4 files changed

+138
-15
lines changed

.changeset/wide-emus-turn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte-language-server': minor
3+
---
4+
5+
feat: implement 'source.removeUnusedImports' code action

packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { internalHelpers } from 'svelte2tsx';
2-
import ts from 'typescript';
2+
import ts, { OrganizeImportsMode } from 'typescript';
33
import {
44
CancellationToken,
55
CodeAction,
@@ -65,6 +65,7 @@ import {
6565
*/
6666
export const SORT_IMPORT_CODE_ACTION_KIND = 'source.sortImports';
6767
export const ADD_MISSING_IMPORTS_CODE_ACTION_KIND = 'source.addMissingImports';
68+
export const REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND = 'source.removeUnusedImports';
6869

6970
interface RefactorArgs {
7071
type: 'refactor';
@@ -120,7 +121,15 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
120121
return await this.organizeImports(
121122
document,
122123
cancellationToken,
123-
/**skipDestructiveCodeActions */ true
124+
OrganizeImportsMode.SortAndCombine
125+
);
126+
}
127+
128+
if (context.only?.[0] === REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND) {
129+
return await this.organizeImports(
130+
document,
131+
cancellationToken,
132+
OrganizeImportsMode.RemoveUnused
124133
);
125134
}
126135

@@ -136,7 +145,12 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
136145
...(await this.organizeImports(
137146
document,
138147
cancellationToken,
139-
/**skipDestructiveCodeActions */ true
148+
OrganizeImportsMode.SortAndCombine
149+
)),
150+
...(await this.organizeImports(
151+
document,
152+
cancellationToken,
153+
OrganizeImportsMode.RemoveUnused
140154
)),
141155
...(await this.addMissingImports(document, cancellationToken))
142156
];
@@ -406,7 +420,7 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
406420
private async organizeImports(
407421
document: Document,
408422
cancellationToken: CancellationToken | undefined,
409-
skipDestructiveCodeActions = false
423+
mode: OrganizeImportsMode = OrganizeImportsMode.All
410424
): Promise<CodeAction[]> {
411425
if (!document.scriptInfo && !document.moduleScriptInfo) {
412426
return [];
@@ -425,7 +439,7 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
425439
{
426440
fileName: tsDoc.filePath,
427441
type: 'file',
428-
skipDestructiveCodeActions
442+
mode
429443
},
430444
{
431445
...(await this.configManager.getFormatCodeSettingsForFile(
@@ -475,15 +489,26 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
475489
this.checkIndentLeftover(change, document);
476490
}
477491

478-
return [
479-
CodeAction.create(
480-
skipDestructiveCodeActions ? 'Sort Imports' : 'Organize Imports',
481-
{ documentChanges },
482-
skipDestructiveCodeActions
483-
? SORT_IMPORT_CODE_ACTION_KIND
484-
: CodeActionKind.SourceOrganizeImports
485-
)
486-
];
492+
let kind: CodeActionKind;
493+
let title: string;
494+
495+
switch (mode) {
496+
case OrganizeImportsMode.SortAndCombine:
497+
kind = SORT_IMPORT_CODE_ACTION_KIND;
498+
title = 'Sort Imports';
499+
break;
500+
501+
case OrganizeImportsMode.RemoveUnused:
502+
kind = REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND;
503+
title = 'Remove Unused Imports';
504+
break;
505+
506+
default:
507+
kind = CodeActionKind.SourceOrganizeImports;
508+
title = 'Organize Imports';
509+
}
510+
511+
return [CodeAction.create(title, { documentChanges }, kind)];
487512
}
488513

489514
private fixIndentationOfImports(edit: TextEdit, document: Document): TextEdit {

packages/language-server/src/server.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ import { configLoader } from './lib/documents/configLoader';
4747
import { setIsTrusted } from './importPackage';
4848
import {
4949
SORT_IMPORT_CODE_ACTION_KIND,
50-
ADD_MISSING_IMPORTS_CODE_ACTION_KIND
50+
ADD_MISSING_IMPORTS_CODE_ACTION_KIND,
51+
REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND
5152
} from './plugins/typescript/features/CodeActionsProvider';
5253
import { createLanguageServices } from './plugins/css/service';
5354
import { FileSystemProvider } from './plugins/css/FileSystemProvider';
@@ -274,6 +275,7 @@ export function startServer(options?: LSOptions) {
274275
CodeActionKind.SourceOrganizeImports,
275276
SORT_IMPORT_CODE_ACTION_KIND,
276277
ADD_MISSING_IMPORTS_CODE_ACTION_KIND,
278+
REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND,
277279
...(clientSupportApplyEditCommand ? [CodeActionKind.Refactor] : [])
278280
].filter(
279281
clientSupportedCodeActionKinds &&

packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { LSConfigManager } from '../../../../src/ls-config';
1616
import {
1717
ADD_MISSING_IMPORTS_CODE_ACTION_KIND,
1818
CodeActionsProviderImpl,
19+
REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND,
1920
SORT_IMPORT_CODE_ACTION_KIND
2021
} from '../../../../src/plugins/typescript/features/CodeActionsProvider';
2122
import { CompletionsProviderImpl } from '../../../../src/plugins/typescript/features/CompletionProvider';
@@ -1550,6 +1551,96 @@ describe('CodeActionsProvider', function () {
15501551
]);
15511552
});
15521553

1554+
it('removes unused imports', async () => {
1555+
const { provider, document } = setup('codeactions.svelte');
1556+
1557+
const codeActions = await provider.getCodeActions(
1558+
document,
1559+
Range.create(Position.create(1, 4), Position.create(1, 5)),
1560+
{
1561+
diagnostics: [],
1562+
only: [REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND]
1563+
}
1564+
);
1565+
(<TextDocumentEdit>codeActions[0]?.edit?.documentChanges?.[0])?.edits.forEach(
1566+
(edit) => (edit.newText = harmonizeNewLines(edit.newText))
1567+
);
1568+
1569+
assert.deepStrictEqual(codeActions, [
1570+
{
1571+
edit: {
1572+
documentChanges: [
1573+
{
1574+
edits: [
1575+
{
1576+
newText:
1577+
"import { C } from 'blubb';\n" +
1578+
"import { A } from 'bla';\n",
1579+
1580+
range: {
1581+
start: {
1582+
character: 0,
1583+
line: 1
1584+
},
1585+
end: {
1586+
character: 0,
1587+
line: 2
1588+
}
1589+
}
1590+
},
1591+
{
1592+
newText: '',
1593+
range: {
1594+
start: {
1595+
character: 0,
1596+
line: 2
1597+
},
1598+
end: {
1599+
character: 0,
1600+
line: 3
1601+
}
1602+
}
1603+
},
1604+
{
1605+
newText: '',
1606+
range: {
1607+
start: {
1608+
character: 0,
1609+
line: 3
1610+
},
1611+
end: {
1612+
character: 0,
1613+
line: 4
1614+
}
1615+
}
1616+
},
1617+
{
1618+
newText: '',
1619+
range: {
1620+
start: {
1621+
character: 0,
1622+
line: 4
1623+
},
1624+
end: {
1625+
character: 0,
1626+
line: 5
1627+
}
1628+
}
1629+
}
1630+
],
1631+
textDocument: {
1632+
uri: getUri('codeactions.svelte'),
1633+
version: null
1634+
}
1635+
}
1636+
]
1637+
},
1638+
kind: REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND,
1639+
title: 'Remove Unused Imports'
1640+
}
1641+
]);
1642+
});
1643+
15531644
it('organizes imports with module script', async () => {
15541645
const { provider, document } = setup('organize-imports-with-module.svelte');
15551646

0 commit comments

Comments
 (0)