New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(core): add input and output filtering for host directives #47536
Conversation
tView: TView, lView: LView, | ||
tNode: TElementNode|TContainerNode|TElementContainerNode): DirectiveDef<unknown>[]|null { | ||
tView: TView, lView: LView, tNode: TElementNode|TContainerNode|TElementContainerNode): | ||
[matches: DirectiveDef<unknown>[], definitionMap: HostDirectiveDefinitionMap|null]|null { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a fan of having this return an array when it might not need to, but I couldn't find a better way of producing two results from findDirectiveDefMatches
. Some of the considered alternatives:
- Having a separate function that is called inside
resolveDirectives
that produces the map. The problem with this is that we don't have a way of distinguishing which matches came from host directives versus selector matching. - Create the definition map inside
resolveDirectives
and pass it intofindDirectiveDefMatches
. This would work, but we might produce the binding map and not use it. - Inverting the selector matching logic. We decided against doing so here refactor(core): generate initial inputs from inputs map #47228 (review).
- Have
findDirectiveDefMatches
return something likeDirectiveDef[] | {matches: DirectiveDef[], mappings: HostDirectiveDefinitionMap} | null
. This should be viable, but I'm not sure about the perf implications of generating object literals instead of arrays.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just as an idea, we can pass an object as an accumulator into the findDirectiveDefMatches
function, for example:
const accumulator = {matchedDefs: null, hostDirectiveDefs: null};
collectDirectiveDefMatches(accumulator, ...);
I think the current approach is fine too, we do have the assertFirstCreatePass
at the very beginning of the function, so we guarantee to invoke the function only once per component (at creation time), so it should not affect the performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was one of the approaches I was considering, but I decided against it because we'd be creating the object even if we don't need it. That being said, I feel like I've been microoptimizing a bit here.
f962853
to
31f98fc
Compare
* Mapping between a directive that was used as a host directive | ||
* and the configuration that was used to define it as such. | ||
*/ | ||
export type HostDirectiveDefinitionMap = Map<DirectiveDef<unknown>, HostDirectiveDef>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was struggling a bit with how to name this so I'm open to suggestions.
The feedback has been addressed. |
31f98fc
to
e35a2b2
Compare
@@ -412,12 +417,27 @@ export interface HostDirectiveDef<T = unknown> { | |||
directive: Type<T>; | |||
|
|||
/** Directive inputs that have been exposed. */ | |||
inputs: {[publicName: string]: string}; | |||
inputs: HostDirectiveBindingMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I'm not mistaken, the inputs
/ outputs
field is applicable to directives that don't have any host directives applied to them, right? If so, I find the name HostDirectiveBindingMap
misleading here. It is more about input / output aliasing, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does two things:
- It acts as an allowlist for the inputs/outputs that are exposed.
- It's used to remap the public name.
I was struggling with how to capture this in the name of the symbol so I went with something more generic like "binding".
e273fe1
to
00f83ad
Compare
I ended up squashing the commits so it's easier to rebase the changes from #47530. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall.
Personally I had a different design on my mind where the feature is patching setInput
and more of the code goes into the feature itself. But this would mean substantial re-design / re-write.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Reviewed-for: size-tracking
Reviewed-for: fw-core
Adds the logic that will filter out unexposed inputs/outputs and apply the aliases that the author specified when writing the host directives.
00f83ad
to
a3571ce
Compare
This PR was merged into the repository by commit 76a8c68. |
…ngular#47536) Adds the logic that will filter out unexposed inputs/outputs and apply the aliases that the author specified when writing the host directives. PR Close angular#47536
…ngular#47536) Adds the logic that will filter out unexposed inputs/outputs and apply the aliases that the author specified when writing the host directives. PR Close angular#47536
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Adds the logic that will filter out unexposed inputs/outputs and apply the aliases that the author specified when writing the host directives.