feat(ivy): produce diagnostics for missing exports, incorrect entrypoint (#27743)

This commit adds tracking of modules, directives, and pipes which are made
visible to consumers through NgModules exported from the package entrypoint.
ngtsc will now produce a diagnostic if such classes are not themselves
exported via the entrypoint (as this is a requirement for downstream
consumers to use them with Ivy).

To accomplish this, a graph of references is created and populated via the
ReferencesRegistry. Symbols exported via the package entrypoint are compared
against the graph to determine if any publicly visible symbols are not
properly exported. Diagnostics are produced for each one which also show the
path by which they become visible.

This commit also introduces a diagnostic (instead of a hard compiler crash)
if an entrypoint file cannot be correctly determined.

PR Close #27743
This commit is contained in:
Alex Rickabaugh
2018-12-13 11:52:20 -08:00
committed by Kara Erickson
parent ac157170c8
commit 0b9094ec63
22 changed files with 597 additions and 66 deletions

View File

@ -75,7 +75,6 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
const expr = ngModule.get('declarations') !;
const declarationMeta = this.evaluator.evaluate(expr);
declarations = this.resolveTypeList(expr, declarationMeta, 'declarations');
this.referencesRegistry.add(...declarations);
}
let imports: Reference<ts.Declaration>[] = [];
if (ngModule.has('imports')) {
@ -83,7 +82,6 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
const importsMeta = this.evaluator.evaluate(
expr, ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
imports = this.resolveTypeList(expr, importsMeta, 'imports');
this.referencesRegistry.add(...imports);
}
let exports: Reference<ts.Declaration>[] = [];
if (ngModule.has('exports')) {
@ -91,14 +89,13 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
const exportsMeta = this.evaluator.evaluate(
expr, ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
exports = this.resolveTypeList(expr, exportsMeta, 'exports');
this.referencesRegistry.add(...exports);
this.referencesRegistry.add(node, ...exports);
}
let bootstrap: Reference<ts.Declaration>[] = [];
if (ngModule.has('bootstrap')) {
const expr = ngModule.get('bootstrap') !;
const bootstrapMeta = this.evaluator.evaluate(expr);
bootstrap = this.resolveTypeList(expr, bootstrapMeta, 'bootstrap');
this.referencesRegistry.add(...bootstrap);
}
// Register this module's information with the SelectorScopeRegistry. This ensures that during

View File

@ -17,15 +17,9 @@ import {Declaration} from '../../reflection';
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>;
add(source: ts.Declaration, ...references: Reference<ts.Declaration>[]): void;
}
/**
@ -34,6 +28,5 @@ export interface ReferencesRegistry {
* 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(); }
add(source: ts.Declaration, ...references: Reference<ts.Declaration>[]): void {}
}