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
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
isKitTypePath,
isPartOfImportStatement
} from './utils';
import { isInTag as svelteIsInTag } from '../svelte-ast-utils';

export interface CompletionEntryWithIdentifier extends ts.CompletionEntry, TextDocumentIdentifier {
position: Position;
Expand Down Expand Up @@ -258,9 +259,12 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionEn
);
}

// moved here due to perf reasons
const existingImports = this.getExistingImports(document);
const wordRangeStartPosition = document.positionAt(wordRange.start);
const fileUrl = pathToUrl(tsDoc.filePath); // moved here due to perf reasons
const fileUrl = pathToUrl(tsDoc.filePath);
const isCompletionInTag = svelteIsInTag(svelteNode, originalOffset);

const completionItems = completions
.filter(isValidCompletion(document, position, !!tsDoc.parserError))
.map((comp) =>
Expand All @@ -269,6 +273,7 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionEn
comp,
fileUrl,
position,
isCompletionInTag,
addCommitCharacters,
existingImports
)
Expand Down Expand Up @@ -420,6 +425,7 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionEn
comp: ts.CompletionEntry,
uri: string,
position: Position,
isCompletionInTag: boolean,
addCommitCharacters: boolean,
existingImports: Set<string>
): AppCompletionItem<CompletionEntryWithIdentifier> | null {
Expand All @@ -428,13 +434,23 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionEn
return null;
}

const { label, insertText, isSvelteComp, replacementSpan } = completionLabelAndInsert;
let { label, insertText, isSvelteComp, replacementSpan } = completionLabelAndInsert;
// TS may suggest another Svelte component even if there already exists an import
// with the same name, because under the hood every Svelte component is postfixed
// with `__SvelteComponent`. In this case, filter out this completion by returning null.
if (isSvelteComp && existingImports.has(label)) {
return null;
}
// Remove wrong quotes, for example when using --css-props
if (
isCompletionInTag &&
!insertText &&
label[0] === '"' &&
label[label.length - 1] === '"'
) {
label = label.slice(1, -1);
}

const textEdit = replacementSpan
? TextEdit.replace(convertRange(snapshot, replacementSpan), insertText ?? label)
: undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ function matchesOnly(type: string | undefined, only?: 'Element' | 'InlineCompone
);
}

/**
* Returns true if given node is a component or html element, or if the offset is at the end of the node
* and its parent is a component or html element.
*/
export function isInTag(node: SvelteNode | null | undefined, offset: number): boolean {
return (
node?.type === 'InlineComponent' ||
node?.type === 'Element' ||
(node?.end === offset &&
(node?.parent?.type === 'InlineComponent' || node?.parent?.type === 'Element'))
);
}

/**
* Returns when given node represents an HTML Attribute.
* Example: The `class` in `<div class=".."`.
Expand Down