Skip to content

Commit

Permalink
feat: add tsserver.logVerbosity and tsserver.path to `initializat…
Browse files Browse the repository at this point in the history
…ionOptions` (#611)
  • Loading branch information
rchl committed Oct 15, 2022
1 parent 417339f commit a03eab5
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 54 deletions.
23 changes: 20 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ typescript-language-server --stdio
-V, --version output the version number
--stdio use stdio (required option)
--log-level <log-level> A number indicating the log level (4 = log, 3 = info, 2 = warn, 1 = error). Defaults to `3`.
--tsserver-log-verbosity <verbosity> Specify tsserver log verbosity (off, terse, normal, verbose). Defaults to `normal`. example: --tsserver-log-verbosity=verbose
--tsserver-path <path> Specify path to tsserver directory. example: --tsserver-path=/Users/me/typescript/lib/
--tsserver-log-verbosity <verbosity> [deprecated] Specify tsserver log verbosity (off, terse, normal, verbose). Defaults to `normal`. example: --tsserver-log-verbosity=verbose
--tsserver-path <path> [deprecated] Specify path to tsserver directory. example: --tsserver-path=/Users/me/typescript/lib/
-h, --help output usage information
```

> The `--tsserver-log-verbosity` and `--tsserver-path` options are deprecated and it is recommended to pass those through corresponding `tsserver.*` `initializationOptions` instead.
> Note: The path passed to `--tsserver-path` should be a path to the `[...]/typescript/lib/tssserver.js` file or to the `[...]/typescript/lib/` directory and not to the shell script `[...]/node_modules/.bin/tsserver`. Though for backward-compatibility reasons, the server will try to do the right thing even when passed a path to the shell script.
## initializationOptions
Expand All @@ -89,16 +91,31 @@ The `tsserver` setting specifies additional options related to the internal `tss
```ts
interface TsserverOptions {
/**
* The path to the directory where the `tsserver` logs will be created.
* The path to the directory where the `tsserver` log files will be created.
* If not provided, the log files will be created within the workspace, inside the `.log` directory.
* If no workspace root is provided when initializating the server and no custom path is specified then
* the logs will not be created.
*
* @default undefined
*/
logDirectory?: string;
/**
* Verbosity of the information logged into the `tsserver` log files.
*
* Log levels from least to most amount of details: `'terse'`, `'normal'`, `'requestTime`', `'verbose'`.
* Enabling particular level also enables all lower levels.
*
* @default 'off'
*/
logVerbosity?: 'off' | 'terse' | 'normal' | 'requestTime' | 'verbose';
/**
* The path to the `tsserver.js` file or the typescript lib directory. For example: `/Users/me/typescript/lib/tsserver.js`.
*/
path?: string;
/**
* The verbosity of logging of the tsserver communication.
* Delivered through the LSP messages and not related to file logging.
*
* @default 'off'
*/
trace?: 'off' | 'messages' | 'verbose';
Expand Down
10 changes: 2 additions & 8 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ const program = new Command('typescript-language-server')

const options = program.opts();

let tsserverLogVerbosity = TsServerLogLevel.fromString(options.tsserverLogVerbosity);

if (options.tsserverLogFile && tsserverLogVerbosity === TsServerLogLevel.Off) {
tsserverLogVerbosity = TsServerLogLevel.Normal;
}

let logLevel = DEFAULT_LOG_LEVEL;
if (options.logLevel) {
logLevel = parseInt(options.logLevel, 10);
Expand All @@ -42,7 +36,7 @@ if (options.logLevel) {
}

createLspConnection({
tsserverPath: options.tsserverPath as string,
tsserverLogVerbosity,
cmdLineTsserverPath: options.tsserverPath as string,
cmdLineTsserverLogVerbosity: TsServerLogLevel.fromString(options.tsserverLogVerbosity),
showMessageLevel: logLevel as lsp.MessageType,
}).listen();
8 changes: 4 additions & 4 deletions src/lsp-connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { LspClientImpl } from './lsp-client.js';
import type { TsServerLogLevel } from './utils/configuration.js';

export interface LspConnectionOptions {
tsserverPath: string;
tsserverLogVerbosity: TsServerLogLevel;
cmdLineTsserverPath: string;
cmdLineTsserverLogVerbosity: TsServerLogLevel;
showMessageLevel: lsp.MessageType;
}

Expand All @@ -26,8 +26,8 @@ export function createLspConnection(options: LspConnectionOptions): lsp.Connecti
const server: LspServer = new LspServer({
logger,
lspClient,
tsserverPath: options.tsserverPath,
tsserverLogVerbosity: options.tsserverLogVerbosity,
tsserverPath: options.cmdLineTsserverPath,
tsserverLogVerbosity: options.cmdLineTsserverLogVerbosity,
});

connection.onInitialize(server.initialize.bind(server));
Expand Down
59 changes: 30 additions & 29 deletions src/lsp-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { provideOrganizeImports } from './organize-imports.js';
import { TypeScriptInitializeParams, TypeScriptInitializationOptions, SupportedFeatures } from './ts-protocol.js';
import { collectDocumentSymbols, collectSymbolInformation } from './document-symbol.js';
import { computeCallers, computeCallees } from './calls.js';
import { TypeScriptServiceConfiguration } from './utils/configuration.js';
import { TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration.js';
import { TypeScriptAutoFixProvider } from './features/fix-all.js';
import { TypeScriptInlayHintsProvider } from './features/inlay-hints.js';
import { SourceDefinitionCommand } from './features/source-definition.js';
Expand Down Expand Up @@ -78,31 +78,6 @@ export class LspServer {
return this._tspClient;
}

private findTypescriptVersion(): TypeScriptVersion | null {
const typescriptVersionProvider = new TypeScriptVersionProvider(this.options, this.logger);
// User-provided tsserver path.
const userSettingVersion = typescriptVersionProvider.getUserSettingVersion();
if (userSettingVersion) {
if (userSettingVersion.isValid) {
return userSettingVersion;
}
this.logger.logIgnoringVerbosity(LogLevel.Warning, `Typescript specified through --tsserver-path ignored due to invalid path "${userSettingVersion.path}"`);
}
// Workspace version.
if (this.workspaceRoot) {
const workspaceVersion = typescriptVersionProvider.getWorkspaceVersion([this.workspaceRoot]);
if (workspaceVersion) {
return workspaceVersion;
}
}
// Bundled version
const bundledVersion = typescriptVersionProvider.bundledVersion();
if (bundledVersion && bundledVersion.isValid) {
return bundledVersion;
}
return null;
}

async initialize(params: TypeScriptInitializeParams): Promise<lsp.InitializeResult> {
this.logger.log('initialize', params);
if (this._tspClient) {
Expand All @@ -125,11 +100,11 @@ export class LspServer {
pluginProbeLocations.push(plugin.location);
}

const typescriptVersion = this.findTypescriptVersion();
const typescriptVersion = this.findTypescriptVersion(tsserver?.path);
if (typescriptVersion) {
this.logger.logIgnoringVerbosity(LogLevel.Info, `Using Typescript version (${typescriptVersion.source}) ${typescriptVersion.versionString} from path "${typescriptVersion.tsServerPath}"`);
} else {
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.');
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.');
}

this.configurationManager.mergeTsPreferences(userInitializationOptions.preferences || {});
Expand Down Expand Up @@ -166,12 +141,13 @@ export class LspServer {
this.features,
this.logger,
);
const tsserverLogVerbosity = tsserver?.logVerbosity && TsServerLogLevel.fromString(tsserver?.logVerbosity);
this._tspClient = new TspClient({
lspClient: this.options.lspClient,
trace: Trace.fromString(tsserver?.trace || 'off'),
typescriptVersion,
logDirectoryProvider: new LogDirectoryProvider(this.getLogDirectoryPath(userInitializationOptions)),
logVerbosity: this.options.tsserverLogVerbosity,
logVerbosity: tsserverLogVerbosity ?? this.options.tsserverLogVerbosity,
disableAutomaticTypingAcquisition,
maxTsServerMemory,
npmLocation,
Expand Down Expand Up @@ -284,6 +260,31 @@ export class LspServer {
return initializeResult;
}

private findTypescriptVersion(userTsserverPath: string | undefined): TypeScriptVersion | null {
const typescriptVersionProvider = new TypeScriptVersionProvider(userTsserverPath || this.options.tsserverPath, this.logger);
// User-provided tsserver path.
const userSettingVersion = typescriptVersionProvider.getUserSettingVersion();
if (userSettingVersion) {
if (userSettingVersion.isValid) {
return userSettingVersion;
}
this.logger.logIgnoringVerbosity(LogLevel.Warning, `Typescript specified through user setting ignored due to invalid path "${userSettingVersion.path}"`);
}
// Workspace version.
if (this.workspaceRoot) {
const workspaceVersion = typescriptVersionProvider.getWorkspaceVersion([this.workspaceRoot]);
if (workspaceVersion) {
return workspaceVersion;
}
}
// Bundled version
const bundledVersion = typescriptVersionProvider.bundledVersion();
if (bundledVersion && bundledVersion.isValid) {
return bundledVersion;
}
return null;
}

private getLogDirectoryPath(initializationOptions: TypeScriptInitializationOptions): string | undefined {
if (initializationOptions.tsserver?.logDirectory) {
return initializationOptions.tsserver.logDirectory;
Expand Down
2 changes: 1 addition & 1 deletion src/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export async function createServer(options: TestLspServerOptions): Promise<TestL
lspClient,
tsserverLogVerbosity: TsServerLogLevel.Off,
};
const typescriptVersionProvider = new TypeScriptVersionProvider(serverOptions, logger);
const typescriptVersionProvider = new TypeScriptVersionProvider(serverOptions.tsserverPath, logger);
const bundled = typescriptVersionProvider.bundledVersion();
const server = new TestLspServer({
...serverOptions,
Expand Down
15 changes: 14 additions & 1 deletion src/ts-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,26 @@ export interface TypeScriptInitializationOptions {

interface TsserverOptions {
/**
* The path to the directory where the `tsserver` logs will be created.
* The path to the directory where the `tsserver` log files will be created.
* If not provided, the log files will be created within the workspace, inside the `.log` directory.
* If no workspace root is provided when initializating the server and no custom path is specified then
* the logs will not be created.
* @default undefined
*/
logDirectory?: string;
/**
* Verbosity of the information logged into the `tsserver` log files.
*
* Log levels from least to most amount of details: `'terse'`, `'normal'`, `'requestTime`', `'verbose'`.
* Enabling particular level also enables all lower levels.
*
* @default 'off'
*/
logVerbosity?: 'off' | 'terse' | 'normal' | 'requestTime' | 'verbose';
/**
* The path to the `tsserver.js` file or the typescript lib directory. For example: `/Users/me/typescript/lib/tsserver.js`.
*/
path?: string;
/**
* The verbosity of logging the tsserver communication through the LSP messages.
* This doesn't affect the file logging.
Expand Down
12 changes: 5 additions & 7 deletions src/tsServer/versionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import path from 'node:path';
import which from 'which';
import { pkgUpSync } from 'pkg-up';
import API from '../utils/api.js';
import type { TypeScriptServiceConfiguration } from '../utils/configuration.js';
import { findPathToModule } from '../utils/modules-resolver.js';
import type { Logger } from '../utils/logger.js';

Expand Down Expand Up @@ -103,18 +102,17 @@ export class TypeScriptVersion {
export const MODULE_FOLDERS = ['node_modules/typescript/lib', '.vscode/pnpify/typescript/lib', '.yarn/sdks/typescript/lib'];

export class TypeScriptVersionProvider {
public constructor(private configuration: TypeScriptServiceConfiguration, private logger: Logger) {}
public constructor(private userTsserverPath: string | undefined, private logger: Logger) {}

public getUserSettingVersion(): TypeScriptVersion | null {
const { tsserverPath } = this.configuration;
if (!tsserverPath) {
if (!this.userTsserverPath) {
return null;
}
this.logger.log(`Resolving user-provided tsserver path "${tsserverPath}"...`);
let resolvedPath = tsserverPath;
this.logger.log(`Resolving user-provided tsserver path "${this.userTsserverPath}"...`);
let resolvedPath = this.userTsserverPath;
// Resolve full path to the binary if path is not absolute.
if (!path.isAbsolute(resolvedPath)) {
const binaryPath = which.sync(tsserverPath, { nothrow:true });
const binaryPath = which.sync(resolvedPath, { nothrow:true });
if (binaryPath) {
resolvedPath = binaryPath;
}
Expand Down
2 changes: 1 addition & 1 deletion src/tsp-client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const configuration: TypeScriptServiceConfiguration = {
lspClient,
tsserverLogVerbosity: TsServerLogLevel.Off,
};
const typescriptVersionProvider = new TypeScriptVersionProvider(configuration, logger);
const typescriptVersionProvider = new TypeScriptVersionProvider(configuration.tsserverPath, logger);
const bundled = typescriptVersionProvider.bundledVersion();
let server: TspClient;

Expand Down
3 changes: 3 additions & 0 deletions src/utils/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export enum TsServerLogLevel {
Off,
Normal,
Terse,
RequestTime,
Verbose,
}

Expand All @@ -24,6 +25,8 @@ export namespace TsServerLogLevel {
return TsServerLogLevel.Normal;
case 'terse':
return TsServerLogLevel.Terse;
case 'requestTime':
return TsServerLogLevel.RequestTime;
case 'verbose':
return TsServerLogLevel.Verbose;
case 'off':
Expand Down

0 comments on commit a03eab5

Please sign in to comment.