1 
2 /**
3  A protocol that must be implemented to be a part of module's definition and the module definition itself.
4  */
5 public protocol AnyDefinition {}
6 
7 /**
8  The definition of the module. It is used to define some parameters
9  of the module and what it exports to the JavaScript world.
10  See `ModuleDefinitionBuilder` for more details on how to create it.
11  */
12 public class ModuleDefinition: AnyDefinition {
13   /**
14    The module's type associated with the definition. It's used to create the module instance.
15    */
16   var type: AnyModule.Type?
17 
18   /**
19    Name of the defined module. Falls back to the type name if not provided in the definition.
20    */
21   var name: String
22 
23   let methods: [String : AnyMethod]
24   let constants: [String : Any?]
25   let eventListeners: [EventListener]
26   let viewManager: ViewManagerDefinition?
27 
28   /**
29    Initializer that is called by the `ModuleDefinitionBuilder` results builder.
30    */
31   init(definitions: [AnyDefinition]) {
32     self.name = definitions
33       .compactMap { $0 as? ModuleNameDefinition }
34       .last?
35       .name ?? ""
36 
37     self.methods = definitions
38       .compactMap { $0 as? AnyMethod }
39       .reduce(into: [String : AnyMethod]()) { dict, method in
40         dict[method.name] = method
41       }
42 
43     self.constants = definitions
44       .compactMap { $0 as? ConstantsDefinition }
45       .reduce(into: [String : Any?]()) { dict, definition in
46         dict.merge(definition.constants) { $1 }
47       }
48 
49     self.eventListeners = definitions.compactMap { $0 as? EventListener }
50 
51     self.viewManager = definitions
52       .compactMap { $0 as? ViewManagerDefinition }
53       .last
54   }
55 
56   /**
57    Sets the module type that the definition is associated with. We can't pass this in the initializer
58    as it's called by the results builder that doesn't have access to the type.
59    */
60   func withType(_ type: AnyModule.Type) -> Self {
61     self.type = type
62 
63     // Use the type name if the name is not in the definition or was defined empty.
64     if name.isEmpty {
65       name = String(describing: type)
66     }
67     return self
68   }
69 }
70 
71 /**
72  Module's name definition. Returned by `name()` in module's definition.
73  */
74 internal struct ModuleNameDefinition: AnyDefinition {
75   let name: String
76 }
77 
78 /**
79  A definition for module's constants. Returned by `constants(() -> SomeType)` in module's definition.
80  */
81 internal struct ConstantsDefinition: AnyDefinition {
82   let constants: [String : Any?]
83 }
84