refactor(language-service): [Ivy] remove temporary compiler (#38310)
Now that Ivy compiler has a proper `TemplateTypeChecker` interface (see https://github.com/angular/angular/pull/38105) we no longer need to keep the temporary compiler implementation. The temporary compiler was created to enable testing infrastructure to be developed for the Ivy language service. This commit removes the whole `ivy/compiler` directory and moves two functions `createTypeCheckingProgramStrategy` and `getOrCreateTypeCheckScriptInfo` to the `LanguageService` class. Also re-enable the Ivy LS test since it's no longer blocking development. PR Close #38310
This commit is contained in:
		
							parent
							
								
									3b9c802dee
								
							
						
					
					
						commit
						cfe424e875
					
				| @ -7,7 +7,13 @@ ts_library( | |||||||
|     srcs = glob(["*.ts"]), |     srcs = glob(["*.ts"]), | ||||||
|     deps = [ |     deps = [ | ||||||
|         "//packages/compiler-cli", |         "//packages/compiler-cli", | ||||||
|         "//packages/language-service/ivy/compiler", |         "//packages/compiler-cli/src/ngtsc/core", | ||||||
|  |         "//packages/compiler-cli/src/ngtsc/core:api", | ||||||
|  |         "//packages/compiler-cli/src/ngtsc/file_system", | ||||||
|  |         "//packages/compiler-cli/src/ngtsc/incremental", | ||||||
|  |         "//packages/compiler-cli/src/ngtsc/shims", | ||||||
|  |         "//packages/compiler-cli/src/ngtsc/typecheck", | ||||||
|  |         "//packages/compiler-cli/src/ngtsc/typecheck/api", | ||||||
|         "@npm//typescript", |         "@npm//typescript", | ||||||
|     ], |     ], | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -1,17 +0,0 @@ | |||||||
| load("//tools:defaults.bzl", "ts_library") |  | ||||||
| 
 |  | ||||||
| package(default_visibility = ["//packages/language-service/ivy:__pkg__"]) |  | ||||||
| 
 |  | ||||||
| ts_library( |  | ||||||
|     name = "compiler", |  | ||||||
|     srcs = glob(["*.ts"]), |  | ||||||
|     deps = [ |  | ||||||
|         "//packages/compiler-cli", |  | ||||||
|         "//packages/compiler-cli/src/ngtsc/core", |  | ||||||
|         "//packages/compiler-cli/src/ngtsc/file_system", |  | ||||||
|         "//packages/compiler-cli/src/ngtsc/incremental", |  | ||||||
|         "//packages/compiler-cli/src/ngtsc/typecheck", |  | ||||||
|         "//packages/compiler-cli/src/ngtsc/typecheck/api", |  | ||||||
|         "@npm//typescript", |  | ||||||
|     ], |  | ||||||
| ) |  | ||||||
| @ -1,2 +0,0 @@ | |||||||
| All files in this directory are temporary. This is created to simulate the final |  | ||||||
| form of the Ivy compiler that supports language service. |  | ||||||
| @ -1,124 +0,0 @@ | |||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @license |  | ||||||
|  * Copyright Google LLC All Rights Reserved. |  | ||||||
|  * |  | ||||||
|  * Use of this source code is governed by an MIT-style license that can be |  | ||||||
|  * found in the LICENSE file at https://angular.io/license
 |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| import {CompilerOptions} from '@angular/compiler-cli'; |  | ||||||
| import {NgCompiler, NgCompilerHost} from '@angular/compiler-cli/src/ngtsc/core'; |  | ||||||
| import {absoluteFromSourceFile, AbsoluteFsPath} from '@angular/compiler-cli/src/ngtsc/file_system'; |  | ||||||
| import {PatchedProgramIncrementalBuildStrategy} from '@angular/compiler-cli/src/ngtsc/incremental'; |  | ||||||
| import {TypeCheckShimGenerator} from '@angular/compiler-cli/src/ngtsc/typecheck'; |  | ||||||
| import {TypeCheckingProgramStrategy, UpdateMode} from '@angular/compiler-cli/src/ngtsc/typecheck/api'; |  | ||||||
| import * as ts from 'typescript/lib/tsserverlibrary'; |  | ||||||
| 
 |  | ||||||
| import {makeCompilerHostFromProject} from './compiler_host'; |  | ||||||
| 
 |  | ||||||
| interface AnalysisResult { |  | ||||||
|   compiler: NgCompiler; |  | ||||||
|   program: ts.Program; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export class Compiler { |  | ||||||
|   private tsCompilerHost: ts.CompilerHost; |  | ||||||
|   private lastKnownProgram: ts.Program|null = null; |  | ||||||
|   private readonly strategy: TypeCheckingProgramStrategy; |  | ||||||
| 
 |  | ||||||
|   constructor(private readonly project: ts.server.Project, private options: CompilerOptions) { |  | ||||||
|     this.tsCompilerHost = makeCompilerHostFromProject(project); |  | ||||||
|     this.strategy = createTypeCheckingProgramStrategy(project); |  | ||||||
|     // Do not retrieve the program in constructor because project is still in
 |  | ||||||
|     // the process of loading, and not all data members have been initialized.
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   setCompilerOptions(options: CompilerOptions) { |  | ||||||
|     this.options = options; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   analyze(): AnalysisResult|undefined { |  | ||||||
|     const inputFiles = this.project.getRootFiles(); |  | ||||||
|     const ngCompilerHost = |  | ||||||
|         NgCompilerHost.wrap(this.tsCompilerHost, inputFiles, this.options, this.lastKnownProgram); |  | ||||||
|     const program = this.strategy.getProgram(); |  | ||||||
|     const compiler = new NgCompiler( |  | ||||||
|         ngCompilerHost, this.options, program, this.strategy, |  | ||||||
|         new PatchedProgramIncrementalBuildStrategy(), this.lastKnownProgram); |  | ||||||
|     try { |  | ||||||
|       // 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
 |  | ||||||
|       // throws if it fails to parse any template in the entire program!
 |  | ||||||
|       const d = compiler.getDiagnostics(); |  | ||||||
|       if (d.length) { |  | ||||||
|         // There could be global compilation errors. It's useful to print them
 |  | ||||||
|         // out in development.
 |  | ||||||
|         console.error(d.map(d => ts.flattenDiagnosticMessageText(d.messageText, '\n'))); |  | ||||||
|       } |  | ||||||
|     } catch (e) { |  | ||||||
|       console.error('Failed to analyze program', e.message); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     this.lastKnownProgram = compiler.getNextProgram(); |  | ||||||
|     return { |  | ||||||
|       compiler, |  | ||||||
|       program: this.lastKnownProgram, |  | ||||||
|     }; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function createTypeCheckingProgramStrategy(project: ts.server.Project): |  | ||||||
|     TypeCheckingProgramStrategy { |  | ||||||
|   return { |  | ||||||
|     supportsInlineOperations: false, |  | ||||||
|     shimPathForComponent(component: ts.ClassDeclaration): AbsoluteFsPath { |  | ||||||
|       return TypeCheckShimGenerator.shimFor(absoluteFromSourceFile(component.getSourceFile())); |  | ||||||
|     }, |  | ||||||
|     getProgram(): ts.Program { |  | ||||||
|       const program = project.getLanguageService().getProgram(); |  | ||||||
|       if (!program) { |  | ||||||
|         throw new Error('Language service does not have a program!'); |  | ||||||
|       } |  | ||||||
|       return program; |  | ||||||
|     }, |  | ||||||
|     updateFiles(contents: Map<AbsoluteFsPath, string>, updateMode: UpdateMode) { |  | ||||||
|       if (updateMode !== UpdateMode.Complete) { |  | ||||||
|         throw new Error(`Incremental update mode is currently not supported`); |  | ||||||
|       } |  | ||||||
|       for (const [fileName, newText] of contents) { |  | ||||||
|         const scriptInfo = getOrCreateTypeCheckScriptInfo(project, fileName); |  | ||||||
|         const snapshot = scriptInfo.getSnapshot(); |  | ||||||
|         const length = snapshot.getLength(); |  | ||||||
|         scriptInfo.editContent(0, length, newText); |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|   }; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function getOrCreateTypeCheckScriptInfo( |  | ||||||
|     project: ts.server.Project, tcf: string): ts.server.ScriptInfo { |  | ||||||
|   // First check if there is already a ScriptInfo for the tcf
 |  | ||||||
|   const {projectService} = project; |  | ||||||
|   let scriptInfo = projectService.getScriptInfo(tcf); |  | ||||||
|   if (!scriptInfo) { |  | ||||||
|     // ScriptInfo needs to be opened by client to be able to set its user-defined
 |  | ||||||
|     // content. We must also provide file content, otherwise the service will
 |  | ||||||
|     // attempt to fetch the content from disk and fail.
 |  | ||||||
|     scriptInfo = projectService.getOrCreateScriptInfoForNormalizedPath( |  | ||||||
|         ts.server.toNormalizedPath(tcf), |  | ||||||
|         true,              // openedByClient
 |  | ||||||
|         '',                // fileContent
 |  | ||||||
|         ts.ScriptKind.TS,  // scriptKind
 |  | ||||||
|     ); |  | ||||||
|     if (!scriptInfo) { |  | ||||||
|       throw new Error(`Failed to create script info for ${tcf}`); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   // Add ScriptInfo to project if it's missing. A ScriptInfo needs to be part of
 |  | ||||||
|   // the project so that it becomes part of the program.
 |  | ||||||
|   if (!project.containsScriptInfo(scriptInfo)) { |  | ||||||
|     project.addRoot(scriptInfo); |  | ||||||
|   } |  | ||||||
|   return scriptInfo; |  | ||||||
| } |  | ||||||
| @ -1,103 +0,0 @@ | |||||||
| /** |  | ||||||
|  * @license |  | ||||||
|  * Copyright Google LLC All Rights Reserved. |  | ||||||
|  * |  | ||||||
|  * Use of this source code is governed by an MIT-style license that can be |  | ||||||
|  * found in the LICENSE file at https://angular.io/license
 |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| import * as ts from 'typescript/lib/tsserverlibrary'; |  | ||||||
| 
 |  | ||||||
| export function makeCompilerHostFromProject(project: ts.server.Project): ts.CompilerHost { |  | ||||||
|   const compilerHost: ts.CompilerHost = { |  | ||||||
|     fileExists(fileName: string): boolean { |  | ||||||
|       return project.fileExists(fileName); |  | ||||||
|     }, |  | ||||||
|     readFile(fileName: string): string | |  | ||||||
|         undefined { |  | ||||||
|           return project.readFile(fileName); |  | ||||||
|         }, |  | ||||||
|     directoryExists(directoryName: string): boolean { |  | ||||||
|       return project.directoryExists(directoryName); |  | ||||||
|     }, |  | ||||||
|     getCurrentDirectory(): string { |  | ||||||
|       return project.getCurrentDirectory(); |  | ||||||
|     }, |  | ||||||
|     getDirectories(path: string): string[] { |  | ||||||
|       return project.getDirectories(path); |  | ||||||
|     }, |  | ||||||
|     getSourceFile( |  | ||||||
|         fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void, |  | ||||||
|         shouldCreateNewSourceFile?: boolean): ts.SourceFile | |  | ||||||
|         undefined { |  | ||||||
|           const path = project.projectService.toPath(fileName); |  | ||||||
|           return project.getSourceFile(path); |  | ||||||
|         }, |  | ||||||
|     getSourceFileByPath( |  | ||||||
|         fileName: string, path: ts.Path, languageVersion: ts.ScriptTarget, |  | ||||||
|         onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): ts.SourceFile | |  | ||||||
|         undefined { |  | ||||||
|           return project.getSourceFile(path); |  | ||||||
|         }, |  | ||||||
|     getCancellationToken(): ts.CancellationToken { |  | ||||||
|       return { |  | ||||||
|         isCancellationRequested() { |  | ||||||
|           return project.getCancellationToken().isCancellationRequested(); |  | ||||||
|         }, |  | ||||||
|         throwIfCancellationRequested() { |  | ||||||
|           if (this.isCancellationRequested()) { |  | ||||||
|             throw new ts.OperationCanceledException(); |  | ||||||
|           } |  | ||||||
|         }, |  | ||||||
|       }; |  | ||||||
|     }, |  | ||||||
|     getDefaultLibFileName(options: ts.CompilerOptions): string { |  | ||||||
|       return project.getDefaultLibFileName(); |  | ||||||
|     }, |  | ||||||
|     writeFile( |  | ||||||
|         fileName: string, data: string, writeByteOrderMark: boolean, |  | ||||||
|         onError?: (message: string) => void, sourceFiles?: readonly ts.SourceFile[]) { |  | ||||||
|       return project.writeFile(fileName, data); |  | ||||||
|     }, |  | ||||||
|     getCanonicalFileName(fileName: string): string { |  | ||||||
|       return project.projectService.toCanonicalFileName(fileName); |  | ||||||
|     }, |  | ||||||
|     useCaseSensitiveFileNames(): boolean { |  | ||||||
|       return project.useCaseSensitiveFileNames(); |  | ||||||
|     }, |  | ||||||
|     getNewLine(): string { |  | ||||||
|       return project.getNewLine(); |  | ||||||
|     }, |  | ||||||
|     readDirectory( |  | ||||||
|         rootDir: string, extensions: readonly string[], excludes: readonly string[]|undefined, |  | ||||||
|         includes: readonly string[], depth?: number): string[] { |  | ||||||
|       return project.readDirectory(rootDir, extensions, excludes, includes, depth); |  | ||||||
|     }, |  | ||||||
|     resolveModuleNames( |  | ||||||
|         moduleNames: string[], containingFile: string, reusedNames: string[]|undefined, |  | ||||||
|         redirectedReference: ts.ResolvedProjectReference|undefined, options: ts.CompilerOptions): |  | ||||||
|         (ts.ResolvedModule | undefined)[] { |  | ||||||
|           return project.resolveModuleNames( |  | ||||||
|               moduleNames, containingFile, reusedNames, redirectedReference); |  | ||||||
|         }, |  | ||||||
|     resolveTypeReferenceDirectives( |  | ||||||
|         typeReferenceDirectiveNames: string[], containingFile: string, |  | ||||||
|         redirectedReference: ts.ResolvedProjectReference|undefined, options: ts.CompilerOptions): |  | ||||||
|         (ts.ResolvedTypeReferenceDirective | undefined)[] { |  | ||||||
|           return project.resolveTypeReferenceDirectives( |  | ||||||
|               typeReferenceDirectiveNames, containingFile, redirectedReference); |  | ||||||
|         }, |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   if (project.trace) { |  | ||||||
|     compilerHost.trace = function trace(s: string) { |  | ||||||
|       project.trace!(s); |  | ||||||
|     }; |  | ||||||
|   } |  | ||||||
|   if (project.realpath) { |  | ||||||
|     compilerHost.realpath = function realpath(path: string): string { |  | ||||||
|       return project.realpath!(path); |  | ||||||
|     }; |  | ||||||
|   } |  | ||||||
|   return compilerHost; |  | ||||||
| } |  | ||||||
| @ -7,30 +7,53 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| import {CompilerOptions, createNgCompilerOptions} from '@angular/compiler-cli'; | import {CompilerOptions, createNgCompilerOptions} from '@angular/compiler-cli'; | ||||||
|  | import {NgCompiler} from '@angular/compiler-cli/src/ngtsc/core'; | ||||||
|  | import {NgCompilerAdapter} from '@angular/compiler-cli/src/ngtsc/core/api'; | ||||||
|  | import {absoluteFrom, absoluteFromSourceFile, AbsoluteFsPath} from '@angular/compiler-cli/src/ngtsc/file_system'; | ||||||
|  | import {PatchedProgramIncrementalBuildStrategy} from '@angular/compiler-cli/src/ngtsc/incremental'; | ||||||
|  | import {isShim} from '@angular/compiler-cli/src/ngtsc/shims'; | ||||||
|  | import {TypeCheckShimGenerator} from '@angular/compiler-cli/src/ngtsc/typecheck'; | ||||||
|  | import {OptimizeFor, TypeCheckingProgramStrategy} from '@angular/compiler-cli/src/ngtsc/typecheck/api'; | ||||||
| import * as ts from 'typescript/lib/tsserverlibrary'; | import * as ts from 'typescript/lib/tsserverlibrary'; | ||||||
| import {Compiler} from './compiler/compiler'; |  | ||||||
| 
 | 
 | ||||||
| export class LanguageService { | export class LanguageService { | ||||||
|   private options: CompilerOptions; |   private options: CompilerOptions; | ||||||
|   private readonly compiler: Compiler; |   private lastKnownProgram: ts.Program|null = null; | ||||||
|  |   private readonly strategy: TypeCheckingProgramStrategy; | ||||||
|  |   private readonly adapter: NgCompilerAdapter; | ||||||
| 
 | 
 | ||||||
|   constructor(project: ts.server.Project, private readonly tsLS: ts.LanguageService) { |   constructor(project: ts.server.Project, private readonly tsLS: ts.LanguageService) { | ||||||
|     this.options = parseNgCompilerOptions(project); |     this.options = parseNgCompilerOptions(project); | ||||||
|  |     this.strategy = createTypeCheckingProgramStrategy(project); | ||||||
|  |     this.adapter = createNgCompilerAdapter(project); | ||||||
|     this.watchConfigFile(project); |     this.watchConfigFile(project); | ||||||
|     this.compiler = new Compiler(project, this.options); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   getSemanticDiagnostics(fileName: string): ts.Diagnostic[] { |   getSemanticDiagnostics(fileName: string): ts.Diagnostic[] { | ||||||
|     const result = this.compiler.analyze(); |     const program = this.strategy.getProgram(); | ||||||
|     if (!result) { |     const compiler = this.createCompiler(program); | ||||||
|       return []; |     if (fileName.endsWith('.ts')) { | ||||||
|  |       const sourceFile = program.getSourceFile(fileName); | ||||||
|  |       if (!sourceFile) { | ||||||
|  |         return []; | ||||||
|  |       } | ||||||
|  |       const ttc = compiler.getTemplateTypeChecker(); | ||||||
|  |       const diagnostics = ttc.getDiagnosticsForFile(sourceFile, OptimizeFor.SingleFile); | ||||||
|  |       this.lastKnownProgram = compiler.getNextProgram(); | ||||||
|  |       return diagnostics; | ||||||
|     } |     } | ||||||
|     const {compiler, program} = result; |     throw new Error('Ivy LS currently does not support external template'); | ||||||
|     const sourceFile = program.getSourceFile(fileName); |   } | ||||||
|     if (!sourceFile) { | 
 | ||||||
|       return []; |   private createCompiler(program: ts.Program): NgCompiler { | ||||||
|     } |     return new NgCompiler( | ||||||
|     return compiler.getDiagnostics(sourceFile); |         this.adapter, | ||||||
|  |         this.options, | ||||||
|  |         program, | ||||||
|  |         this.strategy, | ||||||
|  |         new PatchedProgramIncrementalBuildStrategy(), | ||||||
|  |         this.lastKnownProgram, | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private watchConfigFile(project: ts.server.Project) { |   private watchConfigFile(project: ts.server.Project) { | ||||||
| @ -47,7 +70,6 @@ export class LanguageService { | |||||||
|           project.log(`Config file changed: ${fileName}`); |           project.log(`Config file changed: ${fileName}`); | ||||||
|           if (eventKind === ts.FileWatcherEventKind.Changed) { |           if (eventKind === ts.FileWatcherEventKind.Changed) { | ||||||
|             this.options = parseNgCompilerOptions(project); |             this.options = parseNgCompilerOptions(project); | ||||||
|             this.compiler.setCompilerOptions(this.options); |  | ||||||
|           } |           } | ||||||
|         }); |         }); | ||||||
|   } |   } | ||||||
| @ -66,3 +88,80 @@ export function parseNgCompilerOptions(project: ts.server.Project): CompilerOpti | |||||||
|   const basePath = project.getCurrentDirectory(); |   const basePath = project.getCurrentDirectory(); | ||||||
|   return createNgCompilerOptions(basePath, config, project.getCompilationSettings()); |   return createNgCompilerOptions(basePath, config, project.getCompilationSettings()); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | function createNgCompilerAdapter(project: ts.server.Project): NgCompilerAdapter { | ||||||
|  |   return { | ||||||
|  |     entryPoint: null,  // entry point is only needed if code is emitted
 | ||||||
|  |     constructionDiagnostics: [], | ||||||
|  |     ignoreForEmit: new Set(), | ||||||
|  |     factoryTracker: null,      // no .ngfactory shims
 | ||||||
|  |     unifiedModulesHost: null,  // only used in Bazel
 | ||||||
|  |     rootDirs: project.getCompilationSettings().rootDirs?.map(absoluteFrom) || [], | ||||||
|  |     isShim, | ||||||
|  |     fileExists(fileName: string): boolean { | ||||||
|  |       return project.fileExists(fileName); | ||||||
|  |     }, | ||||||
|  |     readFile(fileName: string): string | | ||||||
|  |         undefined { | ||||||
|  |           return project.readFile(fileName); | ||||||
|  |         }, | ||||||
|  |     getCurrentDirectory(): string { | ||||||
|  |       return project.getCurrentDirectory(); | ||||||
|  |     }, | ||||||
|  |     getCanonicalFileName(fileName: string): string { | ||||||
|  |       return project.projectService.toCanonicalFileName(fileName); | ||||||
|  |     }, | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function createTypeCheckingProgramStrategy(project: ts.server.Project): | ||||||
|  |     TypeCheckingProgramStrategy { | ||||||
|  |   return { | ||||||
|  |     supportsInlineOperations: false, | ||||||
|  |     shimPathForComponent(component: ts.ClassDeclaration): AbsoluteFsPath { | ||||||
|  |       return TypeCheckShimGenerator.shimFor(absoluteFromSourceFile(component.getSourceFile())); | ||||||
|  |     }, | ||||||
|  |     getProgram(): ts.Program { | ||||||
|  |       const program = project.getLanguageService().getProgram(); | ||||||
|  |       if (!program) { | ||||||
|  |         throw new Error('Language service does not have a program!'); | ||||||
|  |       } | ||||||
|  |       return program; | ||||||
|  |     }, | ||||||
|  |     updateFiles(contents: Map<AbsoluteFsPath, string>) { | ||||||
|  |       for (const [fileName, newText] of contents) { | ||||||
|  |         const scriptInfo = getOrCreateTypeCheckScriptInfo(project, fileName); | ||||||
|  |         const snapshot = scriptInfo.getSnapshot(); | ||||||
|  |         const length = snapshot.getLength(); | ||||||
|  |         scriptInfo.editContent(0, length, newText); | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function getOrCreateTypeCheckScriptInfo( | ||||||
|  |     project: ts.server.Project, tcf: string): ts.server.ScriptInfo { | ||||||
|  |   // First check if there is already a ScriptInfo for the tcf
 | ||||||
|  |   const {projectService} = project; | ||||||
|  |   let scriptInfo = projectService.getScriptInfo(tcf); | ||||||
|  |   if (!scriptInfo) { | ||||||
|  |     // ScriptInfo needs to be opened by client to be able to set its user-defined
 | ||||||
|  |     // content. We must also provide file content, otherwise the service will
 | ||||||
|  |     // attempt to fetch the content from disk and fail.
 | ||||||
|  |     scriptInfo = projectService.getOrCreateScriptInfoForNormalizedPath( | ||||||
|  |         ts.server.toNormalizedPath(tcf), | ||||||
|  |         true,              // openedByClient
 | ||||||
|  |         '',                // fileContent
 | ||||||
|  |         ts.ScriptKind.TS,  // scriptKind
 | ||||||
|  |     ); | ||||||
|  |     if (!scriptInfo) { | ||||||
|  |       throw new Error(`Failed to create script info for ${tcf}`); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   // Add ScriptInfo to project if it's missing. A ScriptInfo needs to be part of
 | ||||||
|  |   // the project so that it becomes part of the program.
 | ||||||
|  |   if (!project.containsScriptInfo(scriptInfo)) { | ||||||
|  |     project.addRoot(scriptInfo); | ||||||
|  |   } | ||||||
|  |   return scriptInfo; | ||||||
|  | } | ||||||
|  | |||||||
| @ -25,7 +25,6 @@ jasmine_node_test( | |||||||
|     ], |     ], | ||||||
|     tags = [ |     tags = [ | ||||||
|         "ivy-only", |         "ivy-only", | ||||||
|         "manual",  # do not run this on CI since compiler APIs are not yet stable |  | ||||||
|     ], |     ], | ||||||
|     deps = [ |     deps = [ | ||||||
|         ":test_lib", |         ":test_lib", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user