76 lines
2.8 KiB
TypeScript
76 lines
2.8 KiB
TypeScript
|
/**
|
||
|
* @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 {NgCompiler} from '@angular/compiler-cli/src/ngtsc/core';
|
||
|
import {NgCompilerOptions} from '@angular/compiler-cli/src/ngtsc/core/api';
|
||
|
import {TrackedIncrementalBuildStrategy} from '@angular/compiler-cli/src/ngtsc/incremental';
|
||
|
import {TypeCheckingProgramStrategy} from '@angular/compiler-cli/src/ngtsc/typecheck/api';
|
||
|
import * as ts from 'typescript/lib/tsserverlibrary';
|
||
|
|
||
|
import {isExternalTemplate, LanguageServiceAdapter} from './language_service_adapter';
|
||
|
|
||
|
export class CompilerFactory {
|
||
|
private readonly incrementalStrategy = new TrackedIncrementalBuildStrategy();
|
||
|
private compiler: NgCompiler|null = null;
|
||
|
private lastKnownProgram: ts.Program|null = null;
|
||
|
|
||
|
constructor(
|
||
|
private readonly adapter: LanguageServiceAdapter,
|
||
|
private readonly programStrategy: TypeCheckingProgramStrategy,
|
||
|
) {}
|
||
|
|
||
|
/**
|
||
|
* Create a new instance of the Ivy compiler if the program has changed since
|
||
|
* the last time the compiler was instantiated. If the program has not changed,
|
||
|
* return the existing instance.
|
||
|
* @param fileName override the template if this is an external template file
|
||
|
* @param options angular compiler options
|
||
|
*/
|
||
|
getOrCreateWithChangedFile(fileName: string, options: NgCompilerOptions): NgCompiler {
|
||
|
const program = this.programStrategy.getProgram();
|
||
|
if (!this.compiler || program !== this.lastKnownProgram) {
|
||
|
this.compiler = new NgCompiler(
|
||
|
this.adapter, // like compiler host
|
||
|
options, // angular compiler options
|
||
|
program,
|
||
|
this.programStrategy,
|
||
|
this.incrementalStrategy,
|
||
|
true, // enableTemplateTypeChecker
|
||
|
this.lastKnownProgram,
|
||
|
undefined, // perfRecorder (use default)
|
||
|
);
|
||
|
this.lastKnownProgram = program;
|
||
|
}
|
||
|
if (isExternalTemplate(fileName)) {
|
||
|
this.overrideTemplate(fileName, this.compiler);
|
||
|
}
|
||
|
return this.compiler;
|
||
|
}
|
||
|
|
||
|
private overrideTemplate(fileName: string, compiler: NgCompiler) {
|
||
|
if (!this.adapter.isTemplateDirty(fileName)) {
|
||
|
return;
|
||
|
}
|
||
|
// 1. Get the latest snapshot
|
||
|
const latestTemplate = this.adapter.readResource(fileName);
|
||
|
// 2. Find all components that use the template
|
||
|
const ttc = compiler.getTemplateTypeChecker();
|
||
|
const components = compiler.getComponentsWithTemplateFile(fileName);
|
||
|
// 3. Update component template
|
||
|
for (const component of components) {
|
||
|
if (ts.isClassDeclaration(component)) {
|
||
|
ttc.overrideComponentTemplate(component, latestTemplate);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
registerLastKnownProgram() {
|
||
|
this.lastKnownProgram = this.programStrategy.getProgram();
|
||
|
}
|
||
|
}
|