feat(ivy): pass information about used directive selectors on elements (#31782)

Extend indexing API interface to provide information about used
directives' selectors on template elements. This enables an indexer to
xref element attributes to the directives that match them.

The current way this matching is done is by mapping selectors to indexed
directives. However, this fails in cases where the directive is not
indexed by the indexer API, like for transitive dependencies. This
solution is much more general.

PR Close #31782
This commit is contained in:
Ayaz Hafiz 2019-07-22 10:24:43 -07:00 committed by Misko Hevery
parent a445826dad
commit 44039a4b16
3 changed files with 27 additions and 3 deletions

View File

@ -8,6 +8,7 @@
import {ParseSourceFile} from '@angular/compiler';
import * as ts from 'typescript';
import {ClassDeclaration} from '../../reflection';
/**
* Describes the kind of identifier found in a template.
@ -38,6 +39,11 @@ export interface MethodIdentifier extends TemplateIdentifier { kind: IdentifierK
/** Describes an element attribute in a template. */
export interface AttributeIdentifier extends TemplateIdentifier { kind: IdentifierKind.Attribute; }
/** A reference to a directive node and its selector. */
interface DirectiveReference {
node: ClassDeclaration;
selector: string;
}
/**
* Describes an indexed element in a template. The name of an `ElementIdentifier` is the entire
* element tag, which can be parsed by an indexer to determine where used directives should be
@ -50,7 +56,7 @@ export interface ElementIdentifier extends TemplateIdentifier {
attributes: Set<AttributeIdentifier>;
/** Directives applied to an element. */
usedDirectives: Set<ts.Declaration>;
usedDirectives: Set<DirectiveReference>;
}
/**

View File

@ -157,7 +157,12 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
span: new AbsoluteSourceSpan(start, start + name.length),
kind: IdentifierKind.Element,
attributes: new Set(attributes),
usedDirectives: new Set(usedDirectives.map(dir => dir.ref.node)),
usedDirectives: new Set(usedDirectives.map(dir => {
return {
node: dir.ref.node,
selector: dir.selector,
};
})),
};
this.identifiers.add(elId);

View File

@ -246,7 +246,20 @@ runInEachFileSystem(() => {
const refs = getTemplateIdentifiers(boundTemplate);
const [ref] = Array.from(refs);
const usedDirectives = (ref as ElementIdentifier).usedDirectives;
expect(usedDirectives).toEqual(new Set([declA, declB, declC]));
expect(usedDirectives).toEqual(new Set([
{
node: declA,
selector: 'a-selector',
},
{
node: declB,
selector: '[b-selector]',
},
{
node: declC,
selector: ':not(never-selector)',
}
]));
});
});
});