typescript-language-server 1.0.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +128 -21
  3. package/lib/calls.d.ts +1 -1
  4. package/lib/calls.d.ts.map +1 -1
  5. package/lib/calls.js +140 -164
  6. package/lib/calls.js.map +1 -1
  7. package/lib/cli.js +1 -1
  8. package/lib/commands.d.ts +1 -0
  9. package/lib/commands.d.ts.map +1 -1
  10. package/lib/commands.js +3 -1
  11. package/lib/commands.js.map +1 -1
  12. package/lib/completion.d.ts +4 -7
  13. package/lib/completion.d.ts.map +1 -1
  14. package/lib/completion.js +64 -66
  15. package/lib/completion.js.map +1 -1
  16. package/lib/configuration-manager.d.ts +47 -0
  17. package/lib/configuration-manager.d.ts.map +1 -0
  18. package/lib/configuration-manager.js +105 -0
  19. package/lib/configuration-manager.js.map +1 -0
  20. package/lib/diagnostic-queue.d.ts +5 -4
  21. package/lib/diagnostic-queue.d.ts.map +1 -1
  22. package/lib/diagnostic-queue.js +7 -8
  23. package/lib/diagnostic-queue.js.map +1 -1
  24. package/lib/document-symbol.d.ts.map +1 -1
  25. package/lib/document-symbol.js +11 -10
  26. package/lib/document-symbol.js.map +1 -1
  27. package/lib/features/fix-all.d.ts.map +1 -1
  28. package/lib/features/fix-all.js +96 -112
  29. package/lib/features/fix-all.js.map +1 -1
  30. package/lib/features/inlay-hints.d.ts +11 -0
  31. package/lib/features/inlay-hints.d.ts.map +1 -0
  32. package/lib/features/inlay-hints.js +70 -0
  33. package/lib/features/inlay-hints.js.map +1 -0
  34. package/lib/features/source-definition.d.ts +11 -0
  35. package/lib/features/source-definition.d.ts.map +1 -0
  36. package/lib/features/source-definition.js +50 -0
  37. package/lib/features/source-definition.js.map +1 -0
  38. package/lib/file-lsp-server.spec.js +16 -25
  39. package/lib/file-lsp-server.spec.js.map +1 -1
  40. package/lib/hover.d.ts +2 -1
  41. package/lib/hover.d.ts.map +1 -1
  42. package/lib/hover.js +47 -7
  43. package/lib/hover.js.map +1 -1
  44. package/lib/logger.js +1 -1
  45. package/lib/logger.js.map +1 -1
  46. package/lib/lsp-client.d.ts +11 -15
  47. package/lib/lsp-client.d.ts.map +1 -1
  48. package/lib/lsp-client.js +29 -61
  49. package/lib/lsp-client.js.map +1 -1
  50. package/lib/lsp-connection.d.ts.map +1 -1
  51. package/lib/lsp-connection.js +3 -2
  52. package/lib/lsp-connection.js.map +1 -1
  53. package/lib/lsp-protocol.inlayHints.proposed.d.ts +0 -9
  54. package/lib/lsp-protocol.inlayHints.proposed.d.ts.map +1 -1
  55. package/lib/lsp-server.d.ts +15 -20
  56. package/lib/lsp-server.d.ts.map +1 -1
  57. package/lib/lsp-server.js +807 -901
  58. package/lib/lsp-server.js.map +1 -1
  59. package/lib/lsp-server.spec.js +772 -495
  60. package/lib/lsp-server.spec.js.map +1 -1
  61. package/lib/organize-imports.spec.js +8 -8
  62. package/lib/protocol-translation.d.ts +2 -7
  63. package/lib/protocol-translation.d.ts.map +1 -1
  64. package/lib/protocol-translation.js +19 -106
  65. package/lib/protocol-translation.js.map +1 -1
  66. package/lib/quickfix.js +1 -1
  67. package/lib/refactor.js +5 -1
  68. package/lib/refactor.js.map +1 -1
  69. package/lib/test-utils.d.ts +4 -3
  70. package/lib/test-utils.d.ts.map +1 -1
  71. package/lib/test-utils.js +103 -77
  72. package/lib/test-utils.js.map +1 -1
  73. package/lib/ts-protocol.d.ts +4 -19
  74. package/lib/ts-protocol.d.ts.map +1 -1
  75. package/lib/ts-protocol.js.map +1 -1
  76. package/lib/tsp-client.d.ts +36 -32
  77. package/lib/tsp-client.d.ts.map +1 -1
  78. package/lib/tsp-client.js +9 -7
  79. package/lib/tsp-client.js.map +1 -1
  80. package/lib/tsp-client.spec.js +26 -33
  81. package/lib/tsp-client.spec.js.map +1 -1
  82. package/lib/tsp-command-types.d.ts +1 -0
  83. package/lib/tsp-command-types.d.ts.map +1 -1
  84. package/lib/tsp-command-types.js +1 -1
  85. package/lib/tsp-command-types.js.map +1 -1
  86. package/lib/utils/typeConverters.d.ts +19 -1
  87. package/lib/utils/typeConverters.d.ts.map +1 -1
  88. package/lib/utils/typeConverters.js +103 -4
  89. package/lib/utils/typeConverters.js.map +1 -1
  90. package/lib/utils/versionProvider.js +17 -19
  91. package/lib/utils/versionProvider.js.map +1 -1
  92. package/lib/utils.d.ts.map +1 -1
  93. package/lib/utils.js +2 -0
  94. package/lib/utils.js.map +1 -1
  95. package/package.json +10 -7
package/lib/lsp-server.js CHANGED
@@ -4,15 +4,6 @@
4
4
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
5
5
  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
6
  */
7
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
8
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
9
- return new (P || (P = Promise))(function (resolve, reject) {
10
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
11
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
12
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
13
- step((generator = generator.apply(thisArg, _arguments || [])).next());
14
- });
15
- };
16
7
  import * as path from 'node:path';
17
8
  import fs from 'fs-extra';
18
9
  import debounce from 'p-debounce';
@@ -24,10 +15,10 @@ import API from './utils/api.js';
24
15
  import { PrefixingLogger } from './logger.js';
25
16
  import { TspClient } from './tsp-client.js';
26
17
  import { DiagnosticEventQueue } from './diagnostic-queue.js';
27
- import { toDocumentHighlight, asRange, asTagsDocumentation, uriToPath, toSymbolKind, toLocation, toPosition, pathToUri, toTextEdit, toFileRangeRequestArgs, asPlainText, normalizePath } from './protocol-translation.js';
18
+ import { toDocumentHighlight, asTagsDocumentation, uriToPath, toSymbolKind, toLocation, pathToUri, toTextEdit, asPlainText, normalizePath } from './protocol-translation.js';
28
19
  import { LspDocuments } from './document.js';
29
20
  import { asCompletionItem, asResolvedCompletionItem, getCompletionTriggerCharacter } from './completion.js';
30
- import { asSignatureHelp } from './hover.js';
21
+ import { asSignatureHelp, toTsTriggerReason } from './hover.js';
31
22
  import { Commands } from './commands.js';
32
23
  import { provideQuickFix } from './quickfix.js';
33
24
  import { provideRefactors } from './refactor.js';
@@ -36,38 +27,11 @@ import { collectDocumentSymbols, collectSymbolInformation } from './document-sym
36
27
  import { computeCallers, computeCallees } from './calls.js';
37
28
  import { TypeScriptVersionProvider } from './utils/versionProvider.js';
38
29
  import { TypeScriptAutoFixProvider } from './features/fix-all.js';
30
+ import { TypeScriptInlayHintsProvider } from './features/inlay-hints.js';
31
+ import { SourceDefinitionCommand } from './features/source-definition.js';
32
+ import { Position, Range } from './utils/typeConverters.js';
39
33
  import { CodeActionKind } from './utils/types.js';
