Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/wide-emus-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte-language-server': minor
---

feat: implement 'source.removeUnusedImports' code action
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { internalHelpers } from 'svelte2tsx';
import ts from 'typescript';
import ts, { OrganizeImportsMode } from 'typescript';
import {
CancellationToken,
CodeAction,
Expand Down Expand Up @@ -65,6 +65,7 @@ import {
*/
export const SORT_IMPORT_CODE_ACTION_KIND = 'source.sortImports';
export const ADD_MISSING_IMPORTS_CODE_ACTION_KIND = 'source.addMissingImports';
export const REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND = 'source.removeUnusedImports';

interface RefactorArgs {
type: 'refactor';
Expand Down Expand Up @@ -120,7 +121,15 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
return await this.organizeImports(
document,
cancellationToken,
/**skipDestructiveCodeActions */ true
OrganizeImportsMode.SortAndCombine
);
}

if (context.only?.[0] === REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND) {
return await this.organizeImports(
document,
cancellationToken,
OrganizeImportsMode.RemoveUnused
);
}

Expand All @@ -136,7 +145,12 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
...(await this.organizeImports(
document,
cancellationToken,
/**skipDestructiveCodeActions */ true
OrganizeImportsMode.SortAndCombine
)),
...(await this.organizeImports(
document,
cancellationToken,
OrganizeImportsMode.RemoveUnused
)),
...(await this.addMissingImports(document, cancellationToken))
];
Expand Down Expand Up @@ -406,7 +420,7 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
private async organizeImports(
document: Document,
cancellationToken: CancellationToken | undefined,
skipDestructiveCodeActions = false
mode: OrganizeImportsMode = OrganizeImportsMode.All
): Promise<CodeAction[]> {
if (!document.scriptInfo && !document.moduleScriptInfo) {
return [];
Expand All @@ -425,7 +439,7 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
{
fileName: tsDoc.filePath,
type: 'file',
skipDestructiveCodeActions
mode
},
{
...(await this.configManager.getFormatCodeSettingsForFile(
Expand Down Expand Up @@ -475,15 +489,26 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
this.checkIndentLeftover(change, document);
}

return [
CodeAction.create(
skipDestructiveCodeActions ? 'Sort Imports' : 'Organize Imports',
{ documentChanges },
skipDestructiveCodeActions
? SORT_IMPORT_CODE_ACTION_KIND
: CodeActionKind.SourceOrganizeImports
)
];
let kind: CodeActionKind;
let title: string;

switch (mode) {
case OrganizeImportsMode.SortAndCombine:
kind = SORT_IMPORT_CODE_ACTION_KIND;
title = 'Sort Imports';
break;

case OrganizeImportsMode.RemoveUnused:
kind = REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND;
title = 'Remove Unused Imports';
break;

default:
kind = CodeActionKind.SourceOrganizeImports;
title = 'Organize Imports';
}

return [CodeAction.create(title, { documentChanges }, kind)];
}

private fixIndentationOfImports(edit: TextEdit, document: Document): TextEdit {
Expand Down
4 changes: 3 additions & 1 deletion packages/language-server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ import { configLoader } from './lib/documents/configLoader';
import { setIsTrusted } from './importPackage';
import {
SORT_IMPORT_CODE_ACTION_KIND,
ADD_MISSING_IMPORTS_CODE_ACTION_KIND
ADD_MISSING_IMPORTS_CODE_ACTION_KIND,
REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND
} from './plugins/typescript/features/CodeActionsProvider';
import { createLanguageServices } from './plugins/css/service';
import { FileSystemProvider } from './plugins/css/FileSystemProvider';
Expand Down Expand Up @@ -274,6 +275,7 @@ export function startServer(options?: LSOptions) {
CodeActionKind.SourceOrganizeImports,
SORT_IMPORT_CODE_ACTION_KIND,
ADD_MISSING_IMPORTS_CODE_ACTION_KIND,
REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND,
...(clientSupportApplyEditCommand ? [CodeActionKind.Refactor] : [])
].filter(
clientSupportedCodeActionKinds &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { LSConfigManager } from '../../../../src/ls-config';
import {
ADD_MISSING_IMPORTS_CODE_ACTION_KIND,
CodeActionsProviderImpl,
REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND,
SORT_IMPORT_CODE_ACTION_KIND
} from '../../../../src/plugins/typescript/features/CodeActionsProvider';
import { CompletionsProviderImpl } from '../../../../src/plugins/typescript/features/CompletionProvider';
Expand Down Expand Up @@ -1550,6 +1551,96 @@ describe('CodeActionsProvider', function () {
]);
});

it('removes unused imports', async () => {
const { provider, document } = setup('codeactions.svelte');

const codeActions = await provider.getCodeActions(
document,
Range.create(Position.create(1, 4), Position.create(1, 5)),
{
diagnostics: [],
only: [REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND]
}
);
(<TextDocumentEdit>codeActions[0]?.edit?.documentChanges?.[0])?.edits.forEach(
(edit) => (edit.newText = harmonizeNewLines(edit.newText))
);

assert.deepStrictEqual(codeActions, [
{
edit: {
documentChanges: [
{
edits: [
{
newText:
"import { C } from 'blubb';\n" +
"import { A } from 'bla';\n",

range: {
start: {
character: 0,
line: 1
},
end: {
character: 0,
line: 2
}
}
},
{
newText: '',
range: {
start: {
character: 0,
line: 2
},
end: {
character: 0,
line: 3
}
}
},
{
newText: '',
range: {
start: {
character: 0,
line: 3
},
end: {
character: 0,
line: 4
}
}
},
{
newText: '',
range: {
start: {
character: 0,
line: 4
},
end: {
character: 0,
line: 5
}
}
}
],
textDocument: {
uri: getUri('codeactions.svelte'),
version: null
}
}
]
},
kind: REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND,
title: 'Remove Unused Imports'
}
]);
});

it('organizes imports with module script', async () => {
const { provider, document } = setup('organize-imports-with-module.svelte');

Expand Down