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:

committed by
Kara Erickson

parent
ac157170c8
commit
0b9094ec63
@ -62,7 +62,8 @@ export class ModuleWithProvidersAnalyzer {
|
||||
`The referenced NgModule in ${fn.declaration.getText()} is not a class declaration in the typings program; instead we get ${dtsNgModule.getText()}`);
|
||||
}
|
||||
// Record the usage of the internal module as it needs to become an exported symbol
|
||||
this.referencesRegistry.add(new ResolvedReference(ngModule.node, fn.ngModule));
|
||||
this.referencesRegistry.add(
|
||||
ngModule.node, new ResolvedReference(ngModule.node, fn.ngModule));
|
||||
|
||||
ngModule = {node: dtsNgModule, viaModule: null};
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ export class NgccReferencesRegistry implements ReferencesRegistry {
|
||||
* Only `ResolveReference` references are stored. Other types are ignored.
|
||||
* @param references A collection of references to register.
|
||||
*/
|
||||
add(...references: Reference<ts.Declaration>[]): void {
|
||||
add(source: ts.Declaration, ...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)) {
|
||||
|
@ -7,10 +7,10 @@
|
||||
*/
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ReferencesRegistry} from '../../../ngtsc/annotations';
|
||||
import {Declaration} from '../../../ngtsc/reflection';
|
||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||
import {hasNameIdentifier, isDefined} from '../utils';
|
||||
import {NgccReferencesRegistry} from './ngcc_references_registry';
|
||||
|
||||
export interface ExportInfo {
|
||||
identifier: string;
|
||||
@ -24,7 +24,8 @@ export type PrivateDeclarationsAnalyses = ExportInfo[];
|
||||
* (i.e. on an NgModule) that are not publicly exported via an entry-point.
|
||||
*/
|
||||
export class PrivateDeclarationsAnalyzer {
|
||||
constructor(private host: NgccReflectionHost, private referencesRegistry: ReferencesRegistry) {}
|
||||
constructor(
|
||||
private host: NgccReflectionHost, private referencesRegistry: NgccReferencesRegistry) {}
|
||||
|
||||
analyzeProgram(program: ts.Program): PrivateDeclarationsAnalyses {
|
||||
const rootFiles = this.getRootFiles(program);
|
||||
|
@ -137,15 +137,18 @@ describe('PrivateDeclarationsAnalyzer', () => {
|
||||
const publicComponentDeclaration =
|
||||
getDeclaration(program, '/src/a.js', 'PublicComponent', ts.isClassDeclaration);
|
||||
referencesRegistry.add(
|
||||
null !,
|
||||
new ResolvedReference(publicComponentDeclaration, publicComponentDeclaration.name !));
|
||||
const privateComponentDeclaration =
|
||||
getDeclaration(program, '/src/b.js', 'PrivateComponent', ts.isClassDeclaration);
|
||||
referencesRegistry.add(new ResolvedReference(
|
||||
privateComponentDeclaration, privateComponentDeclaration.name !));
|
||||
referencesRegistry.add(
|
||||
null !, new ResolvedReference(
|
||||
privateComponentDeclaration, privateComponentDeclaration.name !));
|
||||
const internalComponentDeclaration =
|
||||
getDeclaration(program, '/src/c.js', 'InternalComponent', ts.isClassDeclaration);
|
||||
referencesRegistry.add(new ResolvedReference(
|
||||
internalComponentDeclaration, internalComponentDeclaration.name !));
|
||||
referencesRegistry.add(
|
||||
null !, new ResolvedReference(
|
||||
internalComponentDeclaration, internalComponentDeclaration.name !));
|
||||
|
||||
const analyses = analyzer.analyzeProgram(program);
|
||||
expect(analyses.length).toEqual(2);
|
||||
|
@ -43,7 +43,7 @@ describe('NgccReferencesRegistry', () => {
|
||||
const registry = new NgccReferencesRegistry(host);
|
||||
|
||||
const references = evaluator.evaluate(testArrayExpression) as Reference<ts.Declaration>[];
|
||||
registry.add(...references);
|
||||
registry.add(null !, ...references);
|
||||
|
||||
const map = registry.getDeclarationMap();
|
||||
expect(map.size).toEqual(2);
|
||||
|
Reference in New Issue
Block a user