40
- const DEFAULT_TSSERVER_PREFERENCES = {
41
- allowIncompleteCompletions: true,
42
- allowRenameOfImportPath: true,
43
- allowTextChangesInNewFiles: true,
44
- disableSuggestions: false,
45
- displayPartsForJSDoc: true,
46
- generateReturnInDocTemplate: true,
47
- importModuleSpecifierEnding: 'auto',
48
- importModuleSpecifierPreference: 'shortest',
49
- includeAutomaticOptionalChainCompletions: true,
50
- includeCompletionsForImportStatements: true,
51
- includeCompletionsForModuleExports: true,
52
- includeCompletionsWithClassMemberSnippets: true,
53
- includeCompletionsWithInsertText: true,
54
- includeCompletionsWithObjectLiteralMethodSnippets: true,
55
- includeCompletionsWithSnippetText: true,
56
- includeInlayEnumMemberValueHints: false,
57
- includeInlayFunctionLikeReturnTypeHints: false,
58
- includeInlayFunctionParameterTypeHints: false,
59
- includeInlayParameterNameHints: 'none',
60
- includeInlayParameterNameHintsWhenArgumentMatchesName: false,
61
- includeInlayPropertyDeclarationTypeHints: false,
62
- includeInlayVariableTypeHints: false,
63
- includePackageJsonAutoImports: 'auto',
64
- jsxAttributeCompletionStyle: 'auto',
65
- lazyConfiguredProjectsFromExternalProject: false,
66
- providePrefixAndSuffixTextForRename: true,
67
- provideRefactorNotApplicableReason: false,
68
- quotePreference: 'auto',
69
- useLabelDetailsInCompletionEntries: true
70
- };
34
+ import { ConfigurationManager } from './configuration-manager.js';
71
35
  class ServerInitializingIndicator {
72
36
  constructor(lspClient) {
73
37
  this.lspClient = lspClient;
@@ -76,24 +40,24 @@ class ServerInitializingIndicator {
76
40
  if (this._loadingProjectName) {
77
41
  this._loadingProjectName = undefined;
78
42
  if (this._progressReporter) {
79
- this._progressReporter.end();
43
+ this._progressReporter.done();
80
44
  this._progressReporter = undefined;
81
45
  }
82
46
  }
83
47
  }
84
- startedLoadingProject(projectName) {
48
+ async startedLoadingProject(projectName) {
85
49
  // TS projects are loaded sequentially. Cancel existing task because it should always be resolved before
86
50
  // the incoming project loading task is.
87
51
  this.reset();
88
52
  this._loadingProjectName = projectName;
89
- this._progressReporter = this.lspClient.createProgressReporter();
53
+ this._progressReporter = await this.lspClient.createProgressReporter();
90
54
  this._progressReporter.begin('Initializing JS/TS language features…');
91
55
  }
92
56
  finishedLoadingProject(projectName) {
93
57
  if (this._loadingProjectName === projectName) {
94
58
  this._loadingProjectName = undefined;
95
59
  if (this._progressReporter) {
96
- this._progressReporter.end();
60
+ this._progressReporter.done();
97
61
  this._progressReporter = undefined;
98
62
  }
99
63
  }
@@ -102,14 +66,18 @@ class ServerInitializingIndicator {
102
66
  export class LspServer {
103
67
  constructor(options) {
104
68
  this.options = options;
69
+ this._tspClient = null;
70
+ this._loadingIndicator = null;
71
+ this.initializeParams = null;
72
+ this.typeScriptAutoFixProvider = null;
105
73
  this.features = {};
106
74
  this.documents = new LspDocuments();
107
75
  // True if diagnostic request is currently debouncing or the request is in progress. False only if there are
108
76
  // no pending requests.
109
77
  this.pendingDebouncedRequest = false;
110
78
  this.doRequestDiagnosticsDebounced = debounce(() => this.doRequestDiagnostics(), 200);
79
+ this.configurationManager = new ConfigurationManager(this.documents);
111
80
  this.logger = new PrefixingLogger(options.logger, '[lspserver]');
112
- this.workspaceConfiguration = {};
113
81
  }
114
82
  closeAll() {
115
83
  for (const file of [...this.documents.files]) {
@@ -162,169 +130,180 @@ export class LspServer {
162
130
  }
163
131
  return null;
164
132
  }
165
- initialize(params) {
166
- var _a, _b, _c, _d, _e, _f, _g;
167
- return __awaiter(this, void 0, void 0, function* () {
168
- this.logger.log('initialize', params);
169
- if (this._tspClient) {
170
- throw new Error('The "initialize" request has already called before.');
171
- }
172
- this.initializeParams = params;
173
- const clientCapabilities = this.initializeParams.capabilities;
174
- this.options.lspClient.setClientCapabilites(clientCapabilities);
175
- this._loadingIndicator = new ServerInitializingIndicator(this.options.lspClient);
176
- this.workspaceRoot = this.initializeParams.rootUri ? uriToPath(this.initializeParams.rootUri) : this.initializeParams.rootPath || undefined;
177
- this.diagnosticQueue = new DiagnosticEventQueue(diagnostics => this.options.lspClient.publishDiagnostics(diagnostics), this.documents, (_a = clientCapabilities.textDocument) === null || _a === void 0 ? void 0 : _a.publishDiagnostics, this.logger);
178
- const userInitializationOptions = this.initializeParams.initializationOptions || {};
179
- const { disableAutomaticTypingAcquisition, hostInfo, maxTsServerMemory, npmLocation, locale } = userInitializationOptions;
180
- const { logVerbosity, plugins } = {
181
- logVerbosity: userInitializationOptions.logVerbosity || this.options.tsserverLogVerbosity,
182
- plugins: userInitializationOptions.plugins || []
183
- };
184
- const logFile = this.getLogFile(logVerbosity);
185
- const globalPlugins = [];
186
- const pluginProbeLocations = [];
187
- for (const plugin of plugins) {
188
- globalPlugins.push(plugin.name);
189
- pluginProbeLocations.push(plugin.location);
190
- }
191
- const typescriptVersion = this.findTypescriptVersion();
192
- if (typescriptVersion) {
193
- this.logger.info(`Using Typescript version (${typescriptVersion.source}) ${typescriptVersion.versionString} from path "${typescriptVersion.tsServerPath}"`);
194
- }
195
- else {
196
- throw Error('Could not find a valid tsserver executable in the workspace or in the $PATH. Please ensure that the "typescript" dependency is installed in either location. Exiting.');
197
- }
198
- const userPreferences = Object.assign(Object.assign({}, DEFAULT_TSSERVER_PREFERENCES), userInitializationOptions.preferences);
199
- if (userPreferences.useLabelDetailsInCompletionEntries
200
- && ((_d = (_c = (_b = clientCapabilities.textDocument) === null || _b === void 0 ? void 0 : _b.completion) === null || _c === void 0 ? void 0 : _c.completionItem) === null || _d === void 0 ? void 0 : _d.labelDetailsSupport)
201
- && ((_e = typescriptVersion.version) === null || _e === void 0 ? void 0 : _e.gte(API.v470))) {
202
- this.features.labelDetails = true;
133
+ async initialize(params) {
134
+ this.logger.log('initialize', params);
135
+ if (this._tspClient) {
136
+ throw new Error('The "initialize" request has already called before.');
137
+ }
138
+ this.initializeParams = params;
139
+ const clientCapabilities = this.initializeParams.capabilities;
140
+ this._loadingIndicator = new ServerInitializingIndicator(this.options.lspClient);
141
+ this.workspaceRoot = this.initializeParams.rootUri ? uriToPath(this.initializeParams.rootUri) : this.initializeParams.rootPath || undefined;
142
+ const userInitializationOptions = this.initializeParams.initializationOptions || {};
143
+ const { disableAutomaticTypingAcquisition, hostInfo, maxTsServerMemory, npmLocation, locale } = userInitializationOptions;
144
+ const { logVerbosity, plugins } = {
145
+ logVerbosity: userInitializationOptions.logVerbosity || this.options.tsserverLogVerbosity,
146
+ plugins: userInitializationOptions.plugins || [],
147
+ };
148
+ const logFile = this.getLogFile(logVerbosity);
149
+ const globalPlugins = [];
150
+ const pluginProbeLocations = [];
151
+ for (const plugin of plugins) {
152
+ globalPlugins.push(plugin.name);
153
+ pluginProbeLocations.push(plugin.location);
154
+ }
155
+ const typescriptVersion = this.findTypescriptVersion();
156
+ if (typescriptVersion) {
157
+ this.logger.info(`Using Typescript version (${typescriptVersion.source}) ${typescriptVersion.versionString} from path "${typescriptVersion.tsServerPath}"`);
158
+ }
159
+ else {
160
+ throw Error('Could not find a valid TypeScript installation. Please ensure that the "typescript" dependency is installed in the workspace or that a valid --tsserver-path is specified. Exiting.');
161
+ }
162
+ this.configurationManager.mergeTsPreferences(userInitializationOptions.preferences || {});
163
+ // Setup supported features.
164
+ const { textDocument } = clientCapabilities;
165
+ this.features.definitionLinkSupport = textDocument?.definition?.linkSupport && typescriptVersion.version?.gte(API.v270);
166
+ const completionCapabilities = textDocument?.completion;
167
+ if (completionCapabilities?.completionItem) {
168
+ if (this.configurationManager.tsPreferences.useLabelDetailsInCompletionEntries
169
+ && completionCapabilities.completionItem.labelDetailsSupport
170
+ && typescriptVersion.version?.gte(API.v470)) {
171
+ this.features.completionLabelDetails = true;
172
+ }
173
+ if (completionCapabilities.completionItem.snippetSupport) {
174
+ this.features.completionSnippets = true;
175
+ }
176
+ if (textDocument?.publishDiagnostics?.tagSupport) {
177
+ this.features.diagnosticsTagSupport = true;
203
178
  }
204
- const finalPreferences = Object.assign(Object.assign({}, userPreferences), { useLabelDetailsInCompletionEntries: this.features.labelDetails });
205
- this._tspClient = new TspClient({
206
- tsserverPath: typescriptVersion.tsServerPath,
207
- logFile,
208
- logVerbosity,
209
- disableAutomaticTypingAcquisition,
210
- maxTsServerMemory,
211
- npmLocation,
212
- locale,
213
- globalPlugins,
214
- pluginProbeLocations,
215
- logger: this.options.logger,
216
- onEvent: this.onTsEvent.bind(this),
217
- onExit: (exitCode, signal) => {
218
- if (exitCode) {
219
- this.logger.error(`tsserver process has exited (exit code: ${exitCode}, signal: ${signal}). Stopping the server.`);
220
- }
221
- this.shutdown();
179
+ }
180
+ this.configurationManager.mergeTsPreferences({
181
+ useLabelDetailsInCompletionEntries: this.features.completionLabelDetails,
182
+ });
183
+ this.diagnosticQueue = new DiagnosticEventQueue(diagnostics => this.options.lspClient.publishDiagnostics(diagnostics), this.documents, this.features, this.logger);
184
+ this._tspClient = new TspClient({
185
+ apiVersion: typescriptVersion.version || API.defaultVersion,
186
+ tsserverPath: typescriptVersion.tsServerPath,
187
+ logFile,
188
+ logVerbosity,
189
+ disableAutomaticTypingAcquisition,
190
+ maxTsServerMemory,
191
+ npmLocation,
192
+ locale,
193
+ globalPlugins,
194
+ pluginProbeLocations,
195
+ logger: this.options.logger,
196
+ onEvent: this.onTsEvent.bind(this),
197
+ onExit: (exitCode, signal) => {
198
+ if (exitCode) {
199
+ this.logger.error(`tsserver process has exited (exit code: ${exitCode}, signal: ${signal}). Stopping the server.`);
222
200
  }
223
- });
224
- const started = this.tspClient.start();
225
- if (!started) {
226
- throw new Error('tsserver process has failed to start.');
227
- }
228
- process.on('exit', () => {
229
201
  this.shutdown();
230
- });
231
- process.on('SIGINT', () => {
232
- process.exit();
233
- });
234
- this.typeScriptAutoFixProvider = new TypeScriptAutoFixProvider(this.tspClient);
235
- yield Promise.all([
236
- this.tspClient.request("configure" /* CommandTypes.Configure */, Object.assign(Object.assign({}, hostInfo ? { hostInfo } : {}), { formatOptions: {
237
- // We can use \n here since the editor should normalize later on to its line endings.
238
- newLineCharacter: '\n'
239
- }, preferences: finalPreferences })),
240
- this.tspClient.request("compilerOptionsForInferredProjects" /* CommandTypes.CompilerOptionsForInferredProjects */, {
241
- options: {
242
- module: "CommonJS" /* tsp.ModuleKind.CommonJS */,
243
- target: "ES2016" /* tsp.ScriptTarget.ES2016 */,
244
- jsx: "Preserve" /* tsp.JsxEmit.Preserve */,
245
- allowJs: true,
246
- allowSyntheticDefaultImports: true,
247
- allowNonTsExtensions: true
248
- }
249
- })
250
- ]);
251
- const logFileUri = logFile && pathToUri(logFile, undefined);
252
- this.initializeResult = {
253
- capabilities: {
254
- textDocumentSync: lsp.TextDocumentSyncKind.Incremental,
255
- completionProvider: {
256
- triggerCharacters: ['.', '"', '\'', '/', '@', '<'],
257
- resolveProvider: true
258
- },
259
- codeActionProvider: ((_g = (_f = clientCapabilities.textDocument) === null || _f === void 0 ? void 0 : _f.codeAction) === null || _g === void 0 ? void 0 : _g.codeActionLiteralSupport)
260
- ? { codeActionKinds: [
261
- ...TypeScriptAutoFixProvider.kinds.map(kind => kind.value),
262
- CodeActionKind.SourceOrganizeImportsTs.value,
263
- CodeActionKind.QuickFix.value,
264
- CodeActionKind.Refactor.value
265
- ] } : true,
266
- definitionProvider: true,
267
- documentFormattingProvider: true,
268
- documentRangeFormattingProvider: true,
269
- documentHighlightProvider: true,
270
- documentSymbolProvider: true,
271
- executeCommandProvider: {
272
- commands: [
273
- Commands.APPLY_WORKSPACE_EDIT,
274
- Commands.APPLY_CODE_ACTION,
275
- Commands.APPLY_REFACTORING,
276
- Commands.ORGANIZE_IMPORTS,
277
- Commands.APPLY_RENAME_FILE
278
- ]
279
- },
280
- hoverProvider: true,
281
- renameProvider: true,
282
- referencesProvider: true,
283
- signatureHelpProvider: {
284
- triggerCharacters: ['(', ',', '<']
202
+ },
203
+ });
204
+ const started = this.tspClient.start();
205
+ if (!started) {
206
+ throw new Error('tsserver process has failed to start.');
207
+ }
208
+ process.on('exit', () => {
209
+ this.shutdown();
210
+ });
211
+ process.on('SIGINT', () => {
212
+ process.exit();
213
+ });
214
+ this.typeScriptAutoFixProvider = new TypeScriptAutoFixProvider(this.tspClient);
215
+ await Promise.all([
216
+ this.configurationManager.setAndConfigureTspClient(this._tspClient, hostInfo),
217
+ this.tspClient.request("compilerOptionsForInferredProjects" /* CommandTypes.CompilerOptionsForInferredProjects */, {
218
+ options: {
219
+ module: "CommonJS" /* tsp.ModuleKind.CommonJS */,
220
+ target: "ES2016" /* tsp.ScriptTarget.ES2016 */,
221
+ jsx: "Preserve" /* tsp.JsxEmit.Preserve */,
222
+ allowJs: true,
223
+ allowSyntheticDefaultImports: true,
224
+ allowNonTsExtensions: true,
225
+ },
226
+ }),
227
+ ]);
228
+ const logFileUri = logFile && pathToUri(logFile, undefined);
229
+ const initializeResult = {
230
+ capabilities: {
231
+ textDocumentSync: lsp.TextDocumentSyncKind.Incremental,
232
+ completionProvider: {
233
+ triggerCharacters: ['.', '"', '\'', '/', '@', '<'],
234
+ resolveProvider: true,
235
+ },
236
+ codeActionProvider: clientCapabilities.textDocument?.codeAction?.codeActionLiteralSupport
237
+ ? { codeActionKinds: [
238
+ ...TypeScriptAutoFixProvider.kinds.map(kind => kind.value),
239
+ CodeActionKind.SourceOrganizeImportsTs.value,
240
+ CodeActionKind.QuickFix.value,
241
+ CodeActionKind.Refactor.value,
242
+ ] } : true,
243
+ definitionProvider: true,
244
+ documentFormattingProvider: true,
245
+ documentRangeFormattingProvider: true,
246
+ documentHighlightProvider: true,
247
+ documentSymbolProvider: true,
248
+ executeCommandProvider: {
249
+ commands: [
250
+ Commands.APPLY_WORKSPACE_EDIT,
251
+ Commands.APPLY_CODE_ACTION,
252
+ Commands.APPLY_REFACTORING,
253
+ Commands.ORGANIZE_IMPORTS,
254
+ Commands.APPLY_RENAME_FILE,
255
+ Commands.SOURCE_DEFINITION,
256
+ ],
257
+ },
258
+ hoverProvider: true,
259
+ inlayHintProvider: true,
260
+ renameProvider: true,
261
+ referencesProvider: true,
262
+ signatureHelpProvider: {
263
+ triggerCharacters: ['(', ',', '<'],
264
+ retriggerCharacters: [')'],
265
+ },
266
+ workspaceSymbolProvider: true,
267
+ implementationProvider: true,
268
+ typeDefinitionProvider: true,
269
+ foldingRangeProvider: true,
270
+ semanticTokensProvider: {
271
+ documentSelector: null,
272
+ legend: {
273
+ // list taken from: https://github.com/microsoft/TypeScript/blob/main/src/services/classifier2020.ts#L10
274
+ tokenTypes: [
275
+ 'class',
276
+ 'enum',
277
+ 'interface',
278
+ 'namespace',
279
+ 'typeParameter',
280
+ 'type',
281
+ 'parameter',
282
+ 'variable',
283
+ 'enumMember',
284
+ 'property',
285
+ 'function',
286
+ 'member',
287
+ ],
288
+ // token from: https://github.com/microsoft/TypeScript/blob/main/src/services/classifier2020.ts#L14
289
+ tokenModifiers: [
290
+ 'declaration',
291
+ 'static',
292
+ 'async',
293
+ 'readonly',
294
+ 'defaultLibrary',
295
+ 'local',
296
+ ],
285
297
  },
286
- workspaceSymbolProvider: true,
287
- implementationProvider: true,
288
- typeDefinitionProvider: true,
289
- foldingRangeProvider: true,
290
- semanticTokensProvider: {
291
- documentSelector: null,
292
- legend: {
293
- // list taken from: https://github.com/microsoft/TypeScript/blob/main/src/services/classifier2020.ts#L10
294
- tokenTypes: [
295
- 'class',
296
- 'enum',
297
- 'interface',
298
- 'namespace',
299
- 'typeParameter',
300
- 'type',
301
- 'parameter',
302
- 'variable',
303
- 'enumMember',
304
- 'property',
305
- 'function',
306
- 'member'
307
- ],
308
- // token from: https://github.com/microsoft/TypeScript/blob/main/src/services/classifier2020.ts#L14
309
- tokenModifiers: [
310
- 'declaration',
311
- 'static',
312
- 'async',
313
- 'readonly',
314
- 'defaultLibrary',
315
- 'local'
316
- ]
317
- },
318
- full: true,
319
- range: true
320
- }
298
+ full: true,
299
+ range: true,
321
300
  },
322
- logFileUri
323
- };
324
- this.initializeResult.capabilities.callsProvider = true;
325
- this.logger.log('onInitialize result', this.initializeResult);
326
- return this.initializeResult;
327
- });
301
+ },
302
+ logFileUri,
303
+ };
304
+ initializeResult.capabilities.callsProvider = true;
305
+ this.logger.log('onInitialize result', initializeResult);
306
+ return initializeResult;
328
307
  }
329
308
  getLogFile(logVerbosity) {
330
309
  if (logVerbosity === undefined || logVerbosity === 'off') {
@@ -350,19 +329,9 @@ export class LspServer {
350
329
  return undefined;
351
330
  }
352
331
  didChangeConfiguration(params) {
353
- var _a, _b;
354
- this.workspaceConfiguration = params.settings || {};
355
- const ignoredDiagnosticCodes = ((_a = this.workspaceConfiguration.diagnostics) === null || _a === void 0 ? void 0 : _a.ignoredCodes) || [];
356
- (_b = this.diagnosticQueue) === null || _b === void 0 ? void 0 : _b.updateIgnoredDiagnosticCodes(ignoredDiagnosticCodes);
357
- }
358
- getWorkspacePreferencesForDocument(file) {
359
- var _a;
360
- const doc = this.documents.get(file);
361
- if (!doc) {
362
- return {};
363
- }
364
- const preferencesKey = doc.languageId.startsWith('typescript') ? 'typescript' : 'javascript';
365
- return (_a = this.workspaceConfiguration[preferencesKey]) !== null && _a !== void 0 ? _a : {};
332
+ this.configurationManager.setWorkspaceConfiguration(params.settings || {});
333
+ const ignoredDiagnosticCodes = this.configurationManager.workspaceConfiguration.diagnostics?.ignoredCodes || [];
334
+ this.diagnosticQueue?.updateIgnoredDiagnosticCodes(ignoredDiagnosticCodes);
366
335
  }
367
336
  interuptDiagnostics(f) {
368
337
  if (!this.diagnosticsTokenSource) {
@@ -373,28 +342,24 @@ export class LspServer {
373
342
  this.requestDiagnostics();
374
343
  return result;
375
344
  }
376
- requestDiagnostics() {
377
- return __awaiter(this, void 0, void 0, function* () {
378
- this.pendingDebouncedRequest = true;
379
- yield this.doRequestDiagnosticsDebounced();
380
- });
345
+ async requestDiagnostics() {
346
+ this.pendingDebouncedRequest = true;
347
+ await this.doRequestDiagnosticsDebounced();
381
348
  }
382
- doRequestDiagnostics() {
383
- return __awaiter(this, void 0, void 0, function* () {
384
- this.cancelDiagnostics();
385
- const geterrTokenSource = new lsp.CancellationTokenSource();
386
- this.diagnosticsTokenSource = geterrTokenSource;
387
- const { files } = this.documents;
388
- try {
389
- return yield this.tspClient.request("geterr" /* CommandTypes.Geterr */, { delay: 0, files }, this.diagnosticsTokenSource.token);
390
- }
391
- finally {
392
- if (this.diagnosticsTokenSource === geterrTokenSource) {
393
- this.diagnosticsTokenSource = undefined;
394
- this.pendingDebouncedRequest = false;
395
- }
349
+ async doRequestDiagnostics() {
350
+ this.cancelDiagnostics();
351
+ const geterrTokenSource = new lsp.CancellationTokenSource();
352
+ this.diagnosticsTokenSource = geterrTokenSource;
353
+ const { files } = this.documents;
354
+ try {
355
+ return await this.tspClient.request("geterr" /* CommandTypes.Geterr */, { delay: 0, files }, this.diagnosticsTokenSource.token);
356
+ }
357
+ finally {
358
+ if (this.diagnosticsTokenSource === geterrTokenSource) {
359
+ this.diagnosticsTokenSource = undefined;
360
+ this.pendingDebouncedRequest = false;
396
361
  }
397
- });
362
+ }
398
363
  }
399
364
  cancelDiagnostics() {
400
365
  if (this.diagnosticsTokenSource) {
@@ -412,7 +377,7 @@ export class LspServer {
412
377
  file,
413
378
  fileContent: params.textDocument.text,
414
379
  scriptKindName: this.getScriptKindName(params.textDocument.languageId),
415
- projectRootPath: this.workspaceRoot
380
+ projectRootPath: this.workspaceRoot,
416
381
  });
417
382
  this.requestDiagnostics();
418
383
  }
@@ -422,9 +387,9 @@ export class LspServer {
422
387
  textDocument: params.textDocument,
423
388
  contentChanges: [
424
389
  {
425
- text: params.textDocument.text
426
- }
427
- ]
390
+ text: params.textDocument.text,
391
+ },
392
+ ],
428
393
  });
429
394
  }
430
395
  }
@@ -455,7 +420,7 @@ export class LspServer {
455
420
  // so we don't leave stale ones.
456
421
  this.options.lspClient.publishDiagnostics({
457
422
  uri: document.uri,
458
- diagnostics: []
423
+ diagnostics: [],
459
424
  });
460
425
  }
461
426
  didChangeTextDocument(params) {
@@ -497,7 +462,7 @@ export class LspServer {
497
462
  offset,
498
463
  endLine,
499
464
  endOffset,
500
- insertString: change.text
465
+ insertString: change.text,
501
466
  });
502
467
  document.applyEdit(textDocument.version, change);
503
468
  }
@@ -506,76 +471,95 @@ export class LspServer {
506
471
  didSaveTextDocument(_params) {
507
472
  // do nothing
508
473
  }
509
- definition(params) {
510
- return __awaiter(this, void 0, void 0, function* () {
511
- // TODO: implement version checking and if semver.gte(version, 270) use `definitionAndBoundSpan` instead
512
- return this.getDefinition({
513
- type: 'definition',
514
- params
515
- });
474
+ async definition(params) {
475
+ return this.getDefinition({
476
+ type: this.features.definitionLinkSupport ? "definitionAndBoundSpan" /* CommandTypes.DefinitionAndBoundSpan */ : "definition" /* CommandTypes.Definition */,
477
+ params,
516
478
  });
517
479
  }
518
- implementation(params) {
519
- return __awaiter(this, void 0, void 0, function* () {
520
- return this.getDefinition({
521
- type: 'implementation',
522
- params
523
- });
480
+ async implementation(params) {
481
+ return this.getSymbolLocations({
482
+ type: "implementation" /* CommandTypes.Implementation */,
483
+ params,
524
484
  });
525
485
  }
526
- typeDefinition(params) {
527
- return __awaiter(this, void 0, void 0, function* () {
528
- return this.getDefinition({
529
- type: 'typeDefinition',
530
- params
531
- });
486
+ async typeDefinition(params) {
487
+ return this.getSymbolLocations({
488
+ type: "typeDefinition" /* CommandTypes.TypeDefinition */,
489
+ params,
532
490
  });
533
491
  }
534
- getDefinition({ type, params }) {
535
- return __awaiter(this, void 0, void 0, function* () {
536
- const file = uriToPath(params.textDocument.uri);
537
- this.logger.log(type, params, file);
538
- if (!file) {
539
- return [];
492
+ async getDefinition({ type, params }) {
493
+ const file = uriToPath(params.textDocument.uri);
494
+ this.logger.log(type, params, file);
495
+ if (!file) {
496
+ return undefined;
497
+ }
498
+ if (type === "definitionAndBoundSpan" /* CommandTypes.DefinitionAndBoundSpan */) {
499
+ const args = Position.toFileLocationRequestArgs(file, params.position);
500
+ const response = await this.tspClient.request(type, args);
501
+ if (response.type !== 'response' || !response.body) {
502
+ return undefined;
540
503
  }
541
- const result = yield this.tspClient.request(type, {
542
- file,
543
- line: params.position.line + 1,
544
- offset: params.position.character + 1
504
+ // `textSpan` can be undefined in older TypeScript versions, despite type saying otherwise.
505
+ const span = response.body.textSpan ? Range.fromTextSpan(response.body.textSpan) : undefined;
506
+ return response.body.definitions
507
+ .map((location) => {
508
+ const target = toLocation(location, this.documents);
509
+ const targetRange = location.contextStart && location.contextEnd
510
+ ? Range.fromLocations(location.contextStart, location.contextEnd)
511
+ : target.range;
512
+ return {
513
+ originSelectionRange: span,
514
+ targetRange,
515
+ targetUri: target.uri,
516
+ targetSelectionRange: target.range,
517
+ };
545
518
  });
546
- return result.body ? result.body.map(fileSpan => toLocation(fileSpan, this.documents)) : [];
547
- });
519
+ }
520
+ return this.getSymbolLocations({ type: "definition" /* CommandTypes.Definition */, params });
548
521
  }
549
- documentSymbol(params) {
550
- return __awaiter(this, void 0, void 0, function* () {
551
- const file = uriToPath(params.textDocument.uri);
552
- this.logger.log('symbol', params, file);
553
- if (!file) {
554
- return [];
555
- }
556
- const response = yield this.tspClient.request("navtree" /* CommandTypes.NavTree */, {
557
- file
558
- });
559
- const tree = response.body;
560
- if (!tree || !tree.childItems) {
561
- return [];
562
- }
563
- if (this.supportHierarchicalDocumentSymbol) {
564
- const symbols = [];
565
- for (const item of tree.childItems) {
566
- collectDocumentSymbols(item, symbols);
567
- }
568
- return symbols;
569
- }
522
+ async getSymbolLocations({ type, params }) {
523
+ const file = uriToPath(params.textDocument.uri);
524
+ this.logger.log(type, params, file);
525
+ if (!file) {
526
+ return [];
527
+ }
528
+ const args = Position.toFileLocationRequestArgs(file, params.position);
529
+ const response = await this.tspClient.request(type, args);
530
+ if (response.type !== 'response' || !response.body) {
531
+ return undefined;
532
+ }
533
+ return response.body.map(fileSpan => toLocation(fileSpan, this.documents));
534
+ }
535
+ async documentSymbol(params) {
536
+ const file = uriToPath(params.textDocument.uri);
537
+ this.logger.log('symbol', params, file);
538
+ if (!file) {
539
+ return [];
540
+ }
541
+ const response = await this.tspClient.request("navtree" /* CommandTypes.NavTree */, {
542
+ file,
543
+ });
544
+ const tree = response.body;
545
+ if (!tree || !tree.childItems) {
546
+ return [];
547
+ }
548
+ if (this.supportHierarchicalDocumentSymbol) {
570
549
  const symbols = [];
571
550
  for (const item of tree.childItems) {
572
- collectSymbolInformation(params.textDocument.uri, item, symbols);
551
+ collectDocumentSymbols(item, symbols);
573
552
  }
574
553
  return symbols;
575
- });
554
+ }
555
+ const symbols = [];
556
+ for (const item of tree.childItems) {
557
+ collectSymbolInformation(params.textDocument.uri, item, symbols);
558
+ }
559
+ return symbols;
576
560
  }
577
561
  get supportHierarchicalDocumentSymbol() {
578
- const textDocument = this.initializeParams.capabilities.textDocument;
562
+ const textDocument = this.initializeParams?.capabilities.textDocument;
579
563
  const documentSymbol = textDocument && textDocument.documentSymbol;
580
564
  return !!documentSymbol && !!documentSymbol.hierarchicalDocumentSymbolSupport;
581
565
  }
@@ -583,541 +567,477 @@ export class LspServer {
583
567
  * implemented based on
584
568
  * https://github.com/Microsoft/vscode/blob/master/extensions/typescript-language-features/src/features/completions.ts
585
569
  */
586
- completion(params) {
587
- return __awaiter(this, void 0, void 0, function* () {
588
- const file = uriToPath(params.textDocument.uri);
589
- this.logger.log('completion', params, file);
590
- if (!file) {
591
- return lsp.CompletionList.create([]);
592
- }
593
- const document = this.documents.get(file);
594
- if (!document) {
595
- throw new Error('The document should be opened for completion, file: ' + file);
596
- }
597
- try {
598
- const result = yield this.interuptDiagnostics(() => {
599
- var _a, _b;
600
- return this.tspClient.request("completionInfo" /* CommandTypes.CompletionInfo */, {
601
- file,
602
- line: params.position.line + 1,
603
- offset: params.position.character + 1,
604
- triggerCharacter: getCompletionTriggerCharacter((_a = params.context) === null || _a === void 0 ? void 0 : _a.triggerCharacter),
605
- triggerKind: (_b = params.context) === null || _b === void 0 ? void 0 : _b.triggerKind
606
- });
607
- });
608
- const { body } = result;
609
- const completions = (body ? body.entries : [])
610
- .filter(entry => entry.kind !== 'warning')
611
- .map(entry => asCompletionItem(entry, file, params.position, document, this.features));
612
- return lsp.CompletionList.create(completions, body === null || body === void 0 ? void 0 : body.isIncomplete);
613
- }
614
- catch (error) {
615
- if (error.message === 'No content available.') {
616
- this.logger.info('No content was available for completion request');
617
- return null;
570
+ async completion(params) {
571
+ const file = uriToPath(params.textDocument.uri);
572
+ this.logger.log('completion', params, file);
573
+ if (!file) {
574
+ return lsp.CompletionList.create([]);
575
+ }
576
+ const document = this.documents.get(file);
577
+ if (!document) {
578
+ throw new Error('The document should be opened for completion, file: ' + file);
579
+ }
580
+ try {
581
+ const result = await this.interuptDiagnostics(() => this.tspClient.request("completionInfo" /* CommandTypes.CompletionInfo */, {
582
+ file,
583
+ line: params.position.line + 1,
584
+ offset: params.position.character + 1,
585
+ triggerCharacter: getCompletionTriggerCharacter(params.context?.triggerCharacter),
586
+ triggerKind: params.context?.triggerKind,
587
+ }));
588
+ const { body } = result;
589
+ const completions = [];
590
+ for (const entry of body?.entries ?? []) {
591
+ if (entry.kind === 'warning') {
592
+ continue;
618
593
  }
619
- else {
620
- throw error;
594
+ const completion = asCompletionItem(entry, file, params.position, document, this.features);
595
+ if (!completion) {
596
+ continue;
621
597
  }
598
+ completions.push(completion);
622
599
  }
623
- });
624
- }
625
- completionResolve(item) {
626
- return __awaiter(this, void 0, void 0, function* () {
627
- this.logger.log('completion/resolve', item);
628
- yield this.tspClient.request("configure" /* CommandTypes.Configure */, {
629
- formatOptions: this.getWorkspacePreferencesForDocument(item.data.file).format
630
- });
631
- const { body } = yield this.interuptDiagnostics(() => this.tspClient.request("completionEntryDetails" /* CommandTypes.CompletionDetails */, item.data));
632
- const details = body && body.length && body[0];
633
- if (!details) {
634
- return item;
635
- }
636
- return asResolvedCompletionItem(item, details, this.tspClient, this.workspaceConfiguration.completions || {});
637
- });
638
- }
639
- hover(params) {
640
- return __awaiter(this, void 0, void 0, function* () {
641
- const file = uriToPath(params.textDocument.uri);
642
- this.logger.log('hover', params, file);
643
- if (!file) {
644
- return { contents: [] };
645
- }
646
- const result = yield this.interuptDiagnostics(() => this.getQuickInfo(file, params.position));
647
- if (!result || !result.body) {
648
- return { contents: [] };
600
+ return lsp.CompletionList.create(completions, body?.isIncomplete);
601
+ }
602
+ catch (error) {
603
+ if (error.message === 'No content available.') {
604
+ this.logger.info('No content was available for completion request');
605
+ return null;
649
606
  }
650
- const range = asRange(result.body);
651
- const contents = [];
652
- if (result.body.displayString) {
653
- contents.push({ language: 'typescript', value: result.body.displayString });
607
+ else {
608
+ throw error;
654
609
  }
655
- const tags = asTagsDocumentation(result.body.tags);
656
- const documentation = asPlainText(result.body.documentation);
657
- contents.push(documentation + (tags ? '\n\n' + tags : ''));
658
- return {
659
- contents,
660
- range
661
- };
662
- });
610
+ }
663
611
  }
664
- getQuickInfo(file, position) {
665
- return __awaiter(this, void 0, void 0, function* () {
666
- try {
667
- return yield this.tspClient.request("quickinfo" /* CommandTypes.Quickinfo */, {
668
- file,
669
- line: position.line + 1,
670
- offset: position.character + 1
671
- });
672
- }
673
- catch (err) {
674
- return undefined;
675
- }
676
- });
612
+ async completionResolve(item) {
613
+ this.logger.log('completion/resolve', item);
614
+ await this.configurationManager.configureGloballyFromDocument(item.data.file);
615
+ const { body } = await this.interuptDiagnostics(() => this.tspClient.request("completionEntryDetails" /* CommandTypes.CompletionDetails */, item.data));
616
+ const details = body && body.length && body[0];
617
+ if (!details) {
618
+ return item;
619
+ }
620
+ return asResolvedCompletionItem(item, details, this.tspClient, this.configurationManager.workspaceConfiguration.completions || {}, this.features);
677
621
  }
678
- rename(params) {
679
- return __awaiter(this, void 0, void 0, function* () {
680
- const file = uriToPath(params.textDocument.uri);
681
- this.logger.log('onRename', params, file);
682
- if (!file) {
683
- return undefined;
684
- }
685
- const result = yield this.tspClient.request("rename" /* CommandTypes.Rename */, {
622
+ async hover(params) {
623
+ const file = uriToPath(params.textDocument.uri);
624
+ this.logger.log('hover', params, file);
625
+ if (!file) {
626
+ return { contents: [] };
627
+ }
628
+ const result = await this.interuptDiagnostics(() => this.getQuickInfo(file, params.position));
629
+ if (!result || !result.body) {
630
+ return { contents: [] };
631
+ }
632
+ const range = Range.fromTextSpan(result.body);
633
+ const contents = [];
634
+ if (result.body.displayString) {
635
+ contents.push({ language: 'typescript', value: result.body.displayString });
636
+ }
637
+ const tags = asTagsDocumentation(result.body.tags);
638
+ const documentation = asPlainText(result.body.documentation);
639
+ contents.push(documentation + (tags ? '\n\n' + tags : ''));
640
+ return {
641
+ contents,
642
+ range,
643
+ };
644
+ }
645
+ async getQuickInfo(file, position) {
646
+ try {
647
+ return await this.tspClient.request("quickinfo" /* CommandTypes.Quickinfo */, {
686
648
  file,
687
- line: params.position.line + 1,
688
- offset: params.position.character + 1
649
+ line: position.line + 1,
650
+ offset: position.character + 1,
689
651
  });
690
- if (!result.body || !result.body.info.canRename || result.body.locs.length === 0) {
691
- return undefined;
692
- }
693
- const workspaceEdit = {
694
- changes: {}
695
- };
696
- result.body.locs
697
- .forEach((spanGroup) => {
698
- const uri = pathToUri(spanGroup.file, this.documents), textEdits = workspaceEdit.changes[uri] || (workspaceEdit.changes[uri] = []);
699
- spanGroup.locs.forEach((textSpan) => {
700
- textEdits.push({
701
- newText: `${textSpan.prefixText || ''}${params.newName}${textSpan.suffixText || ''}`,
702
- range: {
703
- start: toPosition(textSpan.start),
704
- end: toPosition(textSpan.end)
705
- }
706
- });
652
+ }
653
+ catch (err) {
654
+ return undefined;
655
+ }
656
+ }
657
+ async rename(params) {
658
+ const file = uriToPath(params.textDocument.uri);
659
+ this.logger.log('onRename', params, file);
660
+ if (!file) {
661
+ return undefined;
662
+ }
663
+ const result = await this.tspClient.request("rename" /* CommandTypes.Rename */, {
664
+ file,
665
+ line: params.position.line + 1,
666
+ offset: params.position.character + 1,
667
+ });
668
+ if (!result.body || !result.body.info.canRename || result.body.locs.length === 0) {
669
+ return undefined;
670
+ }
671
+ const workspaceEdit = {};
672
+ result.body.locs
673
+ .forEach((spanGroup) => {
674
+ const uri = pathToUri(spanGroup.file, this.documents);
675
+ if (!workspaceEdit.changes) {
676
+ workspaceEdit.changes = {};
677
+ }
678
+ const textEdits = workspaceEdit.changes[uri] || (workspaceEdit.changes[uri] = []);
679
+ spanGroup.locs.forEach((textSpan) => {
680
+ textEdits.push({
681
+ newText: `${textSpan.prefixText || ''}${params.newName}${textSpan.suffixText || ''}`,
682
+ range: {
683
+ start: Position.fromLocation(textSpan.start),
684
+ end: Position.fromLocation(textSpan.end),
685
+ },
707
686
  });
708
687
  });
709
- return workspaceEdit;
710
688
  });
689
+ return workspaceEdit;
711
690
  }
712
- references(params) {
713
- return __awaiter(this, void 0, void 0, function* () {
714
- const file = uriToPath(params.textDocument.uri);
715
- this.logger.log('onReferences', params, file);
716
- if (!file) {
717
- return [];
718
- }
719
- const result = yield this.tspClient.request("references" /* CommandTypes.References */, {
720
- file,
721
- line: params.position.line + 1,
722
- offset: params.position.character + 1
723
- });
724
- if (!result.body) {
725
- return [];
726
- }
727
- return result.body.refs
728
- .filter(fileSpan => params.context.includeDeclaration || !fileSpan.isDefinition)
729
- .map(fileSpan => toLocation(fileSpan, this.documents));
691
+ async references(params) {
692
+ const file = uriToPath(params.textDocument.uri);
693
+ this.logger.log('onReferences', params, file);
694
+ if (!file) {
695
+ return [];
696
+ }
697
+ const result = await this.tspClient.request("references" /* CommandTypes.References */, {
698
+ file,
699
+ line: params.position.line + 1,
700
+ offset: params.position.character + 1,
730
701
  });
702
+ if (!result.body) {
703
+ return [];
704
+ }
705
+ return result.body.refs
706
+ .filter(fileSpan => params.context.includeDeclaration || !fileSpan.isDefinition)
707
+ .map(fileSpan => toLocation(fileSpan, this.documents));
731
708
  }
732
- documentFormatting(params) {
733
- return __awaiter(this, void 0, void 0, function* () {
734
- const file = uriToPath(params.textDocument.uri);
735
- this.logger.log('documentFormatting', params, file);
736
- if (!file) {
737
- return [];
738
- }
739
- const formatOptions = this.getFormattingOptions(file, params.options);
740
- // options are not yet supported in tsserver, but we can send a configure request first
741
- yield this.tspClient.request("configure" /* CommandTypes.Configure */, {
742
- formatOptions
743
- });
744
- const response = yield this.tspClient.request("format" /* CommandTypes.Format */, {
745
- file,
746
- line: 1,
747
- offset: 1,
748
- endLine: Number.MAX_SAFE_INTEGER,
749
- endOffset: Number.MAX_SAFE_INTEGER,
750
- options: formatOptions
751
- });
752
- if (response.body) {
753
- return response.body.map(e => toTextEdit(e));
754
- }
709
+ async documentFormatting(params) {
710
+ const file = uriToPath(params.textDocument.uri);
711
+ this.logger.log('documentFormatting', params, file);
712
+ if (!file) {
755
713
  return [];
714
+ }
715
+ const formatOptions = params.options;
716
+ await this.configurationManager.configureGloballyFromDocument(file, formatOptions);
717
+ const response = await this.tspClient.request("format" /* CommandTypes.Format */, {
718
+ file,
719
+ line: 1,
720
+ offset: 1,
721
+ endLine: Number.MAX_SAFE_INTEGER,
722
+ endOffset: Number.MAX_SAFE_INTEGER,
723
+ options: formatOptions,
756
724
  });
725
+ if (response.body) {
726
+ return response.body.map(e => toTextEdit(e));
727
+ }
728
+ return [];
757
729
  }
758
- documentRangeFormatting(params) {
759
- return __awaiter(this, void 0, void 0, function* () {
760
- const file = uriToPath(params.textDocument.uri);
761
- this.logger.log('documentRangeFormatting', params, file);
762
- if (!file) {
763
- return [];
764
- }
765
- const formatOptions = this.getFormattingOptions(file, params.options);
766
- // options are not yet supported in tsserver, but we can send a configure request first
767
- yield this.tspClient.request("configure" /* CommandTypes.Configure */, {
768
- formatOptions
769
- });
770
- const response = yield this.tspClient.request("format" /* CommandTypes.Format */, {
771
- file,
772
- line: params.range.start.line + 1,
773
- offset: params.range.start.character + 1,
774
- endLine: params.range.end.line + 1,
775
- endOffset: params.range.end.character + 1,
776
- options: formatOptions
777
- });
778
- if (response.body) {
779
- return response.body.map(e => toTextEdit(e));
780
- }
730
+ async documentRangeFormatting(params) {
731
+ const file = uriToPath(params.textDocument.uri);
732
+ this.logger.log('documentRangeFormatting', params, file);
733
+ if (!file) {
781
734
  return [];
735
+ }
736
+ const formatOptions = params.options;
737
+ await this.configurationManager.configureGloballyFromDocument(file, formatOptions);
738
+ const response = await this.tspClient.request("format" /* CommandTypes.Format */, {
739
+ file,
740
+ line: params.range.start.line + 1,
741
+ offset: params.range.start.character + 1,
742
+ endLine: params.range.end.line + 1,
743
+ endOffset: params.range.end.character + 1,
744
+ options: formatOptions,
782
745
  });
783
- }
784
- getFormattingOptions(file, requestOptions) {
785
- const workspacePreference = this.getWorkspacePreferencesForDocument(file);
786
- let opts = Object.assign(Object.assign({}, (workspacePreference === null || workspacePreference === void 0 ? void 0 : workspacePreference.format) || {}), requestOptions);
787
- // translate
788
- if (opts.convertTabsToSpaces === undefined) {
789
- opts.convertTabsToSpaces = requestOptions.insertSpaces;
746
+ if (response.body) {
747
+ return response.body.map(e => toTextEdit(e));
790
748
  }
791
- if (opts.indentSize === undefined) {
792
- opts.indentSize = requestOptions.tabSize;
749
+ return [];
750
+ }
751
+ async signatureHelp(params) {
752
+ const file = uriToPath(params.textDocument.uri);
753
+ this.logger.log('signatureHelp', params, file);
754
+ if (!file) {
755
+ return undefined;
793
756
  }
794
- if (this.workspaceRoot) {
795
- try {
796
- opts = JSON.parse(fs.readFileSync(this.workspaceRoot + '/tsfmt.json', 'utf-8'));
797
- }
798
- catch (err) {
799
- this.logger.log(`No formatting options found ${err}`);
800
- }
757
+ const response = await this.interuptDiagnostics(() => this.getSignatureHelp(file, params));
758
+ if (!response || !response.body) {
759
+ return undefined;
801
760
  }
802
- return opts;
803
- }
804
- signatureHelp(params) {
805
- return __awaiter(this, void 0, void 0, function* () {
806
- const file = uriToPath(params.textDocument.uri);
807
- this.logger.log('signatureHelp', params, file);
808
- if (!file) {
809
- return undefined;
810
- }
811
- const response = yield this.interuptDiagnostics(() => this.getSignatureHelp(file, params.position));
812
- if (!response || !response.body) {
813
- return undefined;
814
- }
815
- return asSignatureHelp(response.body);
816
- });
761
+ return asSignatureHelp(response.body, params.context);
817
762
  }
818
- getSignatureHelp(file, position) {
819
- return __awaiter(this, void 0, void 0, function* () {
820
- try {
821
- return yield this.tspClient.request("signatureHelp" /* CommandTypes.SignatureHelp */, {
822
- file,
823
- line: position.line + 1,
824
- offset: position.character + 1
825
- });
826
- }
827
- catch (err) {
828
- return undefined;
829
- }
830
- });
763
+ async getSignatureHelp(file, params) {
764
+ try {
765
+ const { position, context } = params;
766
+ return await this.tspClient.request("signatureHelp" /* CommandTypes.SignatureHelp */, {
767
+ file,
768
+ line: position.line + 1,
769
+ offset: position.character + 1,
770
+ triggerReason: context ? toTsTriggerReason(context) : undefined,
771
+ });
772
+ }
773
+ catch (err) {
774
+ return undefined;
775
+ }
831
776
  }
832
- codeAction(params) {
833
- var _a, _b;
834
- return __awaiter(this, void 0, void 0, function* () {
835
- const file = uriToPath(params.textDocument.uri);
836
- this.logger.log('codeAction', params, file);
837
- if (!file) {
838
- return [];
839
- }
840
- const args = toFileRangeRequestArgs(file, params.range);
841
- const actions = [];
842
- const kinds = (_a = params.context.only) === null || _a === void 0 ? void 0 : _a.map(kind => new CodeActionKind(kind));
843
- if (!kinds || kinds.some(kind => kind.contains(CodeActionKind.QuickFix))) {
844
- const errorCodes = params.context.diagnostics.map(diagnostic => Number(diagnostic.code));
845
- actions.push(...provideQuickFix(yield this.getCodeFixes(Object.assign(Object.assign({}, args), { errorCodes })), this.documents));
846
- }
847
- if (!kinds || kinds.some(kind => kind.contains(CodeActionKind.Refactor))) {
848
- actions.push(...provideRefactors(yield this.getRefactors(args), args));
849
- }
850
- // organize import is provided by tsserver for any line, so we only get it if explicitly requested
851
- if (kinds === null || kinds === void 0 ? void 0 : kinds.some(kind => kind.contains(CodeActionKind.SourceOrganizeImportsTs))) {
852
- // see this issue for more context about how this argument is used
853
- // https://github.com/microsoft/TypeScript/issues/43051
854
- const skipDestructiveCodeActions = params.context.diagnostics.some(
855
- // assume no severity is an error
856
- d => { var _a; return ((_a = d.severity) !== null && _a !== void 0 ? _a : 0) <= 2; });
857
- const response = yield this.getOrganizeImports({
858
- scope: { type: 'file', args },
859
- skipDestructiveCodeActions
860
- });
861
- actions.push(...provideOrganizeImports(response, this.documents));
862
- }
863
- // TODO: Since we rely on diagnostics pointing at errors in the correct places, we can't proceed if we are not
864
- // sure that diagnostics are up-to-date. Thus we check `pendingDebouncedRequest` to see if there are *any*
865
- // pending diagnostic requests (regardless of for which file).
866
- // In general would be better to replace the whole diagnostics handling logic with the one from
867
- // bufferSyncSupport.ts in VSCode's typescript language features.
868
- if (kinds && !this.pendingDebouncedRequest) {
869
- const diagnostics = ((_b = this.diagnosticQueue) === null || _b === void 0 ? void 0 : _b.getDiagnosticsForFile(file)) || [];
870
- if (diagnostics.length) {
871
- actions.push(...yield this.typeScriptAutoFixProvider.provideCodeActions(kinds, file, diagnostics, this.documents));
872
- }
777
+ async codeAction(params) {
778
+ const file = uriToPath(params.textDocument.uri);
779
+ this.logger.log('codeAction', params, file);
780
+ if (!file) {
781
+ return [];
782
+ }
783
+ const args = Range.toFileRangeRequestArgs(file, params.range);
784
+ const actions = [];
785
+ const kinds = params.context.only?.map(kind => new CodeActionKind(kind));
786
+ if (!kinds || kinds.some(kind => kind.contains(CodeActionKind.QuickFix))) {
787
+ const errorCodes = params.context.diagnostics.map(diagnostic => Number(diagnostic.code));
788
+ actions.push(...provideQuickFix(await this.getCodeFixes({ ...args, errorCodes }), this.documents));
789
+ }
790
+ if (!kinds || kinds.some(kind => kind.contains(CodeActionKind.Refactor))) {
791
+ actions.push(...provideRefactors(await this.getRefactors(args), args));
792
+ }
793
+ // organize import is provided by tsserver for any line, so we only get it if explicitly requested
794
+ if (kinds?.some(kind => kind.contains(CodeActionKind.SourceOrganizeImportsTs))) {
795
+ // see this issue for more context about how this argument is used
796
+ // https://github.com/microsoft/TypeScript/issues/43051
797
+ const skipDestructiveCodeActions = params.context.diagnostics.some(
798
+ // assume no severity is an error
799
+ d => (d.severity ?? 0) <= 2);
800
+ const response = await this.getOrganizeImports({
801
+ scope: { type: 'file', args },
802
+ skipDestructiveCodeActions,
803
+ });
804
+ actions.push(...provideOrganizeImports(response, this.documents));
805
+ }
806
+ // TODO: Since we rely on diagnostics pointing at errors in the correct places, we can't proceed if we are not
807
+ // sure that diagnostics are up-to-date. Thus we check `pendingDebouncedRequest` to see if there are *any*
808
+ // pending diagnostic requests (regardless of for which file).
809
+ // In general would be better to replace the whole diagnostics handling logic with the one from
810
+ // bufferSyncSupport.ts in VSCode's typescript language features.
811
+ if (kinds && !this.pendingDebouncedRequest) {
812
+ const diagnostics = this.diagnosticQueue?.getDiagnosticsForFile(file) || [];
813
+ if (diagnostics.length) {
814
+ actions.push(...await this.typeScriptAutoFixProvider.provideCodeActions(kinds, file, diagnostics, this.documents));
873
815
  }
874
- return actions;
875
- });
816
+ }
817
+ return actions;
876
818
  }
877
- getCodeFixes(args) {
878
- return __awaiter(this, void 0, void 0, function* () {
879
- try {
880
- return yield this.tspClient.request("getCodeFixes" /* CommandTypes.GetCodeFixes */, args);
881
- }
882
- catch (err) {
883
- return undefined;
884
- }
885
- });
819
+ async getCodeFixes(args) {
820
+ try {
821
+ return await this.tspClient.request("getCodeFixes" /* CommandTypes.GetCodeFixes */, args);
822
+ }
823
+ catch (err) {
824
+ return undefined;
825
+ }
886
826
  }
887
- getRefactors(args) {
888
- return __awaiter(this, void 0, void 0, function* () {
889
- try {
890
- return yield this.tspClient.request("getApplicableRefactors" /* CommandTypes.GetApplicableRefactors */, args);
891
- }
892
- catch (err) {
893
- return undefined;
894
- }
895
- });
827
+ async getRefactors(args) {
828
+ try {
829
+ return await this.tspClient.request("getApplicableRefactors" /* CommandTypes.GetApplicableRefactors */, args);
830
+ }
831
+ catch (err) {
832
+ return undefined;
833
+ }
896
834
  }
897
- getOrganizeImports(args) {
898
- return __awaiter(this, void 0, void 0, function* () {
899
- try {
900
- // Pass format options to organize imports
901
- yield this.tspClient.request("configure" /* CommandTypes.Configure */, {
902
- formatOptions: this.getWorkspacePreferencesForDocument(args.scope.args.file).format
903
- });
904
- return yield this.tspClient.request("organizeImports" /* CommandTypes.OrganizeImports */, args);
905
- }
906
- catch (err) {
907
- return undefined;
908
- }
909
- });
835
+ async getOrganizeImports(args) {
836
+ try {
837
+ await this.configurationManager.configureGloballyFromDocument(args.scope.args.file);
838
+ return await this.tspClient.request("organizeImports" /* CommandTypes.OrganizeImports */, args);
839
+ }
840
+ catch (err) {
841
+ return undefined;
842
+ }
910
843
  }
911
- executeCommand(arg) {
912
- return __awaiter(this, void 0, void 0, function* () {
913
- this.logger.log('executeCommand', arg);
914
- if (arg.command === Commands.APPLY_WORKSPACE_EDIT && arg.arguments) {
915
- const edit = arg.arguments[0];
916
- yield this.options.lspClient.applyWorkspaceEdit({
917
- edit
918
- });
919
- }
920
- else if (arg.command === Commands.APPLY_CODE_ACTION && arg.arguments) {
921
- const codeAction = arg.arguments[0];
922
- if (!(yield this.applyFileCodeEdits(codeAction.changes))) {
923
- return;
924
- }
925
- if (codeAction.commands && codeAction.commands.length) {
926
- for (const command of codeAction.commands) {
927
- yield this.tspClient.request("applyCodeActionCommand" /* CommandTypes.ApplyCodeActionCommand */, { command });
928
- }
929
- }
930
- }
931
- else if (arg.command === Commands.APPLY_REFACTORING && arg.arguments) {
932
- const args = arg.arguments[0];
933
- const { body } = yield this.tspClient.request("getEditsForRefactor" /* CommandTypes.GetEditsForRefactor */, args);
934
- if (!body || !body.edits.length) {
935
- return;
936
- }
937
- for (const edit of body.edits) {
938
- yield fs.ensureFile(edit.fileName);
939
- }
940
- if (!(yield this.applyFileCodeEdits(body.edits))) {
941
- return;
942
- }
943
- const renameLocation = body.renameLocation;
944
- if (renameLocation) {
945
- yield this.options.lspClient.rename({
946
- textDocument: {
947
- uri: pathToUri(args.file, this.documents)
948
- },
949
- position: toPosition(renameLocation)
950
- });
844
+ async executeCommand(arg, token, workDoneProgress) {
845
+ this.logger.log('executeCommand', arg);
846
+ if (arg.command === Commands.APPLY_WORKSPACE_EDIT && arg.arguments) {
847
+ const edit = arg.arguments[0];
848
+ await this.options.lspClient.applyWorkspaceEdit({ edit });
849
+ }
850
+ else if (arg.command === Commands.APPLY_CODE_ACTION && arg.arguments) {
851
+ const codeAction = arg.arguments[0];
852
+ if (!await this.applyFileCodeEdits(codeAction.changes)) {
853
+ return;
854
+ }
855
+ if (codeAction.commands && codeAction.commands.length) {
856
+ for (const command of codeAction.commands) {
857
+ await this.tspClient.request("applyCodeActionCommand" /* CommandTypes.ApplyCodeActionCommand */, { command });
951
858
  }
952
859
  }
953
- else if (arg.command === Commands.ORGANIZE_IMPORTS && arg.arguments) {
954
- const file = arg.arguments[0];
955
- const additionalArguments = arg.arguments[1] || {};
956
- yield this.tspClient.request("configure" /* CommandTypes.Configure */, {
957
- formatOptions: this.getWorkspacePreferencesForDocument(file).format
958
- });
959
- const { body } = yield this.tspClient.request("organizeImports" /* CommandTypes.OrganizeImports */, {
960
- scope: {
961
- type: 'file',
962
- args: { file }
860
+ }
861
+ else if (arg.command === Commands.APPLY_REFACTORING && arg.arguments) {
862
+ const args = arg.arguments[0];
863
+ const { body } = await this.tspClient.request("getEditsForRefactor" /* CommandTypes.GetEditsForRefactor */, args);
864
+ if (!body || !body.edits.length) {
865
+ return;
866
+ }
867
+ for (const edit of body.edits) {
868
+ await fs.ensureFile(edit.fileName);
869
+ }
870
+ if (!await this.applyFileCodeEdits(body.edits)) {
871
+ return;
872
+ }
873
+ const renameLocation = body.renameLocation;
874
+ if (renameLocation) {
875
+ await this.options.lspClient.rename({
876
+ textDocument: {
877
+ uri: pathToUri(args.file, this.documents),
963
878
  },
964
- skipDestructiveCodeActions: additionalArguments.skipDestructiveCodeActions
879
+ position: Position.fromLocation(renameLocation),
965
880
  });
966
- yield this.applyFileCodeEdits(body);
967
- }
968
- else if (arg.command === Commands.APPLY_RENAME_FILE && arg.arguments) {
969
- const { sourceUri, targetUri } = arg.arguments[0];
970
- this.applyRenameFile(sourceUri, targetUri);
971
881
  }
972
- else if (arg.command === Commands.APPLY_COMPLETION_CODE_ACTION && arg.arguments) {
973
- const [_, codeActions] = arg.arguments;
974
- for (const codeAction of codeActions) {
975
- yield this.applyFileCodeEdits(codeAction.changes);
976
- if (codeAction.commands && codeAction.commands.length) {
977
- for (const command of codeAction.commands) {
978
- yield this.tspClient.request("applyCodeActionCommand" /* CommandTypes.ApplyCodeActionCommand */, { command });
979
- }
882
+ }
883
+ else if (arg.command === Commands.ORGANIZE_IMPORTS && arg.arguments) {
884
+ const file = arg.arguments[0];
885
+ const additionalArguments = arg.arguments[1] || {};
886
+ await this.configurationManager.configureGloballyFromDocument(file);
887
+ const { body } = await this.tspClient.request("organizeImports" /* CommandTypes.OrganizeImports */, {
888
+ scope: {
889
+ type: 'file',
890
+ args: { file },
891
+ },
892
+ skipDestructiveCodeActions: additionalArguments.skipDestructiveCodeActions,
893
+ });
894
+ await this.applyFileCodeEdits(body);
895
+ }
896
+ else if (arg.command === Commands.APPLY_RENAME_FILE && arg.arguments) {
897
+ const { sourceUri, targetUri } = arg.arguments[0];
898
+ this.applyRenameFile(sourceUri, targetUri);
899
+ }
900
+ else if (arg.command === Commands.APPLY_COMPLETION_CODE_ACTION && arg.arguments) {
901
+ const [_, codeActions] = arg.arguments;
902
+ for (const codeAction of codeActions) {
903
+ await this.applyFileCodeEdits(codeAction.changes);
904
+ if (codeAction.commands && codeAction.commands.length) {
905
+ for (const command of codeAction.commands) {
906
+ await this.tspClient.request("applyCodeActionCommand" /* CommandTypes.ApplyCodeActionCommand */, { command });
980
907
  }
981
- // Execute only the first code action.
982
- break;
983
908
  }
909
+ // Execute only the first code action.
910
+ break;
984
911
  }
985
- else {
986
- this.logger.error(`Unknown command ${arg.command}.`);
987
- }
988
- });
912
+ }
913
+ else if (arg.command === Commands.SOURCE_DEFINITION) {
914
+ const [uri, position] = (arg.arguments || []);
915
+ const reporter = await this.options.lspClient.createProgressReporter(token, workDoneProgress);
916
+ return SourceDefinitionCommand.execute(uri, position, this.documents, this.tspClient, this.options.lspClient, reporter);
917
+ }
918
+ else {
919
+ this.logger.error(`Unknown command ${arg.command}.`);
920
+ }
989
921
  }
990
- applyFileCodeEdits(edits) {
991
- return __awaiter(this, void 0, void 0, function* () {
992
- if (!edits.length) {
993
- return false;
994
- }
995
- const changes = {};
996
- for (const edit of edits) {
997
- changes[pathToUri(edit.fileName, this.documents)] = edit.textChanges.map(toTextEdit);
998
- }
999
- const { applied } = yield this.options.lspClient.applyWorkspaceEdit({
1000
- edit: { changes }
1001
- });
1002
- return applied;
922
+ async applyFileCodeEdits(edits) {
923
+ if (!edits.length) {
924
+ return false;
925
+ }
926
+ const changes = {};
927
+ for (const edit of edits) {
928
+ changes[pathToUri(edit.fileName, this.documents)] = edit.textChanges.map(toTextEdit);
929
+ }
930
+ const { applied } = await this.options.lspClient.applyWorkspaceEdit({
931
+ edit: { changes },
1003
932
  });
933
+ return applied;
1004
934
  }
1005
- applyRenameFile(sourceUri, targetUri) {
1006
- return __awaiter(this, void 0, void 0, function* () {
1007
- const edits = yield this.getEditsForFileRename(sourceUri, targetUri);
1008
- this.applyFileCodeEdits(edits);
1009
- });
935
+ async applyRenameFile(sourceUri, targetUri) {
936
+ const edits = await this.getEditsForFileRename(sourceUri, targetUri);
937
+ this.applyFileCodeEdits(edits);
1010
938
  }
1011
- getEditsForFileRename(sourceUri, targetUri) {
1012
- return __awaiter(this, void 0, void 0, function* () {
1013
- const newFilePath = uriToPath(targetUri);
1014
- const oldFilePath = uriToPath(sourceUri);
1015
- if (!newFilePath || !oldFilePath) {
1016
- return [];
1017
- }
1018
- try {
1019
- const { body } = yield this.tspClient.request("getEditsForFileRename" /* CommandTypes.GetEditsForFileRename */, {
1020
- oldFilePath,
1021
- newFilePath
1022
- });
1023
- return body;
1024
- }
1025
- catch (err) {
1026
- return [];
1027
- }
1028
- });
939
+ async getEditsForFileRename(sourceUri, targetUri) {
940
+ const newFilePath = uriToPath(targetUri);
941
+ const oldFilePath = uriToPath(sourceUri);
942
+ if (!newFilePath || !oldFilePath) {
943
+ return [];
944
+ }
945
+ try {
946
+ const { body } = await this.tspClient.request("getEditsForFileRename" /* CommandTypes.GetEditsForFileRename */, {
947
+ oldFilePath,
948
+ newFilePath,
949
+ });
950
+ return body;
951
+ }
952
+ catch (err) {
953
+ return [];
954
+ }
1029
955
  }
1030
- documentHighlight(arg) {
1031
- return __awaiter(this, void 0, void 0, function* () {
1032
- const file = uriToPath(arg.textDocument.uri);
1033
- this.logger.log('documentHighlight', arg, file);
1034
- if (!file) {
1035
- return [];
1036
- }
1037
- let response;
1038
- try {
1039
- response = yield this.tspClient.request("documentHighlights" /* CommandTypes.DocumentHighlights */, {
1040
- file,
1041
- line: arg.position.line + 1,
1042
- offset: arg.position.character + 1,
1043
- filesToSearch: [file]
1044
- });
1045
- }
1046
- catch (err) {
1047
- return [];
1048
- }
1049
- if (!response.body) {
1050
- return [];
1051
- }
1052
- const result = [];
1053
- for (const item of response.body) {
1054
- // tsp returns item.file with POSIX path delimiters, whereas file is platform specific.
1055
- // Converting to a URI and back to a path ensures consistency.
1056
- if (normalizePath(item.file) === file) {
1057
- const highlights = toDocumentHighlight(item);
1058
- result.push(...highlights);
1059
- }
956
+ async documentHighlight(arg) {
957
+ const file = uriToPath(arg.textDocument.uri);
958
+ this.logger.log('documentHighlight', arg, file);
959
+ if (!file) {
960
+ return [];
961
+ }
962
+ let response;
963
+ try {
964
+ response = await this.tspClient.request("documentHighlights" /* CommandTypes.DocumentHighlights */, {
965
+ file,
966
+ line: arg.position.line + 1,
967
+ offset: arg.position.character + 1,
968
+ filesToSearch: [file],
969
+ });
970
+ }
971
+ catch (err) {
972
+ return [];
973
+ }
974
+ if (!response.body) {
975
+ return [];
976
+ }
977
+ const result = [];
978
+ for (const item of response.body) {
979
+ // tsp returns item.file with POSIX path delimiters, whereas file is platform specific.
980
+ // Converting to a URI and back to a path ensures consistency.
981
+ if (normalizePath(item.file) === file) {
982
+ const highlights = toDocumentHighlight(item);
983
+ result.push(...highlights);
1060
984
  }
1061
- return result;
1062
- });
985
+ }
986
+ return result;
1063
987
  }
1064
988
  lastFileOrDummy() {
1065
989
  return this.documents.files[0] || this.workspaceRoot;
1066
990
  }
1067
- workspaceSymbol(params) {
1068
- return __awaiter(this, void 0, void 0, function* () {
1069
- const result = yield this.tspClient.request("navto" /* CommandTypes.Navto */, {
1070
- file: this.lastFileOrDummy(),
1071
- searchValue: params.query
1072
- });
1073
- if (!result.body) {
1074
- return [];
1075
- }
1076
- return result.body.map(item => {
1077
- return {
1078
- location: {
1079
- uri: pathToUri(item.file, this.documents),
1080
- range: {
1081
- start: toPosition(item.start),
1082
- end: toPosition(item.end)
1083
- }
991
+ async workspaceSymbol(params) {
992
+ const result = await this.tspClient.request("navto" /* CommandTypes.Navto */, {
993
+ file: this.lastFileOrDummy(),
994
+ searchValue: params.query,
995
+ });
996
+ if (!result.body) {
997
+ return [];
998
+ }
999
+ return result.body.map(item => {
1000
+ return {
1001
+ location: {
1002
+ uri: pathToUri(item.file, this.documents),
1003
+ range: {
1004
+ start: Position.fromLocation(item.start),
1005
+ end: Position.fromLocation(item.end),
1084
1006
  },
1085
- kind: toSymbolKind(item.kind),
1086
- name: item.name
1087
- };
1088
- });
1007
+ },
1008
+ kind: toSymbolKind(item.kind),
1009
+ name: item.name,
1010
+ };
1089
1011
  });
1090
1012
  }
1091
1013
  /**
1092
1014
  * implemented based on https://github.com/Microsoft/vscode/blob/master/extensions/typescript-language-features/src/features/folding.ts
1093
1015
  */
1094
- foldingRanges(params) {
1095
- return __awaiter(this, void 0, void 0, function* () {
1096
- const file = uriToPath(params.textDocument.uri);
1097
- this.logger.log('foldingRanges', params, file);
1098
- if (!file) {
1099
- return undefined;
1100
- }
1101
- const document = this.documents.get(file);
1102
- if (!document) {
1103
- throw new Error("The document should be opened for foldingRanges', file: " + file);
1104
- }
1105
- const { body } = yield this.tspClient.request("getOutliningSpans" /* CommandTypes.GetOutliningSpans */, { file });
1106
- if (!body) {
1107
- return undefined;
1108
- }
1109
- const foldingRanges = [];
1110
- for (const span of body) {
1111
- const foldingRange = this.asFoldingRange(span, document);
1112
- if (foldingRange) {
1113
- foldingRanges.push(foldingRange);
1114
- }
1016
+ async foldingRanges(params) {
1017
+ const file = uriToPath(params.textDocument.uri);
1018
+ this.logger.log('foldingRanges', params, file);
1019
+ if (!file) {
1020
+ return undefined;
1021
+ }
1022
+ const document = this.documents.get(file);
1023
+ if (!document) {
1024
+ throw new Error("The document should be opened for foldingRanges', file: " + file);
1025
+ }
1026
+ const { body } = await this.tspClient.request("getOutliningSpans" /* CommandTypes.GetOutliningSpans */, { file });
1027
+ if (!body) {
1028
+ return undefined;
1029
+ }
1030
+ const foldingRanges = [];
1031
+ for (const span of body) {
1032
+ const foldingRange = this.asFoldingRange(span, document);
1033
+ if (foldingRange) {
1034
+ foldingRanges.push(foldingRange);
1115
1035
  }
1116
- return foldingRanges;
1117
- });
1036
+ }
1037
+ return foldingRanges;
1118
1038
  }
1119
1039
  asFoldingRange(span, document) {
1120
- const range = asRange(span.textSpan);
1040
+ const range = Range.fromTextSpan(span.textSpan);
1121
1041
  const kind = this.asFoldingRangeKind(span);
1122
1042
  // workaround for https://github.com/Microsoft/vscode/issues/49904
1123
1043
  if (span.kind === 'comment') {
@@ -1132,7 +1052,7 @@ export class LspServer {
1132
1052
  return {
1133
1053
  startLine,
1134
1054
  endLine,
1135
- kind
1055
+ kind,
1136
1056
  };
1137
1057
  }
1138
1058
  asFoldingRangeKind(span) {
@@ -1144,150 +1064,136 @@ export class LspServer {
1144
1064
  default: return undefined;
1145
1065
  }
1146
1066
  }
1147
- onTsEvent(event) {
1148
- var _a;
1067
+ async onTsEvent(event) {
1149
1068
  if (event.event === "semanticDiag" /* EventTypes.SementicDiag */ ||
1150
1069
  event.event === "syntaxDiag" /* EventTypes.SyntaxDiag */ ||
1151
1070
  event.event === "suggestionDiag" /* EventTypes.SuggestionDiag */) {
1152
- (_a = this.diagnosticQueue) === null || _a === void 0 ? void 0 : _a.updateDiagnostics(event.event, event);
1071
+ this.diagnosticQueue?.updateDiagnostics(event.event, event);
1153
1072
  }
1154
1073
  else if (event.event === "projectLoadingStart" /* EventTypes.ProjectLoadingStart */) {
1155
- this.loadingIndicator.startedLoadingProject(event.body.projectName);
1074
+ await this.loadingIndicator.startedLoadingProject(event.body.projectName);
1156
1075
  }
1157
1076
  else if (event.event === "projectLoadingFinish" /* EventTypes.ProjectLoadingFinish */) {
1158
1077
  this.loadingIndicator.finishedLoadingProject(event.body.projectName);
1159
1078
  }
1160
1079
  else {
1161
1080
  this.logger.log('Ignored event', {
1162
- event: event.event
1081
+ event: event.event,
1163
1082
  });
1164
1083
  }
1165
1084
  }
1166
- calls(params) {
1167
- return __awaiter(this, void 0, void 0, function* () {
1168
- let callsResult = { calls: [] };
1169
- const file = uriToPath(params.textDocument.uri);
1170
- this.logger.log('calls', params, file);
1171
- if (!file) {
1172
- return callsResult;
1173
- }
1174
- if (params.direction === lspcalls.CallDirection.Outgoing) {
1175
- const documentProvider = (file) => this.documents.get(file);
1176
- callsResult = yield computeCallees(this.tspClient, params, documentProvider);
1177
- }
1178
- else {
1179
- callsResult = yield computeCallers(this.tspClient, params);
1180
- }
1085
+ async calls(params) {
1086
+ let callsResult = { calls: [] };
1087
+ const file = uriToPath(params.textDocument.uri);
1088
+ this.logger.log('calls', params, file);
1089
+ if (!file) {
1181
1090
  return callsResult;
1182
- });
1183
- }
1184
- inlayHints(params) {
1185
- var _a, _b, _c, _d, _e, _f;
1186
- return __awaiter(this, void 0, void 0, function* () {
1187
- const file = uriToPath(params.textDocument.uri);
1188
- this.logger.log('inlayHints', params, file);
1189
- if (!file) {
1190
- return { inlayHints: [] };
1191
- }
1192
- yield this.tspClient.request("configure" /* CommandTypes.Configure */, {
1193
- preferences: this.getInlayHintsOptions(file)
1194
- });
1195
- const doc = this.documents.get(file);
1196
- if (!doc) {
1197
- return { inlayHints: [] };
1198
- }
1199
- const start = doc.offsetAt((_b = (_a = params.range) === null || _a === void 0 ? void 0 : _a.start) !== null && _b !== void 0 ? _b : {
1200
- line: 0,
1201
- character: 0
1202
- });
1203
- const end = doc.offsetAt((_d = (_c = params.range) === null || _c === void 0 ? void 0 : _c.end) !== null && _d !== void 0 ? _d : {
1204
- line: doc.lineCount + 1,
1205
- character: 0
1206
- });
1207
- try {
1208
- const result = yield this.tspClient.request("provideInlayHints" /* CommandTypes.ProvideInlayHints */, {
1209
- file,
1210
- start: start,
1211
- length: end - start
1212
- });
1213
- return {
1214
- inlayHints: (_f = (_e = result.body) === null || _e === void 0 ? void 0 : _e.map((item) => ({
1215
- text: item.text,
1216
- position: toPosition(item.position),
1217
- whitespaceAfter: item.whitespaceAfter,
1218
- whitespaceBefore: item.whitespaceBefore,
1219
- kind: item.kind
1220
- }))) !== null && _f !== void 0 ? _f : []
1221
- };
1222
- }
1223
- catch (_g) {
1224
- return {
1225
- inlayHints: []
1226
- };
1227
- }
1228
- });
1091
+ }
1092
+ if (params.direction === lspcalls.CallDirection.Outgoing) {
1093
+ const documentProvider = (file) => this.documents.get(file);
1094
+ callsResult = await computeCallees(this.tspClient, params, documentProvider);
1095
+ }
1096
+ else {
1097
+ callsResult = await computeCallers(this.tspClient, params);
1098
+ }
1099
+ return callsResult;
1229
1100
  }
1230
- getInlayHintsOptions(file) {
1231
- var _a, _b;
1232
- const workspacePreference = this.getWorkspacePreferencesForDocument(file);
1233
- const userPreferences = ((_a = this.initializeParams.initializationOptions) === null || _a === void 0 ? void 0 : _a.preferences) || {};
1234
- return Object.assign(Object.assign({}, userPreferences), (_b = workspacePreference.inlayHints) !== null && _b !== void 0 ? _b : {});
1101
+ async inlayHints(params) {
1102
+ return await TypeScriptInlayHintsProvider.provideInlayHints(params.textDocument.uri, params.range, this.documents, this.tspClient, this.options.lspClient, this.configurationManager);
1235
1103
  }
1236
- semanticTokensFull(params) {
1237
- return __awaiter(this, void 0, void 0, function* () {
1238
- const file = uriToPath(params.textDocument.uri);
1239
- this.logger.log('semanticTokensFull', params, file);
1240
- if (!file) {
1241
- return { data: [] };
1242
- }
1243
- const doc = this.documents.get(file);
1244
- if (!doc) {
1245
- return { data: [] };
1246
- }
1247
- const start = doc.offsetAt({
1248
- line: 0,
1249
- character: 0
1250
- });
1251
- const end = doc.offsetAt({
1252
- line: doc.lineCount,
1253
- character: 0
1254
- });
1255
- return this.getSemanticTokens(doc, file, start, end);
1104
+ async inlayHintsLegacy(params) {
1105
+ this.options.lspClient.logMessage({
1106
+ message: 'Support for experimental "typescript/inlayHints" request is deprecated. Use spec-compliant "textDocument/inlayHint" instead.',
1107
+ type: lsp.MessageType.Warning,
1256
1108
  });
1257
- }
1258
- semanticTokensRange(params) {
1259
- return __awaiter(this, void 0, void 0, function* () {
1260
- const file = uriToPath(params.textDocument.uri);
1261
- this.logger.log('semanticTokensRange', params, file);
1262
- if (!file) {
1263
- return { data: [] };
1264
- }
1265
- const doc = this.documents.get(file);
1266
- if (!doc) {
1267
- return { data: [] };
1268
- }
1269
- const start = doc.offsetAt(params.range.start);
1270
- const end = doc.offsetAt(params.range.end);
1271
- return this.getSemanticTokens(doc, file, start, end);
1109
+ const file = uriToPath(params.textDocument.uri);
1110
+ this.logger.log('inlayHints', params, file);
1111
+ if (!file) {
1112
+ return { inlayHints: [] };
1113
+ }
1114
+ await this.configurationManager.configureGloballyFromDocument(file);
1115
+ const doc = this.documents.get(file);
1116
+ if (!doc) {
1117
+ return { inlayHints: [] };
1118
+ }
1119
+ const start = doc.offsetAt(params.range?.start ?? {
1120
+ line: 0,
1121
+ character: 0,
1122
+ });
1123
+ const end = doc.offsetAt(params.range?.end ?? {
1124
+ line: doc.lineCount + 1,
1125
+ character: 0,
1272
1126
  });
1127
+ try {
1128
+ const result = await this.tspClient.request("provideInlayHints" /* CommandTypes.ProvideInlayHints */, {
1129
+ file,
1130
+ start: start,
1131
+ length: end - start,
1132
+ });
1133
+ return {
1134
+ inlayHints: result.body?.map((item) => ({
1135
+ text: item.text,
1136
+ position: Position.fromLocation(item.position),
1137
+ whitespaceAfter: item.whitespaceAfter,
1138
+ whitespaceBefore: item.whitespaceBefore,
1139
+ kind: item.kind,
1140
+ })) ?? [],
1141
+ };
1142
+ }
1143
+ catch {
1144
+ return {
1145
+ inlayHints: [],
1146
+ };
1147
+ }
1273
1148
  }
1274
- getSemanticTokens(doc, file, startOffset, endOffset) {
1275
- var _a, _b;
1276
- return __awaiter(this, void 0, void 0, function* () {
1277
- try {
1278
- const result = yield this.tspClient.request("encodedSemanticClassifications-full" /* CommandTypes.EncodedSemanticClassificationsFull */, {
1279
- file,
1280
- start: startOffset,
1281
- length: endOffset - startOffset,
1282
- format: '2020'
1283
- });
1284
- const spans = (_b = (_a = result.body) === null || _a === void 0 ? void 0 : _a.spans) !== null && _b !== void 0 ? _b : [];
1285
- return { data: lspsemanticTokens.transformSpans(doc, spans) };
1286
- }
1287
- catch (_c) {
1288
- return { data: [] };
1289
- }
1149
+ async semanticTokensFull(params) {
1150
+ const file = uriToPath(params.textDocument.uri);
1151
+ this.logger.log('semanticTokensFull', params, file);
1152
+ if (!file) {
1153
+ return { data: [] };
1154
+ }
1155
+ const doc = this.documents.get(file);
1156
+ if (!doc) {
1157
+ return { data: [] };
1158
+ }
1159
+ const start = doc.offsetAt({
1160
+ line: 0,
1161
+ character: 0,
1162
+ });
1163
+ const end = doc.offsetAt({
1164
+ line: doc.lineCount,
1165
+ character: 0,
1290
1166
  });
1167
+ return this.getSemanticTokens(doc, file, start, end);
1168
+ }
1169
+ async semanticTokensRange(params) {
1170
+ const file = uriToPath(params.textDocument.uri);
1171
+ this.logger.log('semanticTokensRange', params, file);
1172
+ if (!file) {
1173
+ return { data: [] };
1174
+ }
1175
+ const doc = this.documents.get(file);
1176
+ if (!doc) {
1177
+ return { data: [] };
1178
+ }
1179
+ const start = doc.offsetAt(params.range.start);
1180
+ const end = doc.offsetAt(params.range.end);
1181
+ return this.getSemanticTokens(doc, file, start, end);
1182
+ }
1183
+ async getSemanticTokens(doc, file, startOffset, endOffset) {
1184
+ try {
1185
+ const result = await this.tspClient.request("encodedSemanticClassifications-full" /* CommandTypes.EncodedSemanticClassificationsFull */, {
1186
+ file,
1187
+ start: startOffset,
1188
+ length: endOffset - startOffset,
1189
+ format: '2020',
1190
+ });
1191
+ const spans = result.body?.spans ?? [];
1192
+ return { data: lspsemanticTokens.transformSpans(doc, spans) };
1193
+ }
1194
+ catch {
1195
+ return { data: [] };
1196
+ }
1291
1197
  }
1292
1198
  }
1293
1199
  //# sourceMappingURL=lsp-server.js.map