angular-docs-cn/packages/compiler-cli/ngcc/src/analysis/ngcc_trait_compiler.ts

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 {}
}