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:
parent
b93c1dffa1
commit
4a70b669be
|
@ -9,9 +9,8 @@ import {ConstantPool} from '@angular/compiler';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from '../../../ngtsc/annotations';
|
import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader, SelectorScopeRegistry} from '../../../ngtsc/annotations';
|
||||||
import {CompileResult, DecoratorHandler} from '../../../ngtsc/transform';
|
import {CompileResult, DecoratorHandler} from '../../../ngtsc/transform';
|
||||||
|
|
||||||
import {DecoratedClass} from '../host/decorated_class';
|
import {DecoratedClass} from '../host/decorated_class';
|
||||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||||
import {isDefined} from '../utils';
|
import {isDefined} from '../utils';
|
||||||
|
@ -63,13 +62,15 @@ export class DecorationAnalyzer {
|
||||||
this.rootDirs, /* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true),
|
this.rootDirs, /* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true),
|
||||||
new DirectiveDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),
|
new DirectiveDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),
|
||||||
new InjectableDecoratorHandler(this.host, this.isCore),
|
new InjectableDecoratorHandler(this.host, this.isCore),
|
||||||
new NgModuleDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),
|
new NgModuleDecoratorHandler(
|
||||||
|
this.typeChecker, this.host, this.scopeRegistry, this.referencesRegistry, this.isCore),
|
||||||
new PipeDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),
|
new PipeDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),
|
||||||
];
|
];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private typeChecker: ts.TypeChecker, private host: NgccReflectionHost,
|
private typeChecker: ts.TypeChecker, private host: NgccReflectionHost,
|
||||||
private rootDirs: string[], private isCore: boolean) {}
|
private referencesRegistry: ReferencesRegistry, private rootDirs: string[],
|
||||||
|
private isCore: boolean) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyze a program to find all the decorated files should be transformed.
|
* Analyze a program to find all the decorated files should be transformed.
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* @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 {ReferencesRegistry} from '../../../ngtsc/annotations';
|
||||||
|
import {Declaration, ReflectionHost} from '../../../ngtsc/host';
|
||||||
|
import {Reference, ResolvedReference} from '../../../ngtsc/metadata';
|
||||||
|
import {hasNameIdentifier} from '../utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a place for DecoratorHandlers to register references that they
|
||||||
|
* find in their analysis of the code.
|
||||||
|
*
|
||||||
|
* This registry is used to ensure that these references are publicly exported
|
||||||
|
* from libraries that are compiled by ngcc.
|
||||||
|
*/
|
||||||
|
export class NgccReferencesRegistry implements ReferencesRegistry {
|
||||||
|
private map = new Map<ts.Identifier, Declaration>();
|
||||||
|
|
||||||
|
constructor(private host: ReflectionHost) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
references.forEach(ref => {
|
||||||
|
// Only store resolved references. We are not interested in literals.
|
||||||
|
if (ref instanceof ResolvedReference && hasNameIdentifier(ref.node)) {
|
||||||
|
const declaration = this.host.getDeclarationOfIdentifier(ref.node.name);
|
||||||
|
if (declaration && hasNameIdentifier(declaration.node)) {
|
||||||
|
this.map.set(declaration.node.name, declaration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and return a mapping for the registered resolved references.
|
||||||
|
* @returns A map of reference identifiers to reference declarations.
|
||||||
|
*/
|
||||||
|
getDeclarationMap(): Map<ts.Identifier, Declaration> { return this.map; }
|
||||||
|
}
|
|
@ -62,7 +62,7 @@ interface EntryPointPackageJson {
|
||||||
* @param packageJsonPath the absolute path to the package.json file.
|
* @param packageJsonPath the absolute path to the package.json file.
|
||||||
* @returns JSON from the package.json file if it is valid, `null` otherwise.
|
* @returns JSON from the package.json file if it is valid, `null` otherwise.
|
||||||
*/
|
*/
|
||||||
function loadEntryPointPackage(packageJsonPath: string): {[key: string]: any}|null {
|
function loadEntryPointPackage(packageJsonPath: string): EntryPointPackageJson|null {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -109,7 +109,8 @@ export function getEntryPointInfo(packagePath: string, entryPointPath: string):
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also there must exist a `metadata.json` file next to the typings entry-point.
|
// Also there must exist a `metadata.json` file next to the typings entry-point.
|
||||||
const metadataPath = path.resolve(entryPointPath, typings.replace(/\.d\.ts$/, '') + '.metadata.json');
|
const metadataPath =
|
||||||
|
path.resolve(entryPointPath, typings.replace(/\.d\.ts$/, '') + '.metadata.json');
|
||||||
if (!fs.existsSync(metadataPath)) {
|
if (!fs.existsSync(metadataPath)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {mkdir, mv} from 'shelljs';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {DecorationAnalyzer} from '../analysis/decoration_analyzer';
|
import {DecorationAnalyzer} from '../analysis/decoration_analyzer';
|
||||||
|
import {NgccReferencesRegistry} from '../analysis/ngcc_references_registry';
|
||||||
import {SwitchMarkerAnalyzer} from '../analysis/switch_marker_analyzer';
|
import {SwitchMarkerAnalyzer} from '../analysis/switch_marker_analyzer';
|
||||||
import {Esm2015ReflectionHost} from '../host/esm2015_host';
|
import {Esm2015ReflectionHost} from '../host/esm2015_host';
|
||||||
import {Esm5ReflectionHost} from '../host/esm5_host';
|
import {Esm5ReflectionHost} from '../host/esm5_host';
|
||||||
|
@ -156,8 +157,10 @@ export class Transformer {
|
||||||
analyzeProgram(
|
analyzeProgram(
|
||||||
program: ts.Program, reflectionHost: NgccReflectionHost, rootDirs: string[],
|
program: ts.Program, reflectionHost: NgccReflectionHost, rootDirs: string[],
|
||||||
isCore: boolean) {
|
isCore: boolean) {
|
||||||
|
const typeChecker = bundle.program.getTypeChecker();
|
||||||
|
const referencesRegistry = new NgccReferencesRegistry(reflectionHost);
|
||||||
const decorationAnalyzer =
|
const decorationAnalyzer =
|
||||||
new DecorationAnalyzer(program.getTypeChecker(), reflectionHost, rootDirs, isCore);
|
new DecorationAnalyzer(typeChecker, reflectionHost, referencesRegistry, rootDirs, isCore);
|
||||||
const switchMarkerAnalyzer = new SwitchMarkerAnalyzer(reflectionHost);
|
const switchMarkerAnalyzer = new SwitchMarkerAnalyzer(reflectionHost);
|
||||||
return {
|
return {
|
||||||
decorationAnalyses: decorationAnalyzer.analyzeProgram(program),
|
decorationAnalyses: decorationAnalyzer.analyzeProgram(program),
|
||||||
|
|
|
@ -40,3 +40,13 @@ export function findAll<T>(node: ts.Node, test: (node: ts.Node) => node is ts.No
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the given declaration have a name which is an identifier?
|
||||||
|
* @param declaration The declaration to test.
|
||||||
|
* @returns true if the declaration has an identifer for a name.
|
||||||
|
*/
|
||||||
|
export function hasNameIdentifier(declaration: ts.Declaration): declaration is ts.Declaration&
|
||||||
|
{name: ts.Identifier} {
|
||||||
|
return ts.isIdentifier((declaration as any).name);
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import * as ts from 'typescript';
|
||||||
import {Decorator} from '../../../ngtsc/host';
|
import {Decorator} from '../../../ngtsc/host';
|
||||||
import {DecoratorHandler} from '../../../ngtsc/transform';
|
import {DecoratorHandler} from '../../../ngtsc/transform';
|
||||||
import {DecorationAnalyses, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
|
import {DecorationAnalyses, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
|
||||||
|
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
|
||||||
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
|
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
|
||||||
|
|
||||||
import {makeProgram} from '../helpers/utils';
|
import {makeProgram} from '../helpers/utils';
|
||||||
|
@ -84,9 +85,10 @@ describe('DecorationAnalyzer', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
program = makeProgram(TEST_PROGRAM);
|
program = makeProgram(TEST_PROGRAM);
|
||||||
const analyzer = new DecorationAnalyzer(
|
const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
|
||||||
program.getTypeChecker(), new Esm2015ReflectionHost(false, program.getTypeChecker()),
|
const referencesRegistry = new NgccReferencesRegistry(host);
|
||||||
[''], false);
|
const analyzer =
|
||||||
|
new DecorationAnalyzer(program.getTypeChecker(), host, referencesRegistry, [''], false);
|
||||||
testHandler = createTestHandler();
|
testHandler = createTestHandler();
|
||||||
analyzer.handlers = [testHandler];
|
analyzer.handlers = [testHandler];
|
||||||
result = analyzer.analyzeProgram(program);
|
result = analyzer.analyzeProgram(program);
|
||||||
|
@ -126,9 +128,10 @@ describe('DecorationAnalyzer', () => {
|
||||||
it('should analyze an internally imported component, which is not publicly exported from the entry-point',
|
it('should analyze an internally imported component, which is not publicly exported from the entry-point',
|
||||||
() => {
|
() => {
|
||||||
const program = makeProgram(...INTERNAL_COMPONENT_PROGRAM);
|
const program = makeProgram(...INTERNAL_COMPONENT_PROGRAM);
|
||||||
|
const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
|
||||||
|
const referencesRegistry = new NgccReferencesRegistry(host);
|
||||||
const analyzer = new DecorationAnalyzer(
|
const analyzer = new DecorationAnalyzer(
|
||||||
program.getTypeChecker(), new Esm2015ReflectionHost(false, program.getTypeChecker()),
|
program.getTypeChecker(), host, referencesRegistry, [''], false);
|
||||||
[''], false);
|
|
||||||
const testHandler = createTestHandler();
|
const testHandler = createTestHandler();
|
||||||
analyzer.handlers = [testHandler];
|
analyzer.handlers = [testHandler];
|
||||||
const result = analyzer.analyzeProgram(program);
|
const result = analyzer.analyzeProgram(program);
|
||||||
|
@ -142,9 +145,10 @@ describe('DecorationAnalyzer', () => {
|
||||||
|
|
||||||
it('should analyze an internally defined component, which is not exported at all', () => {
|
it('should analyze an internally defined component, which is not exported at all', () => {
|
||||||
const program = makeProgram(...INTERNAL_COMPONENT_PROGRAM);
|
const program = makeProgram(...INTERNAL_COMPONENT_PROGRAM);
|
||||||
const analyzer = new DecorationAnalyzer(
|
const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
|
||||||
program.getTypeChecker(), new Esm2015ReflectionHost(false, program.getTypeChecker()),
|
const referencesRegistry = new NgccReferencesRegistry(host);
|
||||||
[''], false);
|
const analyzer =
|
||||||
|
new DecorationAnalyzer(program.getTypeChecker(), host, referencesRegistry, [''], false);
|
||||||
const testHandler = createTestHandler();
|
const testHandler = createTestHandler();
|
||||||
analyzer.handlers = [testHandler];
|
analyzer.handlers = [testHandler];
|
||||||
const result = analyzer.analyzeProgram(program);
|
const result = analyzer.analyzeProgram(program);
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
* @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 {Reference, TypeScriptReflectionHost, staticallyResolve} from '../../../ngtsc/metadata';
|
||||||
|
import {getDeclaration, makeProgram} from '../../../ngtsc/testing/in_memory_typescript';
|
||||||
|
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
|
||||||
|
|
||||||
|
describe('NgccReferencesRegistry', () => {
|
||||||
|
it('should return a mapping from resolved reference identifiers to their declarations', () => {
|
||||||
|
const {program} = makeProgram([{
|
||||||
|
name: 'index.ts',
|
||||||
|
contents: `
|
||||||
|
export class SomeClass {}
|
||||||
|
export function someFunction() {}
|
||||||
|
export const someVariable = 42;
|
||||||
|
|
||||||
|
export const testArray = [SomeClass, someFunction, someVariable];
|
||||||
|
`
|
||||||
|
}]);
|
||||||
|
|
||||||
|
const checker = program.getTypeChecker();
|
||||||
|
|
||||||
|
const testArrayDeclaration =
|
||||||
|
getDeclaration(program, 'index.ts', 'testArray', ts.isVariableDeclaration);
|
||||||
|
const someClassDecl = getDeclaration(program, 'index.ts', 'SomeClass', ts.isClassDeclaration);
|
||||||
|
const someFunctionDecl =
|
||||||
|
getDeclaration(program, 'index.ts', 'someFunction', ts.isFunctionDeclaration);
|
||||||
|
const someVariableDecl =
|
||||||
|
getDeclaration(program, 'index.ts', 'someVariable', ts.isVariableDeclaration);
|
||||||
|
const testArrayExpression = testArrayDeclaration.initializer !;
|
||||||
|
|
||||||
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
|
const registry = new NgccReferencesRegistry(host);
|
||||||
|
|
||||||
|
const references =
|
||||||
|
staticallyResolve(testArrayExpression, host, checker) as Reference<ts.Declaration>[];
|
||||||
|
registry.add(...references);
|
||||||
|
|
||||||
|
const map = registry.getDeclarationMap();
|
||||||
|
expect(map.size).toEqual(2);
|
||||||
|
expect(map.get(someClassDecl.name !) !.node).toBe(someClassDecl);
|
||||||
|
expect(map.get(someFunctionDecl.name !) !.node).toBe(someFunctionDecl);
|
||||||
|
expect(map.has(someVariableDecl.name as ts.Identifier)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
|
@ -12,6 +12,7 @@ import MagicString from 'magic-string';
|
||||||
import {fromObject, generateMapFileComment} from 'convert-source-map';
|
import {fromObject, generateMapFileComment} from 'convert-source-map';
|
||||||
import {makeProgram} from '../helpers/utils';
|
import {makeProgram} from '../helpers/utils';
|
||||||
import {CompiledClass, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
|
import {CompiledClass, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
|
||||||
|
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
|
||||||
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
|
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
|
||||||
import {BundleInfo, createBundleInfo} from '../../src/packages/bundle';
|
import {BundleInfo, createBundleInfo} from '../../src/packages/bundle';
|
||||||
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
|
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
|
||||||
|
@ -46,8 +47,10 @@ function createTestRenderer(
|
||||||
options.rewriteCoreImportsTo ? program.getSourceFile(options.rewriteCoreImportsTo) ! : null;
|
options.rewriteCoreImportsTo ? program.getSourceFile(options.rewriteCoreImportsTo) ! : null;
|
||||||
const bundle = createBundleInfo(options.isCore || false, rewriteCoreImportsTo, null);
|
const bundle = createBundleInfo(options.isCore || false, rewriteCoreImportsTo, null);
|
||||||
const host = new Esm2015ReflectionHost(bundle.isCore, program.getTypeChecker());
|
const host = new Esm2015ReflectionHost(bundle.isCore, program.getTypeChecker());
|
||||||
|
const referencesRegistry = new NgccReferencesRegistry(host);
|
||||||
const decorationAnalyses =
|
const decorationAnalyses =
|
||||||
new DecorationAnalyzer(program.getTypeChecker(), host, [''], bundle.isCore)
|
new DecorationAnalyzer(
|
||||||
|
program.getTypeChecker(), host, referencesRegistry, [''], bundle.isCore)
|
||||||
.analyzeProgram(program);
|
.analyzeProgram(program);
|
||||||
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program);
|
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program);
|
||||||
const renderer = new TestRenderer(host, bundle);
|
const renderer = new TestRenderer(host, bundle);
|
||||||
|
|
|
@ -15,4 +15,5 @@ export {DirectiveDecoratorHandler} from './src/directive';
|
||||||
export {InjectableDecoratorHandler} from './src/injectable';
|
export {InjectableDecoratorHandler} from './src/injectable';
|
||||||
export {NgModuleDecoratorHandler} from './src/ng_module';
|
export {NgModuleDecoratorHandler} from './src/ng_module';
|
||||||
export {PipeDecoratorHandler} from './src/pipe';
|
export {PipeDecoratorHandler} from './src/pipe';
|
||||||
|
export {NoopReferencesRegistry, ReferencesRegistry} from './src/references_registry';
|
||||||
export {CompilationScope, SelectorScopeRegistry} from './src/selector_scope';
|
export {CompilationScope, SelectorScopeRegistry} from './src/selector_scope';
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {Reference, ResolvedReference, ResolvedValue, reflectObjectLiteral, stati
|
||||||
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
|
||||||
|
|
||||||
import {generateSetClassMetadataCall} from './metadata';
|
import {generateSetClassMetadataCall} from './metadata';
|
||||||
|
import {ReferencesRegistry} from './references_registry';
|
||||||
import {SelectorScopeRegistry} from './selector_scope';
|
import {SelectorScopeRegistry} from './selector_scope';
|
||||||
import {getConstructorDependencies, isAngularCore, toR3Reference, unwrapExpression} from './util';
|
import {getConstructorDependencies, isAngularCore, toR3Reference, unwrapExpression} from './util';
|
||||||
|
|
||||||
|
@ -32,7 +33,8 @@ export interface NgModuleAnalysis {
|
||||||
export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalysis, Decorator> {
|
export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalysis, Decorator> {
|
||||||
constructor(
|
constructor(
|
||||||
private checker: ts.TypeChecker, private reflector: ReflectionHost,
|
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 {
|
detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined {
|
||||||
if (!decorators) {
|
if (!decorators) {
|
||||||
|
@ -72,6 +74,7 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||||
const expr = ngModule.get('declarations') !;
|
const expr = ngModule.get('declarations') !;
|
||||||
const declarationMeta = staticallyResolve(expr, this.reflector, this.checker);
|
const declarationMeta = staticallyResolve(expr, this.reflector, this.checker);
|
||||||
declarations = this.resolveTypeList(expr, declarationMeta, 'declarations');
|
declarations = this.resolveTypeList(expr, declarationMeta, 'declarations');
|
||||||
|
this.referencesRegistry.add(...declarations);
|
||||||
}
|
}
|
||||||
let imports: Reference<ts.Declaration>[] = [];
|
let imports: Reference<ts.Declaration>[] = [];
|
||||||
if (ngModule.has('imports')) {
|
if (ngModule.has('imports')) {
|
||||||
|
@ -80,6 +83,7 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||||
expr, this.reflector, this.checker,
|
expr, this.reflector, this.checker,
|
||||||
ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
|
ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
|
||||||
imports = this.resolveTypeList(expr, importsMeta, 'imports');
|
imports = this.resolveTypeList(expr, importsMeta, 'imports');
|
||||||
|
this.referencesRegistry.add(...imports);
|
||||||
}
|
}
|
||||||
let exports: Reference<ts.Declaration>[] = [];
|
let exports: Reference<ts.Declaration>[] = [];
|
||||||
if (ngModule.has('exports')) {
|
if (ngModule.has('exports')) {
|
||||||
|
@ -88,12 +92,14 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||||
expr, this.reflector, this.checker,
|
expr, this.reflector, this.checker,
|
||||||
ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
|
ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
|
||||||
exports = this.resolveTypeList(expr, exportsMeta, 'exports');
|
exports = this.resolveTypeList(expr, exportsMeta, 'exports');
|
||||||
|
this.referencesRegistry.add(...exports);
|
||||||
}
|
}
|
||||||
let bootstrap: Reference<ts.Declaration>[] = [];
|
let bootstrap: Reference<ts.Declaration>[] = [];
|
||||||
if (ngModule.has('bootstrap')) {
|
if (ngModule.has('bootstrap')) {
|
||||||
const expr = ngModule.get('bootstrap') !;
|
const expr = ngModule.get('bootstrap') !;
|
||||||
const bootstrapMeta = staticallyResolve(expr, this.reflector, this.checker);
|
const bootstrapMeta = staticallyResolve(expr, this.reflector, this.checker);
|
||||||
bootstrap = this.resolveTypeList(expr, bootstrapMeta, 'bootstrap');
|
bootstrap = this.resolveTypeList(expr, bootstrapMeta, 'bootstrap');
|
||||||
|
this.referencesRegistry.add(...bootstrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register this module's information with the SelectorScopeRegistry. This ensures that during
|
// 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 * as api from '../transformers/api';
|
||||||
import {nocollapseHack} from '../transformers/nocollapse_hack';
|
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 {BaseDefDecoratorHandler} from './annotations/src/base_def';
|
||||||
import {TypeScriptReflectionHost} from './metadata';
|
import {TypeScriptReflectionHost} from './metadata';
|
||||||
import {FileResourceLoader, HostResourceLoader} from './resource_loader';
|
import {FileResourceLoader, HostResourceLoader} from './resource_loader';
|
||||||
|
@ -214,6 +214,7 @@ export class NgtscProgram implements api.Program {
|
||||||
private makeCompilation(): IvyCompilation {
|
private makeCompilation(): IvyCompilation {
|
||||||
const checker = this.tsProgram.getTypeChecker();
|
const checker = this.tsProgram.getTypeChecker();
|
||||||
const scopeRegistry = new SelectorScopeRegistry(checker, this.reflector);
|
const scopeRegistry = new SelectorScopeRegistry(checker, this.reflector);
|
||||||
|
const referencesRegistry = new NoopReferencesRegistry();
|
||||||
|
|
||||||
// Set up the IvyCompilation, which manages state for the Ivy transformer.
|
// Set up the IvyCompilation, which manages state for the Ivy transformer.
|
||||||
const handlers = [
|
const handlers = [
|
||||||
|
@ -223,7 +224,8 @@ export class NgtscProgram implements api.Program {
|
||||||
this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false),
|
this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false),
|
||||||
new DirectiveDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
|
new DirectiveDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
|
||||||
new InjectableDecoratorHandler(this.reflector, 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),
|
new PipeDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue