fix(ngcc): correctly match aliased classes between src and dts files (#34254)
The naïve matching algorithm we previously used to match declarations in source files to declarations in typings files was based only on the name of the thing being declared. This did not handle cases where the declared item had been exported via an alias - a common scenario when one of the two file sets (source or typings) has been flattened, while the other has not. The new algorithm tries to overcome this by creating two maps of export name to declaration (i.e. `Map<string, ts.Declaration>`). One for the source files and one for the typings files. It then joins these two together by matching export names, resulting in a new map that maps source declarations to typings declarations directly (i.e. `Map<ts.Declaration, ts.Declaration>`). This new map can handle the declaration names being different between the source and typings as long as they are ultimately both exported with the same alias name. Further more, there is one map for "public exports", i.e. exported via the root of the source tree (the entry-point), and another map for "private exports", which are exported from individual files in the source tree but not necessarily from the root. This second map can be used to "guess" the mapping between exports in a deep (non-flat) file tree, which can be used by ngcc to add required private exports to the entry-point. Fixes #33593 PR Close #34254
This commit is contained in:

committed by
Kara Erickson

parent
e9fb5fdb89
commit
f22a6eb00e
@ -114,7 +114,7 @@ runInEachFileSystem(() => {
|
||||
`import { Directive } from '@angular/core';\nexport class A {\n foo(x) {\n return x;\n }\n}\nA.decorators = [\n { type: Directive, args: [{ selector: '[a]' }] }\n];\n`
|
||||
};
|
||||
INPUT_DTS_PROGRAM = {
|
||||
name: _('/typings/file.d.ts'),
|
||||
name: _('/node_modules/test-package/typings/file.d.ts'),
|
||||
contents: `export declare class A {\nfoo(x: number): number;\n}\n`
|
||||
};
|
||||
});
|
||||
@ -126,7 +126,8 @@ runInEachFileSystem(() => {
|
||||
const result = renderer.renderProgram(
|
||||
decorationAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses);
|
||||
|
||||
const typingsFile = result.find(f => f.path === _('/typings/file.d.ts')) !;
|
||||
const typingsFile =
|
||||
result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts')) !;
|
||||
expect(typingsFile.contents)
|
||||
.toContain(
|
||||
'foo(x: number): number;\n static ɵfac: ɵngcc0.ɵɵFactoryDef<A>;\n static ɵdir: ɵngcc0.ɵɵDirectiveDefWithMeta');
|
||||
@ -139,7 +140,8 @@ runInEachFileSystem(() => {
|
||||
const result = renderer.renderProgram(
|
||||
decorationAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses);
|
||||
|
||||
const typingsFile = result.find(f => f.path === _('/typings/file.d.ts')) !;
|
||||
const typingsFile =
|
||||
result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts')) !;
|
||||
expect(typingsFile.contents).toContain(`\n// ADD IMPORTS\n`);
|
||||
});
|
||||
|
||||
@ -158,7 +160,8 @@ runInEachFileSystem(() => {
|
||||
const result = renderer.renderProgram(
|
||||
decorationAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses);
|
||||
|
||||
const typingsFile = result.find(f => f.path === _('/typings/file.d.ts')) !;
|
||||
const typingsFile =
|
||||
result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts')) !;
|
||||
expect(typingsFile.contents).toContain(`\n// ADD EXPORTS\n`);
|
||||
});
|
||||
|
||||
@ -170,7 +173,8 @@ runInEachFileSystem(() => {
|
||||
const result = renderer.renderProgram(
|
||||
decorationAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses);
|
||||
|
||||
const typingsFile = result.find(f => f.path === _('/typings/file.d.ts')) !;
|
||||
const typingsFile =
|
||||
result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts')) !;
|
||||
expect(typingsFile.contents).toContain(`\n// ADD MODUlE WITH PROVIDERS PARAMS\n`);
|
||||
});
|
||||
});
|
||||
|
@ -483,7 +483,7 @@ export { D };
|
||||
beforeEach(() => {
|
||||
MODULE_WITH_PROVIDERS_PROGRAM = [
|
||||
{
|
||||
name: _('/src/index.js'),
|
||||
name: _('/node_modules/test-package/src/index.js'),
|
||||
contents: `
|
||||
import {ExternalModule} from './module';
|
||||
import {LibraryModule} from 'some-library';
|
||||
@ -510,7 +510,7 @@ export { D };
|
||||
`
|
||||
},
|
||||
{
|
||||
name: _('/src/module.js'),
|
||||
name: _('/node_modules/test-package/src/module.js'),
|
||||
contents: `
|
||||
export class ExternalModule {
|
||||
static withProviders1() { return {ngModule: ExternalModule}; }
|
||||
@ -525,7 +525,7 @@ export { D };
|
||||
|
||||
MODULE_WITH_PROVIDERS_DTS_PROGRAM = [
|
||||
{
|
||||
name: _('/typings/index.d.ts'),
|
||||
name: _('/node_modules/test-package/typings/index.d.ts'),
|
||||
contents: `
|
||||
import {ModuleWithProviders} from '@angular/core';
|
||||
export declare class SomeClass {}
|
||||
@ -552,7 +552,7 @@ export { D };
|
||||
`
|
||||
},
|
||||
{
|
||||
name: _('/typings/module.d.ts'),
|
||||
name: _('/node_modules/test-package/typings/module.d.ts'),
|
||||
contents: `
|
||||
export interface ModuleWithProviders {}
|
||||
export declare class ExternalModule {
|
||||
@ -575,7 +575,8 @@ export { D };
|
||||
const moduleWithProvidersAnalyses =
|
||||
new ModuleWithProvidersAnalyzer(host, referencesRegistry, true)
|
||||
.analyzeProgram(bundle.src.program);
|
||||
const typingsFile = getSourceFileOrError(bundle.dts !.program, _('/typings/index.d.ts'));
|
||||
const typingsFile = getSourceFileOrError(
|
||||
bundle.dts !.program, _('/node_modules/test-package/typings/index.d.ts'));
|
||||
const moduleWithProvidersInfo = moduleWithProvidersAnalyses.get(typingsFile) !;
|
||||
|
||||
const output = new MagicString(MODULE_WITH_PROVIDERS_DTS_PROGRAM[0].contents);
|
||||
@ -611,8 +612,8 @@ export { D };
|
||||
const moduleWithProvidersAnalyses =
|
||||
new ModuleWithProvidersAnalyzer(host, referencesRegistry, true)
|
||||
.analyzeProgram(bundle.src.program);
|
||||
const typingsFile =
|
||||
getSourceFileOrError(bundle.dts !.program, _('/typings/module.d.ts'));
|
||||
const typingsFile = getSourceFileOrError(
|
||||
bundle.dts !.program, _('/node_modules/test-package/typings/module.d.ts'));
|
||||
const moduleWithProvidersInfo = moduleWithProvidersAnalyses.get(typingsFile) !;
|
||||
|
||||
const output = new MagicString(MODULE_WITH_PROVIDERS_DTS_PROGRAM[1].contents);
|
||||
|
Reference in New Issue
Block a user