Alex Rickabaugh 16c7441c2f refactor(compiler-cli): introduce the TemplateTypeChecker abstraction (#38105)
This commit significantly refactors the 'typecheck' package to introduce a
new abstraction, the `TemplateTypeChecker`. To achieve this:

* a 'typecheck:api' package is introduced, containing common interfaces that
  consumers of the template type-checking infrastructure can depend on
  without incurring a dependency on the template type-checking machinery as
  a whole.
* interfaces for `TemplateTypeChecker` and `TypeCheckContext` are introduced
  which contain the abstract operations supported by the implementation
  classes `TemplateTypeCheckerImpl` and `TypeCheckContextImpl` respectively.
* the `TemplateTypeChecker` interface supports diagnostics on a whole
  program basis to start with, but the implementation is purposefully
  designed to support incremental diagnostics at a per-file or per-component
  level.
* `TemplateTypeChecker` supports direct access to the type check block of a
  component.
* the testing utility is refactored to be a lot more useful, and new tests
  are added for the new abstraction.

PR Close #38105
2020-07-29 10:31:20 -07:00

96 lines
3.2 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 * as ts from 'typescript';
import {IncrementalBuild} from '../../../src/ngtsc/incremental/api';
import {NOOP_PERF_RECORDER} from '../../../src/ngtsc/perf';
import {ClassDeclaration, Decorator} from '../../../src/ngtsc/reflection';
import {DecoratorHandler, DtsTransformRegistry, HandlerFlags, Trait, TraitCompiler} from '../../../src/ngtsc/transform';
import {NgccReflectionHost} from '../host/ngcc_host';
import {isDefined} from '../utils';
/**
* Specializes the `TraitCompiler` for ngcc purposes. Mainly, this includes an alternative way of
* scanning for classes to compile using the reflection host's `findClassSymbols`, together with
* support to inject synthetic decorators into the compilation for ad-hoc migrations that ngcc
* performs.
*/
export class NgccTraitCompiler extends TraitCompiler {
constructor(
handlers: DecoratorHandler<unknown, unknown, unknown>[],
private ngccReflector: NgccReflectionHost) {
super(
handlers, ngccReflector, NOOP_PERF_RECORDER, new NoIncrementalBuild(),
/* compileNonExportedClasses */ true, new DtsTransformRegistry());
}
get analyzedFiles(): ts.SourceFile[] {
return Array.from(this.fileToClasses.keys());
}
/**
* Analyzes the source file in search for classes to process. For any class that is found in the
* file, a `ClassRecord` is created and the source file is included in the `analyzedFiles` array.
*/
analyzeFile(sf: ts.SourceFile): void {
const ngccClassSymbols = this.ngccReflector.findClassSymbols(sf);
for (const classSymbol of ngccClassSymbols) {
this.analyzeClass(classSymbol.declaration.valueDeclaration, null);
}
return undefined;
}
/**
* Associate a new synthesized decorator, which did not appear in the original source, with a
* given class.
* @param clazz the class to receive the new decorator.
* @param decorator the decorator to inject.
* @param flags optional bitwise flag to influence the compilation of the decorator.
*/
injectSyntheticDecorator(clazz: ClassDeclaration, decorator: Decorator, flags?: HandlerFlags):
Trait<unknown, unknown, unknown>[] {
const migratedTraits = this.detectTraits(clazz, [decorator]);
if (migratedTraits === null) {
return [];
}
for (const trait of migratedTraits) {
this.analyzeTrait(clazz, trait, flags);
}
return migratedTraits;
}
/**
* Returns all decorators that have been recognized for the provided class, including any
* synthetically injected decorators.
* @param clazz the declaration for which the decorators are returned.
*/
getAllDecorators(clazz: ClassDeclaration): Decorator[]|null {
const record = this.recordFor(clazz);
if (record === null) {
return null;
}
return record.traits.map(trait => trait.detected.decorator).filter(isDefined);
}
}
class NoIncrementalBuild implements IncrementalBuild<any, any> {
priorWorkFor(sf: ts.SourceFile): any[]|null {
return null;
}
priorTypeCheckingResultsFor(): null {
return null;
}
recordSuccessfulTypeCheck(): void {}
}