typescript-language-server
Version:
Language Server Protocol (LSP) implementation for TypeScript using tsserver
125 lines • 5.36 kB
JavaScript
import deepmerge from 'deepmerge';
import path from 'node:path';
import API from './utils/api.js';
const DEFAULT_TSSERVER_PREFERENCES = {
allowIncompleteCompletions: true,
allowRenameOfImportPath: true,
allowTextChangesInNewFiles: true,
autoImportFileExcludePatterns: [],
disableSuggestions: false,
displayPartsForJSDoc: true,
generateReturnInDocTemplate: true,
importModuleSpecifierEnding: 'auto',
importModuleSpecifierPreference: 'shortest',
includeAutomaticOptionalChainCompletions: true,
includeCompletionsForImportStatements: true,
includeCompletionsForModuleExports: true,
includeCompletionsWithClassMemberSnippets: true,
includeCompletionsWithInsertText: true,
includeCompletionsWithObjectLiteralMethodSnippets: true,
includeCompletionsWithSnippetText: true,
includeInlayEnumMemberValueHints: false,
includeInlayFunctionLikeReturnTypeHints: false,
includeInlayFunctionParameterTypeHints: false,
includeInlayParameterNameHints: 'none',
includeInlayParameterNameHintsWhenArgumentMatchesName: false,
includeInlayPropertyDeclarationTypeHints: false,
includeInlayVariableTypeHints: false,
includeInlayVariableTypeHintsWhenTypeMatchesName: false,
includePackageJsonAutoImports: 'auto',
jsxAttributeCompletionStyle: 'auto',
lazyConfiguredProjectsFromExternalProject: false,
providePrefixAndSuffixTextForRename: true,
provideRefactorNotApplicableReason: true,
quotePreference: 'auto',
useLabelDetailsInCompletionEntries: true,
};
export class ConfigurationManager {
constructor(documents) {
this.documents = documents;
this.tsPreferences = deepmerge({}, DEFAULT_TSSERVER_PREFERENCES);
this.workspaceConfiguration = {};
this.tspClient = null;
}
mergeTsPreferences(preferences) {
this.tsPreferences = deepmerge(this.tsPreferences, preferences);
}
setWorkspaceConfiguration(configuration) {
this.workspaceConfiguration = configuration;
}
async setAndConfigureTspClient(workspaceFolder, client, hostInfo) {
this.tspClient = client;
const formatOptions = {
// We can use \n here since the editor should normalize later on to its line endings.
newLineCharacter: '\n',
};
const args = {
...hostInfo ? { hostInfo } : {},
formatOptions,
preferences: {
...this.tsPreferences,
autoImportFileExcludePatterns: this.getAutoImportFileExcludePatternsPreference(workspaceFolder),
},
};
await this.tspClient?.request("configure" /* CommandTypes.Configure */, args);
}
async configureGloballyFromDocument(filename, formattingOptions) {
const args = {
formatOptions: this.getFormattingOptions(filename, formattingOptions),
preferences: this.getPreferences(filename),
};
await this.tspClient?.request("configure" /* CommandTypes.Configure */, args);
}
getPreferences(filename) {
if (this.tspClient?.apiVersion.lt(API.v290)) {
return {};
}
const workspacePreferences = this.getWorkspacePreferencesForFile(filename);
const preferences = Object.assign({}, this.tsPreferences, workspacePreferences?.inlayHints || {});
return {
...preferences,
quotePreference: this.getQuoteStylePreference(preferences),
};
}
getFormattingOptions(filename, formattingOptions) {
const workspacePreferences = this.getWorkspacePreferencesForFile(filename);
const opts = {
...workspacePreferences?.format,
...formattingOptions,
};
if (opts.convertTabsToSpaces === undefined) {
opts.convertTabsToSpaces = formattingOptions?.insertSpaces;
}
if (opts.indentSize === undefined) {
opts.indentSize = formattingOptions?.tabSize;
}
return opts;
}
getQuoteStylePreference(preferences) {
switch (preferences.quotePreference) {
case 'single': return 'single';
case 'double': return 'double';
default: return this.tspClient?.apiVersion.gte(API.v333) ? 'auto' : undefined;
}
}
getWorkspacePreferencesForFile(filename) {
const document = this.documents.get(filename);
const languageId = document?.languageId.startsWith('typescript') ? 'typescript' : 'javascript';
return this.workspaceConfiguration[languageId] || {};
}
getAutoImportFileExcludePatternsPreference(workspaceFolder) {
if (!workspaceFolder || this.tsPreferences.autoImportFileExcludePatterns.length === 0) {
return;
}
return this.tsPreferences.autoImportFileExcludePatterns.map(p => {
// Normalization rules: https://github.com/microsoft/TypeScript/pull/49578
const slashNormalized = p.replace(/\\/g, '/');
const isRelative = /^\.\.?($|\/)/.test(slashNormalized);
return path.posix.isAbsolute(p) ? p :
p.startsWith('*') ? '/' + slashNormalized :
isRelative ? path.posix.join(workspaceFolder, p) :
'/**/' + slashNormalized;
});
}
}
//# sourceMappingURL=configuration-manager.js.map