fix(ivy): deduplicate directives in component scopes (#27462)

A previous fix to ngtsc opened the door for duplicate directives in
the 'directives' array of a component. This would happen if the directive
was declared in a module which was imported more than once within the
component's module.

This commit adds deduplication when the component's scope is materialized,
so declarations which arrive via more than one module import are coalesced.

PR Close #27462
This commit is contained in:
Alex Rickabaugh
2018-12-04 09:42:44 -08:00
committed by Igor Minar
parent b82f62a11d
commit dfdaaf6a0d
4 changed files with 74 additions and 23 deletions

View File

@ -60,4 +60,7 @@ export function forwardRef<T>(fn: () => T): T {
return fn();
}
export interface SimpleChanges { [propName: string]: any; }
export interface SimpleChanges { [propName: string]: any; }
export type ɵNgModuleDefWithMeta<ModuleT, DeclarationsT, ImportsT, ExportsT> = any;
export type ɵDirectiveDefWithMeta<DirT, SelectorT, ExportAsT, InputsT, OutputsT, QueriesT> = any;

View File

@ -1078,4 +1078,40 @@ describe('ngtsc behavioral tests', () => {
// Success is enough to indicate that this passes.
});
it('should not emit multiple references to the same directive', () => {
env.tsconfig();
env.write('node_modules/external/index.d.ts', `
import {ɵDirectiveDefWithMeta, ɵNgModuleDefWithMeta} from '@angular/core';
export declare class ExternalDir {
static ngDirectiveDef: ɵDirectiveDefWithMeta<ExternalDir, '[test]', never, never, never, never>;
}
export declare class ExternalModule {
static ngModuleDef: ɵNgModuleDefWithMeta<ExternalModule, [typeof ExternalDir], never, [typeof ExternalDir]>;
}
`);
env.write('test.ts', `
import {Component, Directive, NgModule} from '@angular/core';
import {ExternalModule} from 'external';
@Component({
template: '<div test></div>',
})
class Cmp {}
@NgModule({
declarations: [Cmp],
// Multiple imports of the same module used to result in duplicate directive references
// in the output.
imports: [ExternalModule, ExternalModule],
})
class Module {}
`);
env.driveMain();
const jsContents = env.getContents('test.js');
expect(jsContents).toMatch(/directives: \[i1\.ExternalDir\]/);
});
});