feat(ivy): Add AOT handling for bare classes with Input and Output decorators (#25367)

PR Close #25367
This commit is contained in:
Ben Lesh
2018-08-07 12:04:39 -07:00
parent 26066f282e
commit a0a29fdd27
22 changed files with 483 additions and 60 deletions

View File

@ -20,12 +20,12 @@ import {Decorator} from '../../host';
* responsible for extracting the information required to perform compilation from the decorators
* and Typescript source, invoking the decorator compiler, and returning the result.
*/
export interface DecoratorHandler<A> {
export interface DecoratorHandler<A, M> {
/**
* Scan a set of reflected decorators and determine if this handler is responsible for compilation
* of one of them.
*/
detect(decorator: Decorator[]): Decorator|undefined;
detect(node: ts.Declaration, decorators: Decorator[]|null): M|undefined;
/**
@ -34,14 +34,14 @@ export interface DecoratorHandler<A> {
* `preAnalyze` is optional and is not guaranteed to be called through all compilation flows. It
* will only be called if asynchronicity is supported in the CompilerHost.
*/
preanalyze?(node: ts.Declaration, decorator: Decorator): Promise<void>|undefined;
preanalyze?(node: ts.Declaration, metadata: M): Promise<void>|undefined;
/**
* Perform analysis on the decorator/class combination, producing instructions for compilation
* if successful, or an array of diagnostic messages if the analysis fails or the decorator
* isn't valid.
*/
analyze(node: ts.Declaration, decorator: Decorator): AnalysisOutput<A>;
analyze(node: ts.Declaration, metadata: M): AnalysisOutput<A>;
/**
* Generate a description of the field which should be added to the class, including any

View File

@ -19,10 +19,10 @@ import {DtsFileTransformer} from './declaration';
* Record of an adapter which decided to emit a static field, and the analysis it performed to
* prepare for that operation.
*/
interface EmitFieldOperation<T> {
adapter: DecoratorHandler<T>;
analysis: AnalysisOutput<T>;
decorator: Decorator;
interface EmitFieldOperation<A, M> {
adapter: DecoratorHandler<A, M>;
analysis: AnalysisOutput<A>;
metadata: M;
}
/**
@ -36,7 +36,7 @@ export class IvyCompilation {
* Tracks classes which have been analyzed and found to have an Ivy decorator, and the
* information recorded about them for later compilation.
*/
private analysis = new Map<ts.Declaration, EmitFieldOperation<any>>();
private analysis = new Map<ts.Declaration, EmitFieldOperation<any, any>>();
/**
* Tracks factory information which needs to be generated.
@ -59,7 +59,7 @@ export class IvyCompilation {
* `null` in most cases.
*/
constructor(
private handlers: DecoratorHandler<any>[], private checker: ts.TypeChecker,
private handlers: DecoratorHandler<any, any>[], private checker: ts.TypeChecker,
private reflector: ReflectionHost, private coreImportsFrom: ts.SourceFile|null,
private sourceToFactorySymbols: Map<string, Set<string>>|null) {}
@ -78,15 +78,14 @@ export class IvyCompilation {
const analyzeClass = (node: ts.Declaration): void => {
// The first step is to reflect the decorators.
const decorators = this.reflector.getDecoratorsOfDeclaration(node);
if (decorators === null) {
return;
}
const classDecorators = this.reflector.getDecoratorsOfDeclaration(node);
// Look through the DecoratorHandlers to see if any are relevant.
this.handlers.forEach(adapter => {
// An adapter is relevant if it matches one of the decorators on the class.
const decorator = adapter.detect(decorators);
if (decorator === undefined) {
const metadata = adapter.detect(node, classDecorators);
if (metadata === undefined) {
return;
}
@ -97,14 +96,15 @@ export class IvyCompilation {
throw new Error('TODO.Diagnostic: Class has multiple Angular decorators.');
}
// Run analysis on the decorator. This will produce either diagnostics, an
// Run analysis on the metadata. This will produce either diagnostics, an
// analysis result, or both.
const analysis = adapter.analyze(node, decorator);
const analysis = adapter.analyze(node, metadata);
if (analysis.analysis !== undefined) {
this.analysis.set(node, {
adapter,
analysis: analysis.analysis, decorator,
analysis: analysis.analysis,
metadata: metadata,
});
}
@ -119,7 +119,7 @@ export class IvyCompilation {
};
if (preanalyze && adapter.preanalyze !== undefined) {
const preanalysis = adapter.preanalyze(node, decorator);
const preanalysis = adapter.preanalyze(node, metadata);
if (preanalysis !== undefined) {
promises.push(preanalysis.then(() => completeAnalysis()));
} else {
@ -185,7 +185,7 @@ export class IvyCompilation {
return undefined;
}
return this.analysis.get(original) !.decorator;
return this.analysis.get(original) !.metadata;
}
/**