2020-01-06 23:12:19 +01:00
|
|
|
/**
|
|
|
|
* @license
|
2020-05-19 12:08:49 -07:00
|
|
|
* Copyright Google LLC All Rights Reserved.
|
2020-01-06 23:12:19 +01:00
|
|
|
*
|
|
|
|
* 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());
|
|
|
|
}
|
|
|
|
|
2020-04-06 08:30:08 +01:00
|
|
|
get analyzedFiles(): ts.SourceFile[] {
|
|
|
|
return Array.from(this.fileToClasses.keys());
|
|
|
|
}
|
2020-01-06 23:12:19 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
perf(compiler-cli): perform template type-checking incrementally (#36211)
This optimization builds on a lot of prior work to finally make type-
checking of templates incremental.
Incrementality requires two main components:
- the ability to reuse work from a prior compilation.
- the ability to know when changes in the current program invalidate that
prior work.
Prior to this commit, on every type-checking pass the compiler would
generate new .ngtypecheck files for each original input file in the program.
1. (Build #1 main program): empty .ngtypecheck files generated for each
original input file.
2. (Build #1 type-check program): .ngtypecheck contents overridden for those
which have corresponding components that need type-checked.
3. (Build #2 main program): throw away old .ngtypecheck files and generate
new empty ones.
4. (Build #2 type-check program): same as step 2.
With this commit, the `IncrementalDriver` now tracks template type-checking
_metadata_ for each input file. The metadata contains information about
source mappings for generated type-checking code, as well as some
diagnostics which were discovered at type-check analysis time. The actual
type-checking code is stored in the TypeScript AST for type-checking files,
which is now re-used between programs as follows:
1. (Build #1 main program): empty .ngtypecheck files generated for each
original input file.
2. (Build #1 type-check program): .ngtypecheck contents overridden for those
which have corresponding components that need type-checked, and the
metadata registered in the `IncrementalDriver`.
3. (Build #2 main program): The `TypeCheckShimGenerator` now reuses _all_
.ngtypecheck `ts.SourceFile` shims from build #1's type-check program in
the construction of build #2's main program. Some of the contents of
these files might be stale (if a component's template changed, for
example), but wholesale reuse here prevents unnecessary changes in the
contents of the program at this point and makes TypeScript's job a lot
easier.
4. (Build #2 type-check program): For those input files which have not
"logically changed" (meaning components within are semantically the same
as they were before), the compiler will re-use the type-check file
metadata from build #1, and _not_ generate a new .ngtypecheck shim.
For components which have logically changed or where the previous
.ngtypecheck contents cannot otherwise be reused, code generation happens
as before.
PR Close #36211
2020-03-19 11:29:58 -07:00
|
|
|
class NoIncrementalBuild implements IncrementalBuild<any, any> {
|
2020-04-06 08:30:08 +01:00
|
|
|
priorWorkFor(sf: ts.SourceFile): any[]|null {
|
|
|
|
return null;
|
|
|
|
}
|
perf(compiler-cli): perform template type-checking incrementally (#36211)
This optimization builds on a lot of prior work to finally make type-
checking of templates incremental.
Incrementality requires two main components:
- the ability to reuse work from a prior compilation.
- the ability to know when changes in the current program invalidate that
prior work.
Prior to this commit, on every type-checking pass the compiler would
generate new .ngtypecheck files for each original input file in the program.
1. (Build #1 main program): empty .ngtypecheck files generated for each
original input file.
2. (Build #1 type-check program): .ngtypecheck contents overridden for those
which have corresponding components that need type-checked.
3. (Build #2 main program): throw away old .ngtypecheck files and generate
new empty ones.
4. (Build #2 type-check program): same as step 2.
With this commit, the `IncrementalDriver` now tracks template type-checking
_metadata_ for each input file. The metadata contains information about
source mappings for generated type-checking code, as well as some
diagnostics which were discovered at type-check analysis time. The actual
type-checking code is stored in the TypeScript AST for type-checking files,
which is now re-used between programs as follows:
1. (Build #1 main program): empty .ngtypecheck files generated for each
original input file.
2. (Build #1 type-check program): .ngtypecheck contents overridden for those
which have corresponding components that need type-checked, and the
metadata registered in the `IncrementalDriver`.
3. (Build #2 main program): The `TypeCheckShimGenerator` now reuses _all_
.ngtypecheck `ts.SourceFile` shims from build #1's type-check program in
the construction of build #2's main program. Some of the contents of
these files might be stale (if a component's template changed, for
example), but wholesale reuse here prevents unnecessary changes in the
contents of the program at this point and makes TypeScript's job a lot
easier.
4. (Build #2 type-check program): For those input files which have not
"logically changed" (meaning components within are semantically the same
as they were before), the compiler will re-use the type-check file
metadata from build #1, and _not_ generate a new .ngtypecheck shim.
For components which have logically changed or where the previous
.ngtypecheck contents cannot otherwise be reused, code generation happens
as before.
PR Close #36211
2020-03-19 11:29:58 -07:00
|
|
|
|
|
|
|
priorTypeCheckingResultsFor(): null {
|
|
|
|
return null;
|
|
|
|
}
|
2020-07-13 16:09:46 -07:00
|
|
|
|
|
|
|
recordSuccessfulTypeCheck(): void {}
|
2020-01-06 23:12:19 +01:00
|
|
|
}
|