UNPKG

javascript-typescript-langserver

Version:

Implementation of the Language Server Protocol for JavaScript and TypeScript

421 lines (420 loc) 16.8 kB
import { Span } from 'opentracing'; import { Observable } from 'rxjs'; import * as ts from 'typescript'; import { Disposable } from './disposable'; import { FileSystemUpdater } from './fs'; import { Logger } from './logging'; import { InMemoryFileSystem } from './memfs'; import { PluginSettings } from './request-type'; /** * Implementaton of LanguageServiceHost that works with in-memory file system. * It takes file content from local cache and provides it to TS compiler on demand * * @implements ts.LanguageServiceHost */ export declare class InMemoryLanguageServiceHost implements ts.LanguageServiceHost { private logger; complete: boolean; /** * Root path */ private rootPath; /** * Compiler options to use when parsing/analyzing source files. * We are extracting them from tsconfig.json or jsconfig.json */ private options; /** * Local file cache where we looking for file content */ private fs; /** * Current list of files that were implicitly added to project * (every time when we need to extract data from a file that we haven't touched yet). * Each item is a relative file path */ private filePaths; /** * Current project version. When something significant is changed, incrementing it to signal TS compiler that * files should be updated and cached data should be invalidated */ private projectVersion; /** * Tracks individual files versions to invalidate TS compiler data when single file is changed. Keys are URIs */ private versions; constructor(rootPath: string, options: ts.CompilerOptions, fs: InMemoryFileSystem, versions: Map<string, number>, logger?: Logger); /** * TypeScript uses this method (when present) to compare project's version * with the last known one to decide if internal data should be synchronized */ getProjectVersion(): string; getNewLine(): string; /** * Incrementing current project version, telling TS compiler to invalidate internal data */ incProjectVersion(): void; getCompilationSettings(): ts.CompilerOptions; getScriptFileNames(): string[]; /** * Adds a file and increments project version, used in conjunction with getProjectVersion() * which may be called by TypeScript to check if internal data is up to date * * @param filePath relative file path */ addFile(filePath: string): void; /** * @param fileName absolute file path */ getScriptVersion(filePath: string): string; /** * @param filePath absolute file path */ getScriptSnapshot(filePath: string): ts.IScriptSnapshot | undefined; getCurrentDirectory(): string; getDefaultLibFileName(options: ts.CompilerOptions): string; trace(message: string): void; log(message: string): void; error(message: string): void; readFile(path: string, encoding?: string): string; fileExists(path: string): boolean; } /** * ProjectConfiguration instances track the compiler configuration (as * defined by {tj}sconfig.json if it exists) and state for a single * TypeScript project. It represents the world of the view as * presented to the compiler. * * For efficiency, a ProjectConfiguration instance may hide some files * from the compiler, preventing them from being parsed and * type-checked. Depending on the use, the caller should call one of * the ensure* methods to ensure that the appropriate files have been * made available to the compiler before calling any other methods on * the ProjectConfiguration or its public members. By default, no * files are parsed. * * Windows file paths are converted to UNIX-style forward slashes * when compared with Typescript configuration (isGlobalTSFile, * expectedFilePaths and typeRoots) */ export declare class ProjectConfiguration { private documentRegistry; private pluginSettings?; private logger; private service?; /** * Object TS service will use to fetch content of source files */ private host?; /** * Local file cache */ private fs; /** * Relative path to configuration file (tsconfig.json/jsconfig.json) */ configFilePath: string; /** * Configuration JSON object. May be used when there is no real configuration file to parse and use */ private configContent; /** * Relative source file path (relative) -> version associations */ private versions; /** * Enables module resolution tracing (done by TS service) */ private traceModuleResolution; /** * Root file path, relative to workspace hierarchy root */ private rootFilePath; /** * List of files that project consist of (based on tsconfig includes/excludes and wildcards). * Each item is a relative UNIX-like file path */ private expectedFilePaths; /** * List of resolved extra root directories to allow global type declaration files to be loaded from. * Each item is an absolute UNIX-like file path */ private typeRoots; private initialized; private ensuredAllFiles; private ensuredBasicFiles; /** * @param fs file system to use * @param documentRegistry Shared DocumentRegistry that manages SourceFile objects * @param rootFilePath root file path, absolute * @param configFilePath configuration file path, absolute * @param configContent optional configuration content to use instead of reading configuration file) */ constructor(fs: InMemoryFileSystem, documentRegistry: ts.DocumentRegistry, rootFilePath: string, versions: Map<string, number>, configFilePath: string, configContent?: any, traceModuleResolution?: boolean, pluginSettings?: PluginSettings | undefined, logger?: Logger); /** * reset resets a ProjectConfiguration to its state immediately * after construction. It should be called whenever the underlying * local filesystem (fs) has changed, and so the * ProjectConfiguration can no longer assume its state reflects * that of the underlying files. */ reset(): void; /** * @return language service object */ getService(): ts.LanguageService; /** * Tells TS service to recompile program (if needed) based on current list of files and compilation options. * TS service relies on information provided by language servide host to see if there were any changes in * the whole project or in some files * * @return program object (cached result of parsing and typechecking done by TS service) */ getProgram(childOf?: Span): ts.Program | undefined; /** * @return language service host that TS service uses to read the data */ getHost(): InMemoryLanguageServiceHost; /** * Initializes (sub)project by parsing configuration and making proper internal objects */ private init; /** * Replaces the LanguageService with an instance wrapped by the plugin * @param pluginModuleFactory function to create the module * @param configEntry extra settings from tsconfig to pass to the plugin module */ private wrapService; /** * Ensures we are ready to process files from a given sub-project */ ensureConfigFile(span?: Span): void; /** * Determines if a fileName is a declaration file within expected files or type roots * @param fileName A Unix-like absolute file path. */ isExpectedDeclarationFile(fileName: string): boolean; /** * Ensures we added basic files (global TS files, dependencies, declarations) */ ensureBasicFiles(span?: Span): void; /** * Ensures a single file is available to the LanguageServiceHost * @param filePath */ ensureSourceFile(filePath: string, span?: Span): void; /** * Ensures we added all project's source file (as were defined in tsconfig.json) */ ensureAllFiles(span?: Span): void; } export declare type ConfigType = 'js' | 'ts'; /** * ProjectManager translates VFS files to one or many projects denoted by [tj]config.json. * It uses either local or remote file system to fetch directory tree and files from and then * makes one or more LanguageService objects. By default all LanguageService objects contain no files, * they are added on demand - current file for hover or definition, project's files for references and * all files from all projects for workspace symbols. * * ProjectManager preserves Windows paths until passed to ProjectConfiguration or TS APIs. */ export declare class ProjectManager implements Disposable { protected logger: Logger; /** * Root path with slashes */ private rootPath; /** * (Workspace subtree (folder) -> TS or JS configuration) mapping. * Configuration settings for a source file A are located in the closest parent folder of A. * Map keys are relative (to workspace root) paths */ private configs; /** * Local side of file content provider which keeps cache of fetched files */ private inMemoryFs; /** * File system updater that takes care of updating the in-memory file system */ private updater; /** * URI -> version map. Every time file content is about to change or changed (didChange/didOpen/...), we are incrementing it's version * signalling that file is changed and file's user must invalidate cached and requery file content */ private versions; /** * Enables module resolution tracing by TS compiler */ private traceModuleResolution; /** * Flag indicating that we fetched module struture (tsconfig.json, jsconfig.json, package.json files) from the remote file system. * Without having this information we won't be able to split workspace to sub-projects */ private ensuredModuleStructure?; /** * Observable that completes when extra dependencies pointed to by tsconfig.json have been loaded. */ private ensuredConfigDependencies?; /** * Observable that completes when `ensureAllFiles` completed */ private ensuredAllFiles?; /** * Observable that completes when `ensureOwnFiles` completed */ private ensuredOwnFiles?; /** * A URI Map from file to files referenced by the file, so files only need to be pre-processed once */ private referencedFiles; /** * Tracks all Subscriptions that are done in the lifetime of this object to dispose on `dispose()` */ private subscriptions; /** * Options passed to the language server at startup */ private pluginSettings?; /** * @param rootPath root path as passed to `initialize` * @param inMemoryFileSystem File system that keeps structure and contents in memory * @param strict indicates if we are working in strict mode (VFS) or with a local file system * @param traceModuleResolution allows to enable module resolution tracing (done by TS compiler) */ constructor(rootPath: string, inMemoryFileSystem: InMemoryFileSystem, updater: FileSystemUpdater, traceModuleResolution?: boolean, pluginSettings?: PluginSettings, logger?: Logger); /** * Disposes the object (removes all registered listeners) */ dispose(): void; /** * @return root path (as passed to `initialize`) */ getRemoteRoot(): string; /** * @return local side of file content provider which keeps cached copies of fethed files */ getFs(): InMemoryFileSystem; /** * @param filePath file path (both absolute or relative file paths are accepted) * @return true if there is a fetched file with a given path */ hasFile(filePath: string): boolean; /** * @return all sub-projects we have identified for a given workspace. * Sub-project is mainly a folder which contains tsconfig.json, jsconfig.json, package.json, * or a root folder which serves as a fallback */ configurations(): IterableIterator<ProjectConfiguration>; /** * Ensures that the module structure of the project exists in memory. * TypeScript/JavaScript module structure is determined by [jt]sconfig.json, * filesystem layout, global*.d.ts and package.json files. * Then creates new ProjectConfigurations, resets existing and invalidates file references. */ ensureModuleStructure(childOf?: Span): Observable<never>; /** * Invalidates caches for `ensureModuleStructure`, `ensureAllFiles` and `insureOwnFiles` */ invalidateModuleStructure(): void; /** * Ensures all files not in node_modules were fetched. * This includes all js/ts files, tsconfig files and package.json files. * Invalidates project configurations after execution */ ensureOwnFiles(childOf?: Span): Observable<never>; /** * Ensures all files were fetched from the remote file system. * Invalidates project configurations after execution */ ensureAllFiles(childOf?: Span): Observable<never>; /** * Recursively collects file(s) dependencies up to given level. * Dependencies are extracted by TS compiler from import and reference statements * * Dependencies include: * - all the configuration files * - files referenced by the given file * - files included by the given file * * The return values of this method are not cached, but those of the file fetching and file processing are. * * @param uri File to process * @param maxDepth Stop collecting when reached given recursion level * @param ignore Tracks visited files to prevent cycles * @param childOf OpenTracing parent span for tracing * @return Observable of file URIs ensured */ ensureReferencedFiles(uri: string, maxDepth?: number, ignore?: Set<string>, childOf?: Span): Observable<string>; /** * Determines if a tsconfig/jsconfig needs additional declaration files loaded. * @param filePath A UNIX-like absolute file path */ isConfigDependency(filePath: string): boolean; /** * Loads files determined by tsconfig to be needed into the file system */ ensureConfigDependencies(childOf?: Span): Observable<never>; /** * Invalidates a cache entry for `resolveReferencedFiles` (e.g. because the file changed) * * @param uri The URI that referenced files should be invalidated for. If not given, all entries are invalidated */ invalidateReferencedFiles(uri?: string): void; /** * Returns the files that are referenced from a given file. * If the file has already been processed, returns a cached value. * * @param uri URI of the file to process * @return URIs of files referenced by the file */ private resolveReferencedFiles; /** * @param filePath source file path, absolute * @return project configuration for a given source file. Climbs directory tree up to workspace root if needed */ getConfiguration(filePath: string, configType?: ConfigType): ProjectConfiguration; /** * @param filePath source file path, absolute * @return closest configuration for a given file path or undefined if there is no such configuration */ getConfigurationIfExists(filePath: string, configType?: ConfigType): ProjectConfiguration | undefined; /** * Returns the ProjectConfiguration a file belongs to */ getParentConfiguration(uri: string, configType?: ConfigType): ProjectConfiguration | undefined; /** * Returns all ProjectConfigurations contained in the given directory or one of its childrens * * @param uri URI of a directory */ getChildConfigurations(uri: string): IterableIterator<ProjectConfiguration>; /** * Called when file was opened by client. Current implementation * does not differenciates open and change events * @param uri file's URI * @param text file's content */ didOpen(uri: string, text: string): void; /** * Called when file was closed by client. Current implementation invalidates compiled version * @param uri file's URI */ didClose(uri: string, span?: Span): void; /** * Called when file was changed by client. Current implementation invalidates compiled version * @param uri file's URI * @param text file's content */ didChange(uri: string, text: string, span?: Span): void; /** * Called when file was saved by client * @param uri file's URI */ didSave(uri: string): void; /** * @param filePath path to source (or config) file * @return configuration type to use for a given file */ private getConfigurationType; }