1
1
import { IConstruct } from "./construct" ;
2
2
3
3
/**
4
- * A set of constructs that can be depended upon
4
+ * Trait marker for classes that can be depended upon
5
+ *
6
+ * The presence of this interface indicates that an object has
7
+ * an `IDependableTrait` implementation.
5
8
*
6
9
* This interface can be used to take an (ordering) dependency on a set of
7
10
* constructs. An ordering dependency implies that the resources represented by
8
11
* those constructs are deployed before the resources depending ON them are
9
12
* deployed.
10
13
*/
11
14
export interface IDependable {
12
- /**
13
- * The set of constructs that form the root of this dependable
14
- *
15
- * All resources under all returned constructs are included in the ordering
16
- * dependency.
17
- */
18
- readonly dependencyRoots : IConstruct [ ] ;
15
+ // Empty, this interface is a trait marker
19
16
}
20
17
21
18
/**
@@ -27,17 +24,71 @@ export interface IDependable {
27
24
export class ConcreteDependable implements IDependable {
28
25
private readonly _dependencyRoots = new Array < IConstruct > ( ) ;
29
26
27
+ constructor ( ) {
28
+ const self = this ;
29
+ DependableTrait . implement ( this , {
30
+ get dependencyRoots ( ) { return self . _dependencyRoots ; } ,
31
+ } ) ;
32
+ }
33
+
30
34
/**
31
35
* Add a construct to the dependency roots
32
36
*/
33
37
public add ( construct : IConstruct ) {
34
38
this . _dependencyRoots . push ( construct ) ;
35
39
}
40
+ }
36
41
42
+ /**
43
+ * Trait for IDependable
44
+ *
45
+ * Traits are interfaces that are privately implemented by objects. Instead of
46
+ * showing up in the public interface of a class, they need to be queried
47
+ * explicitly. This is used to implement certain framework features that are
48
+ * not intended to be used by Construct consumers, and so should be hidden
49
+ * from accidental use.
50
+ *
51
+ * @example
52
+ *
53
+ * // Usage
54
+ * const roots = DependableTrait.get(construct).dependencyRoots;
55
+ *
56
+ * // Definition
57
+ * DependableTrait.implement(construct, {
58
+ * get dependencyRoots() { return []; }
59
+ * });
60
+ */
61
+ export abstract class DependableTrait {
37
62
/**
38
- * Retrieve the current set of dependency roots
63
+ * Register `instance` to have the given DependableTrait
64
+ *
65
+ * Should be called in the class constructor.
39
66
*/
40
- public get dependencyRoots ( ) : IConstruct [ ] {
41
- return this . _dependencyRoots ;
67
+ public static implement ( instance : IDependable , trait : DependableTrait ) {
68
+ // I would also like to reference classes (to cut down on the list of objects
69
+ // we need to manage), but we can't do that either since jsii doesn't have the
70
+ // concept of a class reference.
71
+ DependableTrait . traitMap . set ( instance , trait ) ;
42
72
}
73
+
74
+ /**
75
+ * Return the matching DependableTrait for the given class instance.
76
+ */
77
+ public static get ( instance : IDependable ) : DependableTrait {
78
+ const ret = DependableTrait . traitMap . get ( instance ) ;
79
+ if ( ! ret ) {
80
+ throw new Error ( `${ instance } does not implement DependableTrait` ) ;
81
+ }
82
+ return ret ;
83
+ }
84
+
85
+ private static traitMap = new WeakMap < IDependable , DependableTrait > ( ) ;
86
+
87
+ /**
88
+ * The set of constructs that form the root of this dependable
89
+ *
90
+ * All resources under all returned constructs are included in the ordering
91
+ * dependency.
92
+ */
93
+ public abstract readonly dependencyRoots : IConstruct [ ] ;
43
94
}
0 commit comments