7
7
*/
8
8
import { resolveForwardRef } from '../../di' ;
9
9
import { RuntimeError , RuntimeErrorCode } from '../../errors' ;
10
- import { Type } from '../../interface/type' ;
11
10
import { assertEqual } from '../../util/assert' ;
12
11
import { EMPTY_OBJ } from '../../util/empty' ;
13
12
import { getComponentDef , getDirectiveDef } from '../definition' ;
14
- import {
13
+ import type {
15
14
DirectiveDef ,
16
15
DirectiveDefFeature ,
17
16
HostDirectiveBindingMap ,
17
+ HostDirectiveConfig ,
18
18
HostDirectiveDef ,
19
19
HostDirectiveDefs ,
20
20
} from '../interfaces/definition' ;
21
21
22
- /** Values that can be used to define a host directive through the `HostDirectivesFeature`. */
23
- type HostDirectiveConfig =
24
- | Type < unknown >
25
- | {
26
- directive : Type < unknown > ;
27
- inputs ?: string [ ] ;
28
- outputs ?: string [ ] ;
29
- } ;
30
-
31
22
/**
32
23
* This feature adds the host directives behavior to a directive definition by patching a
33
24
* function onto it. The expectation is that the runtime will invoke the function during
@@ -52,22 +43,17 @@ export function ɵɵHostDirectivesFeature(
52
43
rawHostDirectives : HostDirectiveConfig [ ] | ( ( ) => HostDirectiveConfig [ ] ) ,
53
44
) {
54
45
const feature : DirectiveDefFeature = ( definition : DirectiveDef < unknown > ) => {
55
- const resolved = (
56
- Array . isArray ( rawHostDirectives ) ? rawHostDirectives : rawHostDirectives ( )
57
- ) . map ( ( dir ) => {
58
- return typeof dir === 'function'
59
- ? { directive : resolveForwardRef ( dir ) , inputs : EMPTY_OBJ , outputs : EMPTY_OBJ }
60
- : {
61
- directive : resolveForwardRef ( dir . directive ) ,
62
- inputs : bindingArrayToMap ( dir . inputs ) ,
63
- outputs : bindingArrayToMap ( dir . outputs ) ,
64
- } ;
65
- } ) ;
46
+ const isEager = Array . isArray ( rawHostDirectives ) ;
47
+
66
48
if ( definition . hostDirectives === null ) {
67
49
definition . findHostDirectiveDefs = findHostDirectiveDefs ;
68
- definition . hostDirectives = resolved ;
50
+ definition . hostDirectives = isEager
51
+ ? rawHostDirectives . map ( createHostDirectiveDef )
52
+ : [ rawHostDirectives ] ;
53
+ } else if ( isEager ) {
54
+ definition . hostDirectives . unshift ( ...rawHostDirectives . map ( createHostDirectiveDef ) ) ;
69
55
} else {
70
- definition . hostDirectives . unshift ( ... resolved ) ;
56
+ definition . hostDirectives . unshift ( rawHostDirectives ) ;
71
57
}
72
58
} ;
73
59
feature . ngInherit = true ;
@@ -80,23 +66,50 @@ function findHostDirectiveDefs(
80
66
hostDirectiveDefs : HostDirectiveDefs ,
81
67
) : void {
82
68
if ( currentDef . hostDirectives !== null ) {
83
- for ( const hostDirectiveConfig of currentDef . hostDirectives ) {
84
- const hostDirectiveDef = getDirectiveDef ( hostDirectiveConfig . directive ) ! ;
85
-
86
- if ( typeof ngDevMode === 'undefined' || ngDevMode ) {
87
- validateHostDirective ( hostDirectiveConfig , hostDirectiveDef ) ;
69
+ for ( const configOrFn of currentDef . hostDirectives ) {
70
+ if ( typeof configOrFn === 'function' ) {
71
+ const resolved = configOrFn ( ) ;
72
+ for ( const config of resolved ) {
73
+ trackHostDirectiveDef ( createHostDirectiveDef ( config ) , matchedDefs , hostDirectiveDefs ) ;
74
+ }
75
+ } else {
76
+ trackHostDirectiveDef ( configOrFn , matchedDefs , hostDirectiveDefs ) ;
88
77
}
78
+ }
79
+ }
80
+ }
89
81
90
- // We need to patch the `declaredInputs` so that
91
- // `ngOnChanges` can map the properties correctly.
92
- patchDeclaredInputs ( hostDirectiveDef . declaredInputs , hostDirectiveConfig . inputs ) ;
82
+ /** Tracks a single host directive during directive matching. */
83
+ function trackHostDirectiveDef (
84
+ def : HostDirectiveDef ,
85
+ matchedDefs : DirectiveDef < unknown > [ ] ,
86
+ hostDirectiveDefs : HostDirectiveDefs ,
87
+ ) {
88
+ const hostDirectiveDef = getDirectiveDef ( def . directive ) ! ;
93
89
94
- // Host directives execute before the host so that its host bindings can be overwritten.
95
- findHostDirectiveDefs ( hostDirectiveDef , matchedDefs , hostDirectiveDefs ) ;
96
- hostDirectiveDefs . set ( hostDirectiveDef , hostDirectiveConfig ) ;
97
- matchedDefs . push ( hostDirectiveDef ) ;
98
- }
90
+ if ( typeof ngDevMode === 'undefined' || ngDevMode ) {
91
+ validateHostDirective ( def , hostDirectiveDef ) ;
99
92
}
93
+
94
+ // We need to patch the `declaredInputs` so that
95
+ // `ngOnChanges` can map the properties correctly.
96
+ patchDeclaredInputs ( hostDirectiveDef . declaredInputs , def . inputs ) ;
97
+
98
+ // Host directives execute before the host so that its host bindings can be overwritten.
99
+ findHostDirectiveDefs ( hostDirectiveDef , matchedDefs , hostDirectiveDefs ) ;
100
+ hostDirectiveDefs . set ( hostDirectiveDef , def ) ;
101
+ matchedDefs . push ( hostDirectiveDef ) ;
102
+ }
103
+
104
+ /** Creates a `HostDirectiveDef` from a used-defined host directive configuration. */
105
+ function createHostDirectiveDef ( config : HostDirectiveConfig ) : HostDirectiveDef {
106
+ return typeof config === 'function'
107
+ ? { directive : resolveForwardRef ( config ) , inputs : EMPTY_OBJ , outputs : EMPTY_OBJ }
108
+ : {
109
+ directive : resolveForwardRef ( config . directive ) ,
110
+ inputs : bindingArrayToMap ( config . inputs ) ,
111
+ outputs : bindingArrayToMap ( config . outputs ) ,
112
+ } ;
100
113
}
101
114
102
115
/**
0 commit comments