forked from angular/angular
-
Notifications
You must be signed in to change notification settings - Fork 0
/
inheritance.ts
80 lines (71 loc) · 2.67 KB
/
inheritance.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
/**
* @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 {Reference} from '../../imports';
import {ClassDeclaration} from '../../reflection';
import {DirectiveMeta, MetadataReader} from './api';
import {ClassPropertyMapping, ClassPropertyName} from './property_mapping';
/**
* Given a reference to a directive, return a flattened version of its `DirectiveMeta` metadata
* which includes metadata from its entire inheritance chain.
*
* The returned `DirectiveMeta` will either have `baseClass: null` if the inheritance chain could be
* fully resolved, or `baseClass: 'dynamic'` if the inheritance chain could not be completely
* followed.
*/
export function flattenInheritedDirectiveMetadata(
reader: MetadataReader, dir: Reference<ClassDeclaration>): DirectiveMeta {
const topMeta = reader.getDirectiveMetadata(dir);
if (topMeta === null) {
throw new Error(`Metadata not found for directive: ${dir.debugName}`);
}
const coercedInputFields = new Set<ClassPropertyName>();
const undeclaredInputFields = new Set<ClassPropertyName>();
const restrictedInputFields = new Set<ClassPropertyName>();
const stringLiteralInputFields = new Set<ClassPropertyName>();
let isDynamic = false;
let inputs = ClassPropertyMapping.empty();
let outputs = ClassPropertyMapping.empty();
const addMetadata = (meta: DirectiveMeta): void => {
if (meta.baseClass === 'dynamic') {
isDynamic = true;
} else if (meta.baseClass !== null) {
const baseMeta = reader.getDirectiveMetadata(meta.baseClass);
if (baseMeta !== null) {
addMetadata(baseMeta);
} else {
// Missing metadata for the base class means it's effectively dynamic.
isDynamic = true;
}
}
inputs = ClassPropertyMapping.merge(inputs, meta.inputs);
outputs = ClassPropertyMapping.merge(outputs, meta.outputs);
for (const coercedInputField of meta.coercedInputFields) {
coercedInputFields.add(coercedInputField);
}
for (const undeclaredInputField of meta.undeclaredInputFields) {
undeclaredInputFields.add(undeclaredInputField);
}
for (const restrictedInputField of meta.restrictedInputFields) {
restrictedInputFields.add(restrictedInputField);
}
for (const field of meta.stringLiteralInputFields) {
stringLiteralInputFields.add(field);
}
};
addMetadata(topMeta);
return {
...topMeta,
inputs,
outputs,
coercedInputFields,
undeclaredInputFields,
restrictedInputFields,
stringLiteralInputFields,
baseClass: isDynamic ? 'dynamic' : null,
};
}