9
9
*/
10
10
11
11
import Foundation
12
+ import SymbolKit
12
13
13
14
/// A type that provides documentation bundles that it discovers by traversing the local file system.
14
15
public struct GeneratedDataProvider : DocumentationWorkspaceDataProvider {
15
16
public var identifier : String = UUID ( ) . uuidString
16
17
17
- /// Options to configure how the provider generates documentation bundles.
18
- public var options : BundleDiscoveryOptions
19
-
20
- private let info : DocumentationBundle . Info
21
- private let topLevelPage : URL
22
18
public typealias SymbolGraphDataLoader = ( URL ) -> Data ?
23
19
private let symbolGraphDataLoader : SymbolGraphDataLoader
24
20
25
- /// Creates a new provider that recursively traverses the content of the given root URL to discover documentation bundles.
21
+ /// Creates a new provider that generates documentation bundles from the ``BundleDiscoveryOptions`` it is passed in `` bundles(options:)`` .
26
22
///
27
23
/// - Parameters:
28
- /// - options: Options to configure how the converter discovers documentation bundles.
29
24
/// - symbolGraphDataLoader: A closure that loads the raw data for a symbol graph file at a given URL.
30
- public init ( options: BundleDiscoveryOptions , symbolGraphDataLoader: @escaping SymbolGraphDataLoader ) throws {
31
- self . options = options
25
+ public init ( symbolGraphDataLoader: @escaping SymbolGraphDataLoader ) {
32
26
self . symbolGraphDataLoader = symbolGraphDataLoader
27
+ }
28
+
29
+ public func bundles( options: BundleDiscoveryOptions ) throws -> [ DocumentationBundle ] {
30
+ let info : DocumentationBundle . Info
33
31
do {
34
- self . info = try DocumentationBundle . Info ( bundleDiscoveryOptions: options)
32
+ info = try DocumentationBundle . Info ( bundleDiscoveryOptions: options)
35
33
} catch {
36
34
throw Error . notEnoughDataToGenerateBundle ( options: options, underlyingError: error)
37
35
}
38
36
39
- self . topLevelPage = URL ( string: " \( info. displayName. replacingWhitespaceAndPunctuation ( with: " - " ) ) .md " ) !
40
- }
41
-
42
- public func bundles( options: BundleDiscoveryOptions ) throws -> [ DocumentationBundle ] {
43
37
guard !options. additionalSymbolGraphFiles. isEmpty else {
44
38
return [ ]
45
39
}
46
40
41
+ // Find all the unique module names from the symbol graph files and generate a top level module page for each of them.
42
+ var moduleNames = Set < String > ( )
43
+ for url in options. additionalSymbolGraphFiles {
44
+ guard let data = symbolGraphDataLoader ( url) else {
45
+ throw Error . unableToLoadSymbolGraphData ( url: url)
46
+ }
47
+ let container = try JSONDecoder ( ) . decode ( SymbolGraphModuleContainer . self, from: data)
48
+ moduleNames. insert ( container. module. name)
49
+ }
50
+
51
+ let topLevelPages = moduleNames. map { URL ( string: $0 + " .md " ) ! }
52
+
47
53
return [
48
54
DocumentationBundle (
49
55
info: info,
50
56
attributedCodeListings: [ : ] ,
51
57
symbolGraphURLs: options. additionalSymbolGraphFiles,
52
- markupURLs: [ topLevelPage ] ,
58
+ markupURLs: topLevelPages ,
53
59
miscResourceURLs: [ ]
54
60
)
55
61
]
@@ -92,10 +98,11 @@ public struct GeneratedDataProvider: DocumentationWorkspaceDataProvider {
92
98
}
93
99
94
100
public func contentsOfURL( _ url: URL ) throws -> Data {
95
- if url == topLevelPage {
96
- let markdown = " # `` \( info. displayName) `` "
101
+ if DocumentationBundleFileTypes . isMarkupFile ( url) {
102
+ let moduleName = url. deletingPathExtension ( ) . lastPathComponent
103
+ let markdown = " # `` \( moduleName) `` "
97
104
return Data ( markdown. utf8)
98
- } else if options . additionalSymbolGraphFiles . contains ( url) {
105
+ } else if DocumentationBundleFileTypes . isSymbolGraphFile ( url) {
99
106
guard let data = symbolGraphDataLoader ( url) else {
100
107
throw Error . unableToLoadSymbolGraphData ( url: url)
101
108
}
@@ -105,3 +112,17 @@ public struct GeneratedDataProvider: DocumentationWorkspaceDataProvider {
105
112
}
106
113
}
107
114
}
115
+
116
+ /// A wrapper type that decodes only the module in the symbol graph.
117
+ private struct SymbolGraphModuleContainer : Decodable {
118
+ /// The decoded symbol graph module.
119
+ let module : SymbolGraph . Module
120
+
121
+ typealias CodingKeys = SymbolGraph . CodingKeys
122
+
123
+ public init ( from decoder: Decoder ) throws {
124
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
125
+
126
+ self . module = try container. decode ( SymbolGraph . Module. self, forKey: . module)
127
+ }
128
+ }
0 commit comments