1111//===----------------------------------------------------------------------===//
1212
1313package import Foundation
14+ import SKLogging
1415@_spi ( LinkCompletion) @preconcurrency import SwiftDocC
1516
1617final actor DocCCatalogIndexManager {
@@ -51,6 +52,10 @@ final actor DocCCatalogIndexManager {
5152 catalogToIndexMap [ catalogURL] = . success( catalogIndex)
5253 return catalogIndex
5354 } catch {
55+ // Don't cache cancellation errors
56+ guard !( error is CancellationError ) else {
57+ throw . cancelled
58+ }
5459 let internalError = error as? DocCIndexError ?? DocCIndexError . internalError ( error)
5560 catalogToIndexMap [ catalogURL] = . failure( internalError)
5661 throw internalError
@@ -62,13 +67,16 @@ final actor DocCCatalogIndexManager {
6267package enum DocCIndexError : LocalizedError {
6368 case internalError( any Error )
6469 case unexpectedlyNilRenderReferenceStore
70+ case cancelled
6571
6672 package var errorDescription : String ? {
6773 switch self {
6874 case . internalError( let internalError) :
6975 return " An internal error occurred: \( internalError. localizedDescription) "
7076 case . unexpectedlyNilRenderReferenceStore:
7177 return " Did not receive a RenderReferenceStore from the DocC server "
78+ case . cancelled:
79+ return " The request was cancelled "
7280 }
7381 }
7482}
@@ -101,7 +109,9 @@ package struct DocCCatalogIndex: Sendable {
101109 var assets : [ String : DataAsset ] = [ : ]
102110 for (reference, asset) in renderReferenceStore. assets {
103111 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+ }
105115 assets [ reference. assetName] = asset
106116 }
107117 self . assets = assets
@@ -126,7 +136,7 @@ package struct DocCCatalogIndex: Sendable {
126136 case . overview:
127137 tutorialOverviews [ lastPathComponent] = topicRenderReference
128138 default :
129- guard topicContentValue. isDocumentationExtensionContent else {
139+ guard topicContentValue. isDocumentationExtensionContent, renderReferenceKey . url . pathComponents . count > 2 else {
130140 continue
131141 }
132142 // Documentation extensions are always of the form `doc://<BundleID>/documentation/<SymbolPath>`.
@@ -145,10 +155,29 @@ package struct DocCCatalogIndex: Sendable {
145155 }
146156}
147157
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+
148172fileprivate 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
153182 }
154183}
0 commit comments