feat(ivy): register references from NgModule annotations (#26906)
The `NgModuleDecoratorHandler` can now register all the references that it finds in the `NgModule` metadata, such as `declarations`, `imports`, `exports` etc. This information can then be used by ngcc to work out if any of these references are internal only and need to be manually exported from a library's entry-point. PR Close #26906
This commit is contained in:

committed by
Igor Minar

parent
b93c1dffa1
commit
4a70b669be
@ -15,4 +15,5 @@ export {DirectiveDecoratorHandler} from './src/directive';
|
||||
export {InjectableDecoratorHandler} from './src/injectable';
|
||||
export {NgModuleDecoratorHandler} from './src/ng_module';
|
||||
export {PipeDecoratorHandler} from './src/pipe';
|
||||
export {NoopReferencesRegistry, ReferencesRegistry} from './src/references_registry';
|
||||
export {CompilationScope, SelectorScopeRegistry} from './src/selector_scope';
|
||||
|
@ -15,6 +15,7 @@ import {Reference, ResolvedReference, ResolvedValue, reflectObjectLiteral, stati
|
||||
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
||||
|
||||
import {generateSetClassMetadataCall} from './metadata';
|
||||
import {ReferencesRegistry} from './references_registry';
|
||||
import {SelectorScopeRegistry} from './selector_scope';
|
||||
import {getConstructorDependencies, isAngularCore, toR3Reference, unwrapExpression} from './util';
|
||||
|
||||
@ -32,7 +33,8 @@ export interface NgModuleAnalysis {
|
||||
export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalysis, Decorator> {
|
||||
constructor(
|
||||
private checker: ts.TypeChecker, private reflector: ReflectionHost,
|
||||
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {}
|
||||
private scopeRegistry: SelectorScopeRegistry, private referencesRegistry: ReferencesRegistry,
|
||||
private isCore: boolean) {}
|
||||
|
||||
detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined {
|
||||
if (!decorators) {
|
||||
@ -72,6 +74,7 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||
const expr = ngModule.get('declarations') !;
|
||||
const declarationMeta = staticallyResolve(expr, this.reflector, this.checker);
|
||||
declarations = this.resolveTypeList(expr, declarationMeta, 'declarations');
|
||||
this.referencesRegistry.add(...declarations);
|
||||
}
|
||||
let imports: Reference<ts.Declaration>[] = [];
|
||||
if (ngModule.has('imports')) {
|
||||
@ -80,6 +83,7 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||
expr, this.reflector, this.checker,
|
||||
ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
|
||||
imports = this.resolveTypeList(expr, importsMeta, 'imports');
|
||||
this.referencesRegistry.add(...imports);
|
||||
}
|
||||
let exports: Reference<ts.Declaration>[] = [];
|
||||
if (ngModule.has('exports')) {
|
||||
@ -88,12 +92,14 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||
expr, this.reflector, this.checker,
|
||||
ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
|
||||
exports = this.resolveTypeList(expr, exportsMeta, 'exports');
|
||||
this.referencesRegistry.add(...exports);
|
||||
}
|
||||
let bootstrap: Reference<ts.Declaration>[] = [];
|
||||
if (ngModule.has('bootstrap')) {
|
||||
const expr = ngModule.get('bootstrap') !;
|
||||
const bootstrapMeta = staticallyResolve(expr, this.reflector, this.checker);
|
||||
bootstrap = this.resolveTypeList(expr, bootstrapMeta, 'bootstrap');
|
||||
this.referencesRegistry.add(...bootstrap);
|
||||
}
|
||||
|
||||
// Register this module's information with the SelectorScopeRegistry. This ensures that during
|
||||
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. 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 {Declaration} from '../../host';
|
||||
import {Reference} from '../../metadata';
|
||||
|
||||
/**
|
||||
* Implement this interface if you want DecoratorHandlers to register
|
||||
* references that they find in their analysis of the code.
|
||||
*/
|
||||
export interface ReferencesRegistry {
|
||||
/**
|
||||
* Register one or more references in the registry.
|
||||
* Only `ResolveReference` references are stored. Other types are ignored.
|
||||
* @param references A collection of references to register.
|
||||
*/
|
||||
add(...references: Reference<ts.Declaration>[]): void;
|
||||
/**
|
||||
* Create and return a mapping for the registered resolved references.
|
||||
* @returns A map of reference identifiers to reference declarations.
|
||||
*/
|
||||
getDeclarationMap(): Map<ts.Identifier, Declaration>;
|
||||
}
|
||||
|
||||
/**
|
||||
* This registry does nothing, since ngtsc does not currently need
|
||||
* this functionality.
|
||||
* The ngcc tool implements a working version for its purposes.
|
||||
*/
|
||||
export class NoopReferencesRegistry implements ReferencesRegistry {
|
||||
add(...references: Reference<ts.Declaration>[]): void {}
|
||||
getDeclarationMap(): Map<ts.Identifier, Declaration> { return new Map(); }
|
||||
}
|
@ -13,7 +13,7 @@ import * as ts from 'typescript';
|
||||
import * as api from '../transformers/api';
|
||||
import {nocollapseHack} from '../transformers/nocollapse_hack';
|
||||
|
||||
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from './annotations';
|
||||
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from './annotations';
|
||||
import {BaseDefDecoratorHandler} from './annotations/src/base_def';
|
||||
import {TypeScriptReflectionHost} from './metadata';
|
||||
import {FileResourceLoader, HostResourceLoader} from './resource_loader';
|
||||
@ -214,6 +214,7 @@ export class NgtscProgram implements api.Program {
|
||||
private makeCompilation(): IvyCompilation {
|
||||
const checker = this.tsProgram.getTypeChecker();
|
||||
const scopeRegistry = new SelectorScopeRegistry(checker, this.reflector);
|
||||
const referencesRegistry = new NoopReferencesRegistry();
|
||||
|
||||
// Set up the IvyCompilation, which manages state for the Ivy transformer.
|
||||
const handlers = [
|
||||
@ -223,7 +224,8 @@ export class NgtscProgram implements api.Program {
|
||||
this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false),
|
||||
new DirectiveDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
|
||||
new InjectableDecoratorHandler(this.reflector, this.isCore),
|
||||
new NgModuleDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
|
||||
new NgModuleDecoratorHandler(
|
||||
checker, this.reflector, scopeRegistry, referencesRegistry, this.isCore),
|
||||
new PipeDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
|
||||
];
|
||||
|
||||
|
Reference in New Issue
Block a user