11
11
//===----------------------------------------------------------------------===//
12
12
13
13
package import Foundation
14
+ import SKLogging
14
15
@_spi ( LinkCompletion) @preconcurrency import SwiftDocC
15
16
16
17
final actor DocCCatalogIndexManager {
@@ -51,6 +52,10 @@ final actor DocCCatalogIndexManager {
51
52
catalogToIndexMap [ catalogURL] = . success( catalogIndex)
52
53
return catalogIndex
53
54
} catch {
55
+ // Don't cache cancellation errors
56
+ guard !( error is CancellationError ) else {
57
+ throw . cancelled
58
+ }
54
59
let internalError = error as? DocCIndexError ?? DocCIndexError . internalError ( error)
55
60
catalogToIndexMap [ catalogURL] = . failure( internalError)
56
61
throw internalError
@@ -62,13 +67,16 @@ final actor DocCCatalogIndexManager {
62
67
package enum DocCIndexError : LocalizedError {
63
68
case internalError( any Error )
64
69
case unexpectedlyNilRenderReferenceStore
70
+ case cancelled
65
71
66
72
package var errorDescription : String ? {
67
73
switch self {
68
74
case . internalError( let internalError) :
69
75
return " An internal error occurred: \( internalError. localizedDescription) "
70
76
case . unexpectedlyNilRenderReferenceStore:
71
77
return " Did not receive a RenderReferenceStore from the DocC server "
78
+ case . cancelled:
79
+ return " The request was cancelled "
72
80
}
73
81
}
74
82
}
@@ -101,7 +109,9 @@ package struct DocCCatalogIndex: Sendable {
101
109
var assets : [ String : DataAsset ] = [ : ]
102
110
for (reference, asset) in renderReferenceStore. assets {
103
111
var asset = asset
104
- asset. variants = asset. variants. compactMapValues { $0. withScheme ( " doc-asset " ) }
112
+ asset. variants = asset. variants. compactMapValues { url in
113
+ orLog ( " Failed to convert asset from RenderReferenceStore " ) { try url. withScheme ( " doc-asset " ) }
114
+ }
105
115
assets [ reference. assetName] = asset
106
116
}
107
117
self . assets = assets
@@ -126,7 +136,7 @@ package struct DocCCatalogIndex: Sendable {
126
136
case . overview:
127
137
tutorialOverviews [ lastPathComponent] = topicRenderReference
128
138
default :
129
- guard topicContentValue. isDocumentationExtensionContent else {
139
+ guard topicContentValue. isDocumentationExtensionContent, renderReferenceKey . url . pathComponents . count > 2 else {
130
140
continue
131
141
}
132
142
// Documentation extensions are always of the form `doc://<BundleID>/documentation/<SymbolPath>`.
@@ -145,10 +155,29 @@ package struct DocCCatalogIndex: Sendable {
145
155
}
146
156
}
147
157
158
+ fileprivate enum WithSchemeError : LocalizedError {
159
+ case failedToRetrieveComponents( URL )
160
+ case failedToEncode( URLComponents )
161
+
162
+ var errorDescription : String ? {
163
+ switch self {
164
+ case . failedToRetrieveComponents( let url) :
165
+ " Failed to retrieve components for URL \( url. absoluteString) "
166
+ case . failedToEncode( let components) :
167
+ " Failed to encode URL components \( String ( reflecting: components) ) "
168
+ }
169
+ }
170
+ }
171
+
148
172
fileprivate extension URL {
149
- func withScheme( _ scheme: String ) -> URL {
150
- var components = URLComponents ( url: self , resolvingAgainstBaseURL: true )
151
- components? . scheme = scheme
152
- return components? . url ?? self
173
+ func withScheme( _ scheme: String ) throws ( WithSchemeError) -> URL {
174
+ guard var components = URLComponents ( url: self , resolvingAgainstBaseURL: true ) else {
175
+ throw WithSchemeError . failedToRetrieveComponents ( self )
176
+ }
177
+ components. scheme = scheme
178
+ guard let result = components. url else {
179
+ throw WithSchemeError . failedToEncode ( components)
180
+ }
181
+ return result
153
182
}
154
183
}
0 commit comments