Skip to content

Commit

Permalink
fix: remove hard dependency on typescript (#661)
Browse files Browse the repository at this point in the history
  • Loading branch information
rchl committed Jan 14, 2023
1 parent 5a39c1f commit 9a2e2c8
Show file tree
Hide file tree
Showing 32 changed files with 526 additions and 319 deletions.
38 changes: 18 additions & 20 deletions src/completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,22 @@ import { LspDocument } from './document.js';
import { toTextEdit, normalizePath } from './protocol-translation.js';
import { Commands } from './commands.js';
import { TspClient } from './tsp-client.js';
import { tslib, tsp, KindModifiers, SupportedFeatures, toSymbolDisplayPartKind } from './ts-protocol.js';
import { CommandTypes, KindModifiers, ScriptElementKind, SupportedFeatures, SymbolDisplayPartKind, toSymbolDisplayPartKind } from './ts-protocol.js';
import type { ts } from './ts-protocol.js';
import * as Previewer from './utils/previewer.js';
import { IFilePathToResourceConverter } from './utils/previewer.js';
import SnippetString from './utils/SnippetString.js';
import { Range, Position } from './utils/typeConverters.js';
import type { WorkspaceConfigurationCompletionOptions } from './configuration-manager.js';

import ScriptElementKind = tslib.ScriptElementKind;
import SymbolDisplayPartKind = tslib.SymbolDisplayPartKind;

interface ParameterListParts {
readonly parts: ReadonlyArray<tsp.SymbolDisplayPart>;
readonly parts: ReadonlyArray<ts.server.protocol.SymbolDisplayPart>;
readonly hasOptionalParameters: boolean;
}

export function asCompletionItem(
entry: tsp.CompletionEntry,
optionalReplacementSpan: tsp.TextSpan | undefined,
entry: ts.server.protocol.CompletionEntry,
optionalReplacementSpan: ts.server.protocol.TextSpan | undefined,
file: string, position: lsp.Position,
document: LspDocument,
filePathConverter: IFilePathToResourceConverter,
Expand Down Expand Up @@ -115,8 +113,8 @@ export function asCompletionItem(
}

function getRangeFromReplacementSpan(
replacementSpan: tsp.TextSpan | undefined,
optionalReplacementSpan: tsp.TextSpan | undefined,
replacementSpan: ts.server.protocol.TextSpan | undefined,
optionalReplacementSpan: ts.server.protocol.TextSpan | undefined,
position: lsp.Position,
document: LspDocument,
features: SupportedFeatures,
Expand Down Expand Up @@ -220,7 +218,7 @@ function asCommitCharacters(kind: ScriptElementKind): string[] | undefined {

export async function asResolvedCompletionItem(
item: lsp.CompletionItem,
details: tsp.CompletionEntryDetails,
details: ts.server.protocol.CompletionEntryDetails,
document: LspDocument | undefined,
client: TspClient,
filePathConverter: IFilePathToResourceConverter,
Expand Down Expand Up @@ -252,8 +250,8 @@ async function isValidFunctionCompletionContext(filepath: string, position: lsp.
// Workaround for https://github.com/Microsoft/TypeScript/issues/12677
// Don't complete function calls inside of destructive assigments or imports
try {
const args: tsp.FileLocationRequestArgs = Position.toFileLocationRequestArgs(filepath, position);
const response = await client.request(tsp.CommandTypes.Quickinfo, args);
const args: ts.server.protocol.FileLocationRequestArgs = Position.toFileLocationRequestArgs(filepath, position);
const response = await client.request(CommandTypes.Quickinfo, args);
if (response.type === 'response' && response.body) {
switch (response.body.kind) {
case 'var':
Expand All @@ -277,7 +275,7 @@ function canCreateSnippetOfFunctionCall(kind: lsp.CompletionItemKind | undefined
return options.completeFunctionCalls === true && (kind === lsp.CompletionItemKind.Function || kind === lsp.CompletionItemKind.Method);
}

function createSnippetOfFunctionCall(item: lsp.CompletionItem, detail: tsp.CompletionEntryDetails): void {
function createSnippetOfFunctionCall(item: lsp.CompletionItem, detail: ts.server.protocol.CompletionEntryDetails): void {
const { displayParts } = detail;
const parameterListParts = getParameterListParts(displayParts);
const snippet = new SnippetString();
Expand All @@ -295,8 +293,8 @@ function createSnippetOfFunctionCall(item: lsp.CompletionItem, detail: tsp.Compl
}
}

function getParameterListParts(displayParts: ReadonlyArray<tsp.SymbolDisplayPart>): ParameterListParts {
const parts: tsp.SymbolDisplayPart[] = [];
function getParameterListParts(displayParts: ReadonlyArray<ts.server.protocol.SymbolDisplayPart>): ParameterListParts {
const parts: ts.server.protocol.SymbolDisplayPart[] = [];
let isInMethod = false;
let hasOptionalParameters = false;
let parenCount = 0;
Expand Down Expand Up @@ -352,7 +350,7 @@ function getParameterListParts(displayParts: ReadonlyArray<tsp.SymbolDisplayPart
return { hasOptionalParameters, parts };
}

function appendJoinedPlaceholders(snippet: SnippetString, parts: ReadonlyArray<tsp.SymbolDisplayPart>, joiner: string): void {
function appendJoinedPlaceholders(snippet: SnippetString, parts: ReadonlyArray<ts.server.protocol.SymbolDisplayPart>, joiner: string): void {
for (let i = 0; i < parts.length; ++i) {
const paramterPart = parts[i];
snippet.appendPlaceholder(paramterPart.text);
Expand All @@ -362,7 +360,7 @@ function appendJoinedPlaceholders(snippet: SnippetString, parts: ReadonlyArray<t
}
}

function asAdditionalTextEdits(codeActions: tsp.CodeAction[], filepath: string): lsp.TextEdit[] | undefined {
function asAdditionalTextEdits(codeActions: ts.server.protocol.CodeAction[], filepath: string): lsp.TextEdit[] | undefined {
// Try to extract out the additionalTextEdits for the current file.
const additionalTextEdits: lsp.TextEdit[] = [];
for (const tsAction of codeActions) {
Expand All @@ -380,7 +378,7 @@ function asAdditionalTextEdits(codeActions: tsp.CodeAction[], filepath: string):
return additionalTextEdits.length ? additionalTextEdits : undefined;
}

function asCommand(codeActions: tsp.CodeAction[], filepath: string): lsp.Command | undefined {
function asCommand(codeActions: ts.server.protocol.CodeAction[], filepath: string): lsp.Command | undefined {
let hasRemainingCommandsOrEdits = false;
for (const tsAction of codeActions) {
if (tsAction.commands) {
Expand Down Expand Up @@ -413,7 +411,7 @@ function asCommand(codeActions: tsp.CodeAction[], filepath: string): lsp.Command
}

function asDetail(
{ displayParts, sourceDisplay, source: deprecatedSource }: tsp.CompletionEntryDetails,
{ displayParts, sourceDisplay, source: deprecatedSource }: ts.server.protocol.CompletionEntryDetails,
filePathConverter: IFilePathToResourceConverter,
): string | undefined {
const result: string[] = [];
Expand All @@ -428,7 +426,7 @@ function asDetail(
return result.join('\n');
}

export function getCompletionTriggerCharacter(character: string | undefined): tsp.CompletionsTriggerCharacter | undefined {
export function getCompletionTriggerCharacter(character: string | undefined): ts.server.protocol.CompletionsTriggerCharacter | undefined {
switch (character) {
case '@':
case '#':
Expand Down
37 changes: 19 additions & 18 deletions src/configuration-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import deepmerge from 'deepmerge';
import path from 'node:path';
import type * as lsp from 'vscode-languageserver';
import { LspDocuments } from './document.js';
import { tsp, TypeScriptInitializationOptions } from './ts-protocol.js';
import { CommandTypes, ModuleKind, ScriptTarget, TypeScriptInitializationOptions } from './ts-protocol.js';
import type { ts } from './ts-protocol.js';
import type { TspClient } from './tsp-client.js';
import API from './utils/api.js';

const DEFAULT_TSSERVER_PREFERENCES: Required<tsp.UserPreferences> = {
const DEFAULT_TSSERVER_PREFERENCES: Required<ts.server.protocol.UserPreferences> = {
allowIncompleteCompletions: true,
allowRenameOfImportPath: true,
allowTextChangesInNewFiles: true,
Expand Down Expand Up @@ -44,10 +45,10 @@ const DEFAULT_TSSERVER_PREFERENCES: Required<tsp.UserPreferences> = {
const DEFAULT_IMPLICIT_PROJECT_CONFIGURATION: Required<WorkspaceConfigurationImplicitProjectConfigurationOptions> = {
checkJs: false,
experimentalDecorators: false,
module: tsp.ModuleKind.ESNext,
module: ModuleKind.ESNext,
strictFunctionTypes: true,
strictNullChecks: true,
target: tsp.ScriptTarget.ES2020,
target: ScriptTarget.ES2020,
};

const DEFAULT_WORKSPACE_CONFIGURATION: WorkspaceConfiguration = {
Expand All @@ -63,7 +64,7 @@ export interface WorkspaceConfiguration {
}

export interface WorkspaceConfigurationLanguageOptions {
format?: tsp.FormatCodeSettings;
format?: ts.server.protocol.FormatCodeSettings;
inlayHints?: TypeScriptInlayHintsPreferences;
}

Expand All @@ -78,7 +79,7 @@ export interface WorkspaceConfigurationImplicitProjectConfigurationOptions {

/* eslint-disable @typescript-eslint/indent */
export type TypeScriptInlayHintsPreferences = Pick<
tsp.UserPreferences,
ts.server.protocol.UserPreferences,
'includeInlayParameterNameHints' |
'includeInlayParameterNameHintsWhenArgumentMatchesName' |
'includeInlayFunctionParameterTypeHints' |
Expand All @@ -99,13 +100,13 @@ export interface WorkspaceConfigurationCompletionOptions {
}

export class ConfigurationManager {
public tsPreferences: Required<tsp.UserPreferences> = deepmerge({}, DEFAULT_TSSERVER_PREFERENCES);
public tsPreferences: Required<ts.server.protocol.UserPreferences> = deepmerge({}, DEFAULT_TSSERVER_PREFERENCES);
public workspaceConfiguration: WorkspaceConfiguration = deepmerge({}, DEFAULT_WORKSPACE_CONFIGURATION);
private tspClient: TspClient | null = null;

constructor(private readonly documents: LspDocuments) {}

public mergeTsPreferences(preferences: tsp.UserPreferences): void {
public mergeTsPreferences(preferences: ts.server.protocol.UserPreferences): void {
this.tsPreferences = deepmerge(this.tsPreferences, preferences);
}

Expand All @@ -115,36 +116,36 @@ export class ConfigurationManager {

public setAndConfigureTspClient(workspaceFolder: string | undefined, client: TspClient, hostInfo?: TypeScriptInitializationOptions['hostInfo']): void {
this.tspClient = client;
const formatOptions: tsp.FormatCodeSettings = {
const formatOptions: ts.server.protocol.FormatCodeSettings = {
// We can use \n here since the editor should normalize later on to its line endings.
newLineCharacter: '\n',
};
const args: tsp.ConfigureRequestArguments = {
const args: ts.server.protocol.ConfigureRequestArguments = {
...hostInfo ? { hostInfo } : {},
formatOptions,
preferences: {
...this.tsPreferences,
autoImportFileExcludePatterns: this.getAutoImportFileExcludePatternsPreference(workspaceFolder),
},
};
client.executeWithoutWaitingForResponse(tsp.CommandTypes.Configure, args);
client.executeWithoutWaitingForResponse(CommandTypes.Configure, args);
}

public async configureGloballyFromDocument(filename: string, formattingOptions?: lsp.FormattingOptions): Promise<void> {
const args: tsp.ConfigureRequestArguments = {
const args: ts.server.protocol.ConfigureRequestArguments = {
formatOptions: this.getFormattingOptions(filename, formattingOptions),
preferences: this.getPreferences(filename),
};
await this.tspClient?.request(tsp.CommandTypes.Configure, args);
await this.tspClient?.request(CommandTypes.Configure, args);
}

public getPreferences(filename: string): tsp.UserPreferences {
public getPreferences(filename: string): ts.server.protocol.UserPreferences {
if (this.tspClient?.apiVersion.lt(API.v290)) {
return {};
}

const workspacePreferences = this.getWorkspacePreferencesForFile(filename);
const preferences = Object.assign<tsp.UserPreferences, tsp.UserPreferences, tsp.UserPreferences>(
const preferences = Object.assign<ts.server.protocol.UserPreferences, ts.server.protocol.UserPreferences, ts.server.protocol.UserPreferences>(
{},
this.tsPreferences,
workspacePreferences?.inlayHints || {},
Expand All @@ -156,10 +157,10 @@ export class ConfigurationManager {
};
}

private getFormattingOptions(filename: string, formattingOptions?: lsp.FormattingOptions): tsp.FormatCodeSettings {
private getFormattingOptions(filename: string, formattingOptions?: lsp.FormattingOptions): ts.server.protocol.FormatCodeSettings {
const workspacePreferences = this.getWorkspacePreferencesForFile(filename);

const opts: tsp.FormatCodeSettings = {
const opts: ts.server.protocol.FormatCodeSettings = {
...workspacePreferences?.format,
...formattingOptions,
};
Expand All @@ -174,7 +175,7 @@ export class ConfigurationManager {
return opts;
}

private getQuoteStylePreference(preferences: tsp.UserPreferences) {
private getQuoteStylePreference(preferences: ts.server.protocol.UserPreferences) {
switch (preferences.quotePreference) {
case 'single': return 'single';
case 'double': return 'double';
Expand Down
11 changes: 6 additions & 5 deletions src/diagnostic-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import * as lsp from 'vscode-languageserver';
import debounce from 'p-debounce';
import { Logger } from './utils/logger.js';
import { pathToUri, toDiagnostic } from './protocol-translation.js';
import type { tsp, EventTypes } from './ts-protocol.js';
import { EventTypes } from './ts-protocol.js';
import type { ts } from './ts-protocol.js';
import { LspDocuments } from './document.js';
import { SupportedFeatures } from './ts-protocol.js';

class FileDiagnostics {
private readonly diagnosticsPerKind = new Map<EventTypes, tsp.Diagnostic[]>();
private readonly diagnosticsPerKind = new Map<EventTypes, ts.server.protocol.Diagnostic[]>();

constructor(
protected readonly uri: string,
Expand All @@ -23,7 +24,7 @@ class FileDiagnostics {
protected readonly features: SupportedFeatures,
) { }

update(kind: EventTypes, diagnostics: tsp.Diagnostic[]): void {
update(kind: EventTypes, diagnostics: ts.server.protocol.Diagnostic[]): void {
this.diagnosticsPerKind.set(kind, diagnostics);
this.firePublishDiagnostics();
}
Expand Down Expand Up @@ -54,7 +55,7 @@ export class DiagnosticEventQueue {
protected readonly logger: Logger,
) { }

updateDiagnostics(kind: EventTypes, event: tsp.DiagnosticEvent): void {
updateDiagnostics(kind: EventTypes, event: ts.server.protocol.DiagnosticEvent): void {
if (!event.body) {
this.logger.error(`Received empty ${event.event} diagnostics.`);
return;
Expand All @@ -81,7 +82,7 @@ export class DiagnosticEventQueue {
return this.diagnostics.get(uri)?.getDiagnostics() || [];
}

private isDiagnosticIgnored(diagnostic: tsp.Diagnostic) : boolean {
private isDiagnosticIgnored(diagnostic: ts.server.protocol.Diagnostic) : boolean {
return diagnostic.code !== undefined && this.ignoredDiagnosticCodes.has(diagnostic.code);
}
}
13 changes: 7 additions & 6 deletions src/document-symbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@

import * as lsp from 'vscode-languageserver';
import { toSymbolKind } from './protocol-translation.js';
import { tslib, tsp } from './ts-protocol.js';
import { ScriptElementKind } from './ts-protocol.js';
import type { ts } from './ts-protocol.js';
import { Range } from './utils/typeConverters.js';

export function collectDocumentSymbols(parent: tsp.NavigationTree, symbols: lsp.DocumentSymbol[]): boolean {
export function collectDocumentSymbols(parent: ts.server.protocol.NavigationTree, symbols: lsp.DocumentSymbol[]): boolean {
return collectDocumentSymbolsInRange(parent, symbols, { start: Range.fromTextSpan(parent.spans[0]).start, end: Range.fromTextSpan(parent.spans[parent.spans.length - 1]).end });
}

function collectDocumentSymbolsInRange(parent: tsp.NavigationTree, symbols: lsp.DocumentSymbol[], range: lsp.Range): boolean {
function collectDocumentSymbolsInRange(parent: ts.server.protocol.NavigationTree, symbols: lsp.DocumentSymbol[], range: lsp.Range): boolean {
let shouldInclude = shouldIncludeEntry(parent);

for (const span of parent.spans) {
Expand Down Expand Up @@ -55,7 +56,7 @@ function collectDocumentSymbolsInRange(parent: tsp.NavigationTree, symbols: lsp.
return shouldInclude;
}

export function collectSymbolInformation(uri: string, current: tsp.NavigationTree, symbols: lsp.SymbolInformation[], containerName?: string): boolean {
export function collectSymbolInformation(uri: string, current: ts.server.protocol.NavigationTree, symbols: lsp.SymbolInformation[], containerName?: string): boolean {
let shouldInclude = shouldIncludeEntry(current);
const name = current.text;
for (const span of current.spans) {
Expand Down Expand Up @@ -86,8 +87,8 @@ export function collectSymbolInformation(uri: string, current: tsp.NavigationTre
return shouldInclude;
}

export function shouldIncludeEntry(item: tsp.NavigationTree | tsp.NavigationBarItem): boolean {
if (item.kind === tslib.ScriptElementKind.alias) {
export function shouldIncludeEntry(item: ts.server.protocol.NavigationTree | ts.server.protocol.NavigationBarItem): boolean {
if (item.kind === ScriptElementKind.alias) {
return false;
}
return !!(item.text && item.text !== '<function>' && item.text !== '<class>');
Expand Down
4 changes: 2 additions & 2 deletions src/features/call-hierarchy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import * as chai from 'chai';
import * as lsp from 'vscode-languageserver';
import { uri, createServer, TestLspServer, positionAfter, documentFromFile } from './../test-utils.js';
import { uri, createServer, TestLspServer, positionAfter, documentFromFile } from '../test-utils.js';

const assert = chai.assert;

Expand Down Expand Up @@ -68,7 +68,7 @@ after(() => {
server.shutdown();
});

describe.only('call hierarchy', () => {
describe('call hierarchy', () => {
const oneDoc = documentFromFile({ path: 'call-hierarchy/one.ts' });
const twoDoc = documentFromFile({ path: 'call-hierarchy/two.ts' });
const threeDoc = documentFromFile({ path: 'call-hierarchy/three.ts' });
Expand Down

0 comments on commit 9a2e2c8

Please sign in to comment.