-
-
Notifications
You must be signed in to change notification settings - Fork 75
Expand file tree
/
Copy pathExternalModuleIndex.swift
More file actions
99 lines (84 loc) · 3.76 KB
/
ExternalModuleIndex.swift
File metadata and controls
99 lines (84 loc) · 3.76 KB
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
93
94
95
96
97
98
99
#if canImport(BridgeJSSkeleton)
import BridgeJSSkeleton
#endif
/// Index of `@JS` types from dependencies.
public struct ExternalModuleIndex {
public struct ExternalType: Equatable {
public let moduleName: String
public let bridgeType: BridgeType
}
public enum LookupResult: Equatable {
case unique(ExternalType)
case ambiguous(candidates: [ExternalType])
}
public static var empty: ExternalModuleIndex {
ExternalModuleIndex(dependencies: [])
}
private let byModuleAndPath: [String: [String: ExternalType]]
private let byPath: [String: [ExternalType]]
public var moduleNames: Set<String> { Set(byModuleAndPath.keys) }
public init(dependencies: [(moduleName: String, skeleton: BridgeJSSkeleton)]) {
var entriesByModule: [String: [String: ExternalType]] = [:]
var entriesByDotPath: [String: [ExternalType]] = [:]
for (moduleName, skeleton) in dependencies {
guard let exported = skeleton.exported else { continue }
var moduleEntries = entriesByModule[moduleName] ?? [:]
func register(dotPath: String, bridgeType: BridgeType) {
let externalType = ExternalType(moduleName: moduleName, bridgeType: bridgeType)
if moduleEntries[dotPath] == nil {
moduleEntries[dotPath] = externalType
entriesByDotPath[dotPath, default: []].append(externalType)
}
}
for klass in exported.classes {
register(dotPath: klass.swiftCallName, bridgeType: .swiftHeapObject(klass.swiftCallName))
}
for structDef in exported.structs {
register(dotPath: structDef.swiftCallName, bridgeType: .swiftStruct(structDef.swiftCallName))
}
for enumDef in exported.enums {
let bridgeType: BridgeType
switch enumDef.enumType {
case .simple:
bridgeType = .caseEnum(enumDef.swiftCallName)
case .rawValue:
guard let rawType = enumDef.rawType else { continue }
bridgeType = .rawValueEnum(enumDef.swiftCallName, rawType)
case .associatedValue:
bridgeType = .associatedValueEnum(enumDef.swiftCallName)
case .namespace:
bridgeType = .namespaceEnum(enumDef.swiftCallName)
}
register(dotPath: enumDef.swiftCallName, bridgeType: bridgeType)
}
for proto in exported.protocols {
register(dotPath: proto.name, bridgeType: .swiftProtocol(proto.name))
}
for alias in exported.aliases {
register(
dotPath: alias.swiftCallName,
bridgeType: .alias(name: alias.swiftCallName, underlying: alias.underlying)
)
}
entriesByModule[moduleName] = moduleEntries
}
self.byModuleAndPath = entriesByModule
self.byPath = entriesByDotPath
}
public var isEmpty: Bool { byModuleAndPath.isEmpty }
public func isKnownModule(_ name: String) -> Bool {
byModuleAndPath[name] != nil
}
public func lookup(dotPath: String) -> LookupResult? {
guard let matches = byPath[dotPath], !matches.isEmpty else { return nil }
if matches.count == 1 {
return .unique(matches[0])
}
return .ambiguous(candidates: matches)
}
public func lookup(dotPath: String, module moduleName: String) -> LookupResult? {
guard let moduleEntries = byModuleAndPath[moduleName] else { return nil }
guard let externalType = moduleEntries[dotPath] else { return nil }
return .unique(externalType)
}
}