forked from angular/angular
-
Notifications
You must be signed in to change notification settings - Fork 0
/
host_directives_resolver.ts
92 lines (76 loc) · 3.18 KB
/
host_directives_resolver.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {DirectiveMeta, MatchSource, MetadataReader} from '../../metadata/src/api';
import {ClassDeclaration} from '../../reflection';
import {BindingPropertyName, ClassPropertyMapping, ClassPropertyName} from '../src/property_mapping';
import {flattenInheritedDirectiveMetadata} from './inheritance';
const EMPTY_ARRAY: ReadonlyArray<any> = [];
/** Resolves the host directives of a directive to a flat array of matches. */
export class HostDirectivesResolver {
private cache = new Map<ClassDeclaration, ReadonlyArray<DirectiveMeta>>();
constructor(private metaReader: MetadataReader) {}
/** Resolves all of the host directives that apply to a directive. */
resolve(metadata: DirectiveMeta): ReadonlyArray<DirectiveMeta> {
if (this.cache.has(metadata.ref.node)) {
return this.cache.get(metadata.ref.node)!;
}
const results = metadata.hostDirectives && metadata.hostDirectives.length > 0 ?
this.walkHostDirectives(metadata.hostDirectives, []) :
EMPTY_ARRAY;
this.cache.set(metadata.ref.node, results);
return results;
}
/**
* Traverses all of the host directive chains and produces a flat array of
* directive metadata representing the host directives that apply to the host.
*/
private walkHostDirectives(
directives: NonNullable<DirectiveMeta['hostDirectives']>,
results: DirectiveMeta[]): ReadonlyArray<DirectiveMeta> {
for (const current of directives) {
const hostMeta = flattenInheritedDirectiveMetadata(this.metaReader, current.directive);
// This case has been checked for already and produces a diagnostic
if (hostMeta === null) {
continue;
}
if (hostMeta.hostDirectives) {
this.walkHostDirectives(hostMeta.hostDirectives, results);
}
results.push({
...hostMeta,
matchSource: MatchSource.HostDirective,
inputs: this.filterMappings(hostMeta.inputs, current.inputs),
outputs: this.filterMappings(hostMeta.outputs, current.outputs),
});
}
return results;
}
/**
* Filters the class property mappings so that only the allowed ones are present.
* @param source Property mappings that should be filtered.
* @param allowedProperties Property mappings that are allowed in the final results.
*/
private filterMappings(
source: ClassPropertyMapping,
allowedProperties: {[publicName: string]: string}|null): ClassPropertyMapping {
const result: Record<string, BindingPropertyName|[ClassPropertyName, BindingPropertyName]> = {};
if (allowedProperties !== null) {
for (const publicName in allowedProperties) {
if (allowedProperties.hasOwnProperty(publicName)) {
const bindings = source.getByBindingPropertyName(publicName);
if (bindings !== null) {
for (const binding of bindings) {
result[binding.classPropertyName] = allowedProperties[publicName];
}
}
}
}
}
return ClassPropertyMapping.fromMappedObject(result);
}
}