fix(ngcc): handle imports in dts files when processing CommonJS (#35191)

When statically evaluating CommonJS code it is possible to find that we
are looking for the declaration of an identifier that actually came from
a typings file (rather than a CommonJS file).

Previously, the CommonJS reflection host would always try to use a
CommonJS specific algorithm for finding identifier declarations, but
when the id is actually in a typings file this resulted in the returned
declaration being the containing file of the declaration rather than the
declaration itself.

Now the CommonJS reflection host will check to see if the file
containing the identifier is a typings file and use the appropriate
stategy.

(Note: This is the equivalent of #34356 but for CommonJS.)

PR Close #35191
This commit is contained in:
George Kalpakas 2020-02-10 19:25:36 +02:00 committed by Miško Hevery
parent d7d359e3ee
commit b6e8847967
3 changed files with 36 additions and 6 deletions

View File

@ -47,7 +47,8 @@ export class CommonJsReflectionHost extends Esm5ReflectionHost {
} }
getDeclarationOfIdentifier(id: ts.Identifier): Declaration|null { getDeclarationOfIdentifier(id: ts.Identifier): Declaration|null {
return this.getCommonJsImportedDeclaration(id) || super.getDeclarationOfIdentifier(id); return (!id.getSourceFile().isDeclarationFile && this.getCommonJsImportedDeclaration(id)) ||
super.getDeclarationOfIdentifier(id);
} }
getExportsOfModule(module: ts.Node): Map<string, Declaration>|null { getExportsOfModule(module: ts.Node): Map<string, Declaration>|null {

View File

@ -1786,6 +1786,39 @@ exports.ExternalModule = ExternalModule;
const importOfIdent = host.getDeclarationOfIdentifier(identifier !) !; const importOfIdent = host.getDeclarationOfIdentifier(identifier !) !;
expect(importOfIdent.viaModule).toBe('lib'); expect(importOfIdent.viaModule).toBe('lib');
}); });
it('should return the correct declaration of an identifier imported in a typings file',
() => {
const files = [
{
name: _('/node_modules/test-package/index.d.ts'),
contents: `
import {SubModule} from 'sub_module';
export const x = SubModule;
`,
},
{
name: _('/node_modules/sub_module/index.d.ts'),
contents: 'export class SubModule {}',
}
];
loadTestFiles(files);
const bundle = makeTestBundleProgram(files[0].name);
const host = new CommonJsReflectionHost(new MockLogger(), false, bundle);
const expectedDeclaration = getDeclaration(
bundle.program, files[1].name, 'SubModule', isNamedClassDeclaration);
const x =
getDeclaration(bundle.program, files[0].name, 'x', isNamedVariableDeclaration);
if (x.initializer === undefined || !ts.isIdentifier(x.initializer)) {
return fail('Expected constant `x` to have an identifer as an initializer.');
}
const decl = host.getDeclarationOfIdentifier(x.initializer);
if (decl === null) {
return fail('Expected to find a declaration for ' + x.initializer.getText());
}
expect(decl.viaModule).toEqual('sub_module');
expect(decl.node).toBe(expectedDeclaration);
});
}); });
describe('getExportsOfModule()', () => { describe('getExportsOfModule()', () => {

View File

@ -1916,10 +1916,6 @@ runInEachFileSystem(() => {
export const x = SubModule; export const x = SubModule;
`, `,
}, },
{
name: _('/node_modules/packages.json'),
contents: '{ "typings: "index.d.ts" }',
},
{ {
name: _('/node_modules/sub_module/index.d.ts'), name: _('/node_modules/sub_module/index.d.ts'),
contents: `export class SubModule {}`, contents: `export class SubModule {}`,
@ -1929,7 +1925,7 @@ runInEachFileSystem(() => {
const bundle = makeTestBundleProgram(FILES[0].name); const bundle = makeTestBundleProgram(FILES[0].name);
const host = new UmdReflectionHost(new MockLogger(), false, bundle); const host = new UmdReflectionHost(new MockLogger(), false, bundle);
const expectedDeclaration = const expectedDeclaration =
getDeclaration(bundle.program, FILES[2].name, 'SubModule', isNamedClassDeclaration); getDeclaration(bundle.program, FILES[1].name, 'SubModule', isNamedClassDeclaration);
const x = getDeclaration(bundle.program, FILES[0].name, 'x', isNamedVariableDeclaration); const x = getDeclaration(bundle.program, FILES[0].name, 'x', isNamedVariableDeclaration);
if (x.initializer === undefined || !ts.isIdentifier(x.initializer)) { if (x.initializer === undefined || !ts.isIdentifier(x.initializer)) {
return fail('Expected constant `x` to have an identifer as an initializer.'); return fail('Expected constant `x` to have an identifer as an initializer.');