feat(ivy): Add AOT handling for bare classes with Input and Output decorators (#25367)
PR Close #25367
This commit is contained in:
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user