fix(language-service): [ivy] do not retrieve ts.Program at startup (#38120)
This commit removes compiler instantiation at startup. This is because the constructor is invoked during the plugin loading phase, in which the project has not been completely loaded. Retrieving `ts.Program` at startup will trigger an `updateGraph` operation, which could only be called after the Project has loaded completely. Without this change, the Ivy LS cannot be loaded as a tsserver plugin. Note that the whole `Compiler` class is temporary, so changes made there are only for development. Once we have proper integration with ngtsc the `Compiler` class would be removed. PR Close #38120
This commit is contained in:
parent
6f6102d8ad
commit
e8896b9de3
|
@ -17,44 +17,40 @@ import * as ts from 'typescript/lib/tsserverlibrary';
|
||||||
|
|
||||||
import {makeCompilerHostFromProject} from './compiler_host';
|
import {makeCompilerHostFromProject} from './compiler_host';
|
||||||
|
|
||||||
|
interface AnalysisResult {
|
||||||
|
compiler: NgCompiler;
|
||||||
|
program: ts.Program;
|
||||||
|
}
|
||||||
|
|
||||||
export class Compiler {
|
export class Compiler {
|
||||||
private tsCompilerHost: ts.CompilerHost;
|
private tsCompilerHost: ts.CompilerHost;
|
||||||
private lastKnownProgram: ts.Program;
|
private lastKnownProgram: ts.Program|null = null;
|
||||||
private compiler: NgCompiler;
|
|
||||||
private readonly strategy: TypeCheckingProgramStrategy;
|
private readonly strategy: TypeCheckingProgramStrategy;
|
||||||
|
|
||||||
constructor(private readonly project: ts.server.Project, private options: CompilerOptions) {
|
constructor(private readonly project: ts.server.Project, private options: CompilerOptions) {
|
||||||
this.tsCompilerHost = makeCompilerHostFromProject(project);
|
this.tsCompilerHost = makeCompilerHostFromProject(project);
|
||||||
const ngCompilerHost = NgCompilerHost.wrap(
|
|
||||||
this.tsCompilerHost,
|
|
||||||
project.getRootFiles(), // input files
|
|
||||||
options,
|
|
||||||
null, // old program
|
|
||||||
);
|
|
||||||
this.strategy = createTypeCheckingProgramStrategy(project);
|
this.strategy = createTypeCheckingProgramStrategy(project);
|
||||||
this.lastKnownProgram = this.strategy.getProgram();
|
// Do not retrieve the program in constructor because project is still in
|
||||||
this.compiler = new NgCompiler(
|
// the process of loading, and not all data members have been initialized.
|
||||||
ngCompilerHost, options, this.lastKnownProgram, this.strategy,
|
|
||||||
new PatchedProgramIncrementalBuildStrategy());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setCompilerOptions(options: CompilerOptions) {
|
setCompilerOptions(options: CompilerOptions) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
analyze(): ts.Program|undefined {
|
analyze(): AnalysisResult|undefined {
|
||||||
const inputFiles = this.project.getRootFiles();
|
const inputFiles = this.project.getRootFiles();
|
||||||
const ngCompilerHost =
|
const ngCompilerHost =
|
||||||
NgCompilerHost.wrap(this.tsCompilerHost, inputFiles, this.options, this.lastKnownProgram);
|
NgCompilerHost.wrap(this.tsCompilerHost, inputFiles, this.options, this.lastKnownProgram);
|
||||||
const program = this.strategy.getProgram();
|
const program = this.strategy.getProgram();
|
||||||
this.compiler = new NgCompiler(
|
const compiler = new NgCompiler(
|
||||||
ngCompilerHost, this.options, program, this.strategy,
|
ngCompilerHost, this.options, program, this.strategy,
|
||||||
new PatchedProgramIncrementalBuildStrategy(), this.lastKnownProgram);
|
new PatchedProgramIncrementalBuildStrategy(), this.lastKnownProgram);
|
||||||
try {
|
try {
|
||||||
// This is the only way to force the compiler to update the typecheck file
|
// This is the only way to force the compiler to update the typecheck file
|
||||||
// in the program. We have to do try-catch because the compiler immediately
|
// in the program. We have to do try-catch because the compiler immediately
|
||||||
// throws if it fails to parse any template in the entire program!
|
// throws if it fails to parse any template in the entire program!
|
||||||
const d = this.compiler.getDiagnostics();
|
const d = compiler.getDiagnostics();
|
||||||
if (d.length) {
|
if (d.length) {
|
||||||
// There could be global compilation errors. It's useful to print them
|
// There could be global compilation errors. It's useful to print them
|
||||||
// out in development.
|
// out in development.
|
||||||
|
@ -64,12 +60,11 @@ export class Compiler {
|
||||||
console.error('Failed to analyze program', e.message);
|
console.error('Failed to analyze program', e.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.lastKnownProgram = this.compiler.getNextProgram();
|
this.lastKnownProgram = compiler.getNextProgram();
|
||||||
return this.lastKnownProgram;
|
return {
|
||||||
}
|
compiler,
|
||||||
|
program: this.lastKnownProgram,
|
||||||
getDiagnostics(sourceFile: ts.SourceFile): ts.Diagnostic[] {
|
};
|
||||||
return this.compiler.getDiagnostics(sourceFile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,15 +21,16 @@ export class LanguageService {
|
||||||
}
|
}
|
||||||
|
|
||||||
getSemanticDiagnostics(fileName: string): ts.Diagnostic[] {
|
getSemanticDiagnostics(fileName: string): ts.Diagnostic[] {
|
||||||
const program = this.compiler.analyze();
|
const result = this.compiler.analyze();
|
||||||
if (!program) {
|
if (!result) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
const {compiler, program} = result;
|
||||||
const sourceFile = program.getSourceFile(fileName);
|
const sourceFile = program.getSourceFile(fileName);
|
||||||
if (!sourceFile) {
|
if (!sourceFile) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return this.compiler.getDiagnostics(sourceFile);
|
return compiler.getDiagnostics(sourceFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private watchConfigFile(project: ts.server.Project) {
|
private watchConfigFile(project: ts.server.Project) {
|
||||||
|
|
Loading…
Reference in New Issue