Anton Gilgur d32cf839fa
refactor: simplify hosts to directly assign tsModule.sys where possible (#349)
- no need to duplicate types this way, which can and have changed over
  time -- it's always the same typings this way

- also reorganize `host.ts` to have similar categories of functions near
  each other, instead of a mix of functions wherever
  - similar to how I organized the tests for `host` as well
- shrink the code a bit this way too

- add a comment about `getDefaultLibFileName`'s confusing naming
  pointing to the TS issues about how this is an old mistake but
  changing it now would be breaking

- this is also how the TS Wiki recommends setting up hosts: https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#incremental-build-support-using-the-language-services
  - NOTE: because of how `tsproxy` works to support alternate TS
    implementations, this does require that `tsModule` _exists_ at the
    time of instantiation, i.e. that `setTypescriptModule` has already
    been called
    - for `host.ts`, `LanguageServiceHost` is only instantiated after
      `setTypescriptModule`, but for `diagnostics-format-host.ts`, it is
      immediately instantiated (at the bottom of the file), hence why
      `getCurrentDirectory` can't just be assigned to `tsModule.sys`
      - there is a way to fix this, but the refactoring is more complex
        as it would require creating in `index.ts` and then passing it
        as an argument -- would want to refactor more at that point too,
        so leaving that out for now in this otherwise small, isolated
        refactor
  - for a different, but related reason, the `host.trace` tests have to
    mock `console` instead of just `console.log`, since `trace` would
    just be set to the old, unmocked `console.log` otherwise
    - as it's assigned directly to `console.log` now
2022-06-06 18:24:20 -06:00

110 lines
3.4 KiB
TypeScript

import * as tsTypes from "typescript";
import { normalizePath as normalize } from "@rollup/pluginutils";
import { tsModule } from "./tsproxy";
import { TransformerFactoryCreator } from "./ioptions";
export class LanguageServiceHost implements tsTypes.LanguageServiceHost
{
private snapshots: { [fileName: string]: tsTypes.IScriptSnapshot } = {};
private versions: { [fileName: string]: number } = {};
private service?: tsTypes.LanguageService;
private fileNames: Set<string>;
constructor(private parsedConfig: tsTypes.ParsedCommandLine, private transformers: TransformerFactoryCreator[], private cwd: string)
{
this.fileNames = new Set(parsedConfig.fileNames);
}
public reset()
{
this.snapshots = {};
this.versions = {};
}
public setLanguageService(service: tsTypes.LanguageService)
{
this.service = service;
}
public setSnapshot(fileName: string, data: string): tsTypes.IScriptSnapshot
{
fileName = normalize(fileName);
const snapshot = tsModule.ScriptSnapshot.fromString(data);
this.snapshots[fileName] = snapshot;
this.versions[fileName] = (this.versions[fileName] || 0) + 1;
this.fileNames.add(fileName);
return snapshot;
}
public getScriptSnapshot(fileName: string): tsTypes.IScriptSnapshot | undefined
{
fileName = normalize(fileName);
if (fileName in this.snapshots)
return this.snapshots[fileName];
const source = tsModule.sys.readFile(fileName);
if (source)
{
this.snapshots[fileName] = tsModule.ScriptSnapshot.fromString(source);
this.versions[fileName] = (this.versions[fileName] || 0) + 1;
return this.snapshots[fileName];
}
return undefined;
}
public getScriptFileNames = () => Array.from(this.fileNames.values());
public getScriptVersion(fileName: string)
{
fileName = normalize(fileName);
return (this.versions[fileName] || 0).toString();
}
public getCustomTransformers(): tsTypes.CustomTransformers | undefined
{
if (this.service === undefined || this.transformers === undefined || this.transformers.length === 0)
return undefined;
const transformer: tsTypes.CustomTransformers =
{
before: [],
after: [],
afterDeclarations: [],
};
for (const creator of this.transformers)
{
const factory = creator(this.service);
if (factory.before)
transformer.before = transformer.before!.concat(factory.before);
if (factory.after)
transformer.after = transformer.after!.concat(factory.after);
if (factory.afterDeclarations)
transformer.afterDeclarations = transformer.afterDeclarations!.concat(factory.afterDeclarations);
}
return transformer;
}
public getCompilationSettings = () => this.parsedConfig.options;
public getTypeRootsVersion = () => 0;
public getCurrentDirectory = () => this.cwd;
public useCaseSensitiveFileNames = () => tsModule.sys.useCaseSensitiveFileNames;
public getDefaultLibFileName = tsModule.getDefaultLibFilePath; // confusing naming: https://github.com/microsoft/TypeScript/issues/35318
public readDirectory = tsModule.sys.readDirectory;
public readFile = tsModule.sys.readFile;
public fileExists = tsModule.sys.fileExists;
public directoryExists = tsModule.sys.directoryExists;
public getDirectories = tsModule.sys.getDirectories;
public realpath = tsModule.sys.realpath!; // this exists in the default implementation: https://github.com/microsoft/TypeScript/blob/ab2523bbe0352d4486f67b73473d2143ad64d03d/src/compiler/sys.ts#L1288
public trace = console.log;
}