svelte-language-server
Version:
A language server for Svelte
332 lines • 18.5 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TypeScriptPlugin = void 0;
const typescript_1 = __importDefault(require("typescript"));
const vscode_languageserver_1 = require("vscode-languageserver");
const documents_1 = require("../../lib/documents");
const utils_1 = require("../../utils");
const SnapshotManager_1 = require("./SnapshotManager");
const CodeActionsProvider_1 = require("./features/CodeActionsProvider");
const CompletionProvider_1 = require("./features/CompletionProvider");
const DiagnosticsProvider_1 = require("./features/DiagnosticsProvider");
const FindComponentReferencesProvider_1 = require("./features/FindComponentReferencesProvider");
const FindFileReferencesProvider_1 = require("./features/FindFileReferencesProvider");
const FindReferencesProvider_1 = require("./features/FindReferencesProvider");
const FoldingRangeProvider_1 = require("./features/FoldingRangeProvider");
const HoverProvider_1 = require("./features/HoverProvider");
const ImplementationProvider_1 = require("./features/ImplementationProvider");
const InlayHintProvider_1 = require("./features/InlayHintProvider");
const RenameProvider_1 = require("./features/RenameProvider");
const SelectionRangeProvider_1 = require("./features/SelectionRangeProvider");
const SemanticTokensProvider_1 = require("./features/SemanticTokensProvider");
const SignatureHelpProvider_1 = require("./features/SignatureHelpProvider");
const TypeDefinitionProvider_1 = require("./features/TypeDefinitionProvider");
const UpdateImportsProvider_1 = require("./features/UpdateImportsProvider");
const getDirectiveCommentCompletions_1 = require("./features/getDirectiveCommentCompletions");
const utils_2 = require("./features/utils");
const DocumentHighlightProvider_1 = require("./features/DocumentHighlightProvider");
const svelte_ast_utils_1 = require("./svelte-ast-utils");
const utils_3 = require("./utils");
const CallHierarchyProvider_1 = require("./features/CallHierarchyProvider");
const CodeLensProvider_1 = require("./features/CodeLensProvider");
const WorkspaceSymbolProvider_1 = require("./features/WorkspaceSymbolProvider");
class TypeScriptPlugin {
constructor(configManager, lsAndTsDocResolver, workspaceUris, documentManager) {
this.__name = 'ts';
this.configManager = configManager;
this.documentManager = documentManager;
this.lsAndTsDocResolver = lsAndTsDocResolver;
this.completionProvider = new CompletionProvider_1.CompletionsProviderImpl(this.lsAndTsDocResolver, this.configManager);
this.codeActionsProvider = new CodeActionsProvider_1.CodeActionsProviderImpl(this.lsAndTsDocResolver, this.completionProvider, configManager);
this.updateImportsProvider = new UpdateImportsProvider_1.UpdateImportsProviderImpl(this.lsAndTsDocResolver, typescript_1.default.sys.useCaseSensitiveFileNames);
this.diagnosticsProvider = new DiagnosticsProvider_1.DiagnosticsProviderImpl(this.lsAndTsDocResolver, configManager);
this.renameProvider = new RenameProvider_1.RenameProviderImpl(this.lsAndTsDocResolver, configManager);
this.hoverProvider = new HoverProvider_1.HoverProviderImpl(this.lsAndTsDocResolver);
this.findFileReferencesProvider = new FindFileReferencesProvider_1.FindFileReferencesProviderImpl(this.lsAndTsDocResolver);
this.findComponentReferencesProvider = new FindComponentReferencesProvider_1.FindComponentReferencesProviderImpl(this.lsAndTsDocResolver);
this.findReferencesProvider = new FindReferencesProvider_1.FindReferencesProviderImpl(this.lsAndTsDocResolver, this.findComponentReferencesProvider);
this.selectionRangeProvider = new SelectionRangeProvider_1.SelectionRangeProviderImpl(this.lsAndTsDocResolver);
this.signatureHelpProvider = new SignatureHelpProvider_1.SignatureHelpProviderImpl(this.lsAndTsDocResolver);
this.semanticTokensProvider = new SemanticTokensProvider_1.SemanticTokensProviderImpl(this.lsAndTsDocResolver);
this.implementationProvider = new ImplementationProvider_1.ImplementationProviderImpl(this.lsAndTsDocResolver);
this.typeDefinitionProvider = new TypeDefinitionProvider_1.TypeDefinitionProviderImpl(this.lsAndTsDocResolver);
this.inlayHintProvider = new InlayHintProvider_1.InlayHintProviderImpl(this.lsAndTsDocResolver);
this.callHierarchyProvider = new CallHierarchyProvider_1.CallHierarchyProviderImpl(this.lsAndTsDocResolver, workspaceUris);
this.foldingRangeProvider = new FoldingRangeProvider_1.FoldingRangeProviderImpl(this.lsAndTsDocResolver, configManager);
this.codLensProvider = new CodeLensProvider_1.CodeLensProviderImpl(this.lsAndTsDocResolver, this.findReferencesProvider, this.implementationProvider, this.configManager);
this.documentHeightProvider = new DocumentHighlightProvider_1.DocumentHighlightProviderImpl(this.lsAndTsDocResolver);
this.workspaceSymbolsProvider = new WorkspaceSymbolProvider_1.WorkspaceSymbolsProviderImpl(this.lsAndTsDocResolver, configManager);
}
async getDiagnostics(document, cancellationToken) {
if (!this.featureEnabled('diagnostics')) {
return [];
}
return this.diagnosticsProvider.getDiagnostics(document, cancellationToken);
}
async doHover(document, position) {
if (!this.featureEnabled('hover')) {
return null;
}
return this.hoverProvider.doHover(document, position);
}
async getDocumentSymbols(document, cancellationToken) {
if (!this.featureEnabled('documentSymbols')) {
return [];
}
const { lang, tsDoc } = await this.lsAndTsDocResolver.getLsForSyntheticOperations(document);
if (cancellationToken?.isCancellationRequested) {
return [];
}
const navTree = lang.getNavigationTree(tsDoc.filePath);
const symbols = [];
collectSymbols(navTree, undefined, (symbol) => symbols.push(symbol));
const topContainerName = symbols[0].name;
const result = [];
for (let symbol of symbols.slice(1)) {
if (symbol.containerName === topContainerName) {
symbol.containerName = 'script';
}
symbol = (0, documents_1.mapSymbolInformationToOriginal)(tsDoc, symbol);
if (symbol.location.range.start.line < 0 ||
symbol.location.range.end.line < 0 ||
(0, utils_1.isZeroLengthRange)(symbol.location.range) ||
symbol.name.startsWith('__sveltets_')) {
continue;
}
if ((symbol.kind === vscode_languageserver_1.SymbolKind.Property || symbol.kind === vscode_languageserver_1.SymbolKind.Method) &&
!(0, utils_3.isInScript)(symbol.location.range.start, document)) {
if (symbol.name === 'props' &&
document.getText().charAt(document.offsetAt(symbol.location.range.start)) !==
'p') {
// This is the "props" of a generated component constructor
continue;
}
const node = tsDoc.svelteNodeAt(symbol.location.range.start);
if ((node && ((0, svelte_ast_utils_1.isAttributeName)(node) || (0, svelte_ast_utils_1.isAttributeShorthand)(node))) ||
(0, svelte_ast_utils_1.isEventHandler)(node)) {
// This is a html or component property, they are not treated as a new symbol
// in JSX and so we do the same for the new transformation.
continue;
}
}
if (symbol.name === '<function>') {
let name = (0, documents_1.getTextInRange)(symbol.location.range, document.getText()).trimLeft();
if (name.length > 50) {
name = name.substring(0, 50) + '...';
}
symbol.name = name;
}
if (symbol.name.startsWith('$$_')) {
if (!symbol.name.includes('$on')) {
continue;
}
// on:foo={() => ''} -> $on("foo") callback
symbol.name = symbol.name.substring(symbol.name.indexOf('$on'));
}
result.push(symbol);
}
return result;
function collectSymbols(tree, container, cb) {
const start = tree.spans[0];
const end = tree.spans[tree.spans.length - 1];
if (start && end) {
cb(vscode_languageserver_1.SymbolInformation.create(tree.text, (0, utils_3.symbolKindFromString)(tree.kind), vscode_languageserver_1.Range.create(tsDoc.positionAt(start.start), tsDoc.positionAt(end.start + end.length)), tsDoc.getURL(), container));
}
if (tree.childItems) {
for (const child of tree.childItems) {
collectSymbols(child, tree.text, cb);
}
}
}
}
async getCompletions(document, position, completionContext, cancellationToken) {
if (!this.featureEnabled('completions')) {
return null;
}
const tsDirectiveCommentCompletions = (0, getDirectiveCommentCompletions_1.getDirectiveCommentCompletions)(position, document, completionContext);
const completions = await this.completionProvider.getCompletions(document, position, completionContext, cancellationToken);
if (completions && tsDirectiveCommentCompletions) {
return vscode_languageserver_1.CompletionList.create(completions.items.concat(tsDirectiveCommentCompletions.items), completions.isIncomplete);
}
return completions ?? tsDirectiveCommentCompletions;
}
async resolveCompletion(document, completionItem, cancellationToken) {
return this.completionProvider.resolveCompletion(document, completionItem, cancellationToken);
}
async getDefinitions(document, position) {
const { lang, tsDoc, lsContainer } = await this.lsAndTsDocResolver.getLSAndTSDoc(document);
const defs = lang.getDefinitionAndBoundSpan(tsDoc.filePath, tsDoc.offsetAt(tsDoc.getGeneratedPosition(position)));
if (!defs || !defs.definitions) {
return [];
}
const snapshots = new utils_2.SnapshotMap(this.lsAndTsDocResolver, lsContainer);
snapshots.set(tsDoc.filePath, tsDoc);
const result = await Promise.all(defs.definitions.map(async (def) => {
if ((0, utils_3.isSvelte2tsxShimFile)(def.fileName)) {
return;
}
let snapshot = await snapshots.retrieve(def.fileName);
// Go from generated $store to store if user wants to find definition for $store
if ((0, utils_2.isTextSpanInGeneratedCode)(snapshot.getFullText(), def.textSpan)) {
if (!(0, utils_2.is$storeVariableIn$storeDeclaration)(snapshot.getFullText(), def.textSpan.start)) {
return;
}
// there will be exactly one definition, the store
def = lang.getDefinitionAndBoundSpan(tsDoc.filePath, tsDoc.getFullText().indexOf(');', def.textSpan.start) - 1).definitions[0];
snapshot = await snapshots.retrieve(def.fileName);
}
const defLocation = (0, utils_3.convertToLocationForReferenceOrDefinition)(snapshot, def.textSpan);
return vscode_languageserver_1.LocationLink.create(defLocation.uri, defLocation.range, defLocation.range, (0, utils_3.convertToLocationRange)(tsDoc, defs.textSpan));
}));
return result.filter(utils_1.isNotNullOrUndefined);
}
async prepareRename(document, position) {
return this.renameProvider.prepareRename(document, position);
}
async rename(document, position, newName) {
return this.renameProvider.rename(document, position, newName);
}
async getCodeActions(document, range, context, cancellationToken) {
if (!this.featureEnabled('codeActions')) {
return [];
}
return this.codeActionsProvider.getCodeActions(document, range, context, cancellationToken);
}
async resolveCodeAction(document, codeAction, cancellationToken) {
return this.codeActionsProvider.resolveCodeAction(document, codeAction, cancellationToken);
}
async executeCommand(document, command, args) {
if (!this.featureEnabled('codeActions')) {
return null;
}
return this.codeActionsProvider.executeCommand(document, command, args);
}
async updateImports(fileRename) {
if (!(this.configManager.enabled('svelte.enable') &&
this.configManager.enabled('svelte.rename.enable'))) {
return null;
}
return this.updateImportsProvider.updateImports(fileRename);
}
async findReferences(document, position, context) {
return this.findReferencesProvider.findReferences(document, position, context);
}
async fileReferences(uri) {
return this.findFileReferencesProvider.fileReferences(uri);
}
async findComponentReferences(uri) {
return this.findComponentReferencesProvider.findComponentReferences(uri);
}
async onWatchFileChanges(onWatchFileChangesParas) {
const newFiles = [];
for (const { fileName, changeType } of onWatchFileChangesParas) {
const pathParts = fileName.split(/\/|\\/);
const dirPathParts = pathParts.slice(0, pathParts.length - 1);
const declarationExtensions = [typescript_1.default.Extension.Dcts, typescript_1.default.Extension.Dts, typescript_1.default.Extension.Dmts];
const canSafelyIgnore = declarationExtensions.every((ext) => !fileName.endsWith(ext)) &&
SnapshotManager_1.ignoredBuildDirectories.some((dir) => {
const index = dirPathParts.indexOf(dir);
return (
// Files in .svelte-kit/types should always come through
index > 0 && (dir !== '.svelte-kit' || dirPathParts[index + 1] !== 'types'));
});
if (canSafelyIgnore) {
continue;
}
const isSvelteFile = (0, utils_3.isSvelteFilePath)(fileName);
const isClientSvelteFile = isSvelteFile && this.documentManager.get((0, utils_1.pathToUrl)(fileName))?.openedByClient;
if (changeType === vscode_languageserver_1.FileChangeType.Deleted) {
if (!isClientSvelteFile) {
await this.lsAndTsDocResolver.deleteSnapshot(fileName);
}
continue;
}
if (changeType === vscode_languageserver_1.FileChangeType.Created) {
newFiles.push(fileName);
continue;
}
if (isSvelteFile) {
if (!isClientSvelteFile) {
await this.lsAndTsDocResolver.updateExistingSvelteFile(fileName);
}
continue;
}
await this.lsAndTsDocResolver.updateExistingTsOrJsFile(fileName);
}
if (newFiles.length) {
await this.lsAndTsDocResolver.updateProjectFiles(newFiles);
await this.lsAndTsDocResolver.invalidateModuleCache(newFiles);
}
}
async updateTsOrJsFile(fileName, changes) {
await this.lsAndTsDocResolver.updateExistingTsOrJsFile(fileName, changes);
}
async getSelectionRange(document, position) {
if (!this.featureEnabled('selectionRange')) {
return null;
}
return this.selectionRangeProvider.getSelectionRange(document, position);
}
async getSignatureHelp(document, position, context, cancellationToken) {
if (!this.featureEnabled('signatureHelp')) {
return null;
}
return this.signatureHelpProvider.getSignatureHelp(document, position, context, cancellationToken);
}
async getSemanticTokens(textDocument, range, cancellationToken) {
if (!this.featureEnabled('semanticTokens')) {
return {
data: []
};
}
return this.semanticTokensProvider.getSemanticTokens(textDocument, range, cancellationToken);
}
async getImplementation(document, position, cancellationToken) {
return this.implementationProvider.getImplementation(document, position, cancellationToken);
}
async getTypeDefinition(document, position) {
return this.typeDefinitionProvider.getTypeDefinition(document, position);
}
async getInlayHints(document, range, cancellationToken) {
if (!this.configManager.enabled('typescript.enable')) {
return null;
}
return this.inlayHintProvider.getInlayHints(document, range, cancellationToken);
}
prepareCallHierarchy(document, position, cancellationToken) {
return this.callHierarchyProvider.prepareCallHierarchy(document, position, cancellationToken);
}
getIncomingCalls(item, cancellationToken) {
return this.callHierarchyProvider.getIncomingCalls(item, cancellationToken);
}
async getOutgoingCalls(item, cancellationToken) {
return this.callHierarchyProvider.getOutgoingCalls(item, cancellationToken);
}
async getFoldingRanges(document) {
return this.foldingRangeProvider.getFoldingRanges(document);
}
getCodeLens(document) {
return this.codLensProvider.getCodeLens(document);
}
resolveCodeLens(document, codeLensToResolve, cancellationToken) {
return this.codLensProvider.resolveCodeLens(document, codeLensToResolve, cancellationToken);
}
async findDocumentHighlight(document, position) {
return this.documentHeightProvider.findDocumentHighlight(document, position);
}
async getWorkspaceSymbols(query, cancellationToken) {
if (!this.featureEnabled('workspaceSymbols')) {
return null;
}
return this.workspaceSymbolsProvider.getWorkspaceSymbols(query, cancellationToken);
}
featureEnabled(feature) {
return (this.configManager.enabled('typescript.enable') &&
this.configManager.enabled(`typescript.${feature}.enable`));
}
}
exports.TypeScriptPlugin = TypeScriptPlugin;
//# sourceMappingURL=TypeScriptPlugin.js.map