fix(ivy): support multiple directives with the same selector (#27298)

Previously the concept of multiple directives with the same selector was
not supported by ngtsc. This is due to the treatment of directives for a
component as a Map from selector to the directive, which is an erroneous
representation.

Now the directives for a component are stored as an array which supports
multiple directives with the same selector.

Testing strategy: a new ngtsc_spec test asserts that multiple directives
with the same selector are matched on an element.

PR Close #27298
This commit is contained in:
Alex Rickabaugh
2018-11-20 17:20:16 +01:00
committed by Igor Minar
parent c331fc6f0c
commit 412e47d311
9 changed files with 55 additions and 28 deletions

View File

@ -128,7 +128,7 @@ export interface R3ComponentMetadataFacade extends R3DirectiveMetadataFacade {
animations: any[]|undefined;
viewQueries: R3QueryMetadataFacade[];
pipes: Map<string, any>;
directives: Map<string, any>;
directives: {selector: string, expression: any}[];
styles: string[];
encapsulation: ViewEncapsulation;
viewProviders: Provider[]|null;

View File

@ -153,10 +153,10 @@ export interface R3ComponentMetadata extends R3DirectiveMetadata {
pipes: Map<string, o.Expression>;
/**
* A map of directive selectors to an expression referencing the directive type which are in the
* A list of directive selectors and an expression referencing the directive type which are in the
* scope of the compilation.
*/
directives: Map<string, o.Expression>;
directives: {selector: string, expression: o.Expression}[];
/**
* Whether to wrap the 'directives' and/or `pipes` array, if one is generated, in a closure.

View File

@ -231,11 +231,11 @@ export function compileComponentFromMetadata(
// Generate the CSS matcher that recognize directive
let directiveMatcher: SelectorMatcher|null = null;
if (meta.directives.size) {
if (meta.directives.length > 0) {
const matcher = new SelectorMatcher();
meta.directives.forEach((expression, selector: string) => {
for (const {selector, expression} of meta.directives) {
matcher.addSelectables(CssSelector.parse(selector), expression);
});
}
directiveMatcher = matcher;
}
@ -375,7 +375,7 @@ export function compileComponentFromRender2(
ngContentSelectors: render3Ast.ngContentSelectors,
relativeContextFilePath: '',
},
directives: typeMapToExpressionMap(directiveTypeBySel, outputCtx),
directives: [],
pipes: typeMapToExpressionMap(pipeTypeByName, outputCtx),
viewQueries: queriesFromGlobalMetadata(component.viewQueries, outputCtx),
wrapDirectivesAndPipesInClosure: false,