|
1 | 1 | /*
|
2 | 2 | This source file is part of the Swift.org open source project
|
3 | 3 |
|
4 |
| - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors |
| 4 | + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors |
5 | 5 | Licensed under Apache License v2.0 with Runtime Library Exception
|
6 | 6 |
|
7 | 7 | See https://swift.org/LICENSE.txt for license information
|
@@ -44,68 +44,68 @@ public struct ConvertService: DocumentationService {
|
44 | 44 | _ message: DocumentationServer.Message,
|
45 | 45 | completion: @escaping (DocumentationServer.Message) -> ()
|
46 | 46 | ) {
|
47 |
| - let conversionResult = retrievePayload(message) |
48 |
| - .flatMap(decodeRequest) |
49 |
| - .flatMap(convert) |
50 |
| - .flatMap(encodeResponse) |
51 |
| - |
52 |
| - switch conversionResult { |
53 |
| - case .success(let response): |
54 |
| - completion( |
55 |
| - DocumentationServer.Message( |
56 |
| - type: Self.convertResponseMessageType, |
57 |
| - identifier: "\(message.identifier)-response", |
58 |
| - payload: response |
| 47 | + Task { |
| 48 | + let result = await process(message) |
| 49 | + completion(result) |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + public func process(_ message: DocumentationServer.Message) async -> DocumentationServer.Message { |
| 54 | + func makeErrorResponse(_ error: ConvertServiceError) -> DocumentationServer.Message { |
| 55 | + DocumentationServer.Message( |
| 56 | + type: Self.convertResponseErrorMessageType, |
| 57 | + identifier: "\(message.identifier)-response-error", |
| 58 | + |
| 59 | + // Force trying because encoding known messages should never fail. |
| 60 | + payload: try! JSONEncoder().encode(error) |
| 61 | + ) |
| 62 | + } |
| 63 | + |
| 64 | + guard let payload = message.payload else { |
| 65 | + return makeErrorResponse(.missingPayload()) |
| 66 | + } |
| 67 | + |
| 68 | + let request: ConvertRequest |
| 69 | + do { |
| 70 | + request = try JSONDecoder().decode(ConvertRequest.self, from: payload) |
| 71 | + } catch { |
| 72 | + return makeErrorResponse(.invalidRequest(underlyingError: error.localizedDescription)) |
| 73 | + } |
| 74 | + |
| 75 | + let renderNodes: [RenderNode] |
| 76 | + let renderReferenceStore: RenderReferenceStore? |
| 77 | + do { |
| 78 | + (renderNodes, renderReferenceStore) = try await convert(request: request, messageIdentifier: message.identifier) |
| 79 | + } catch { |
| 80 | + return makeErrorResponse(.conversionError(underlyingError: error.localizedDescription)) |
| 81 | + } |
| 82 | + |
| 83 | + do { |
| 84 | + let encoder = JSONEncoder() |
| 85 | + let encodedResponse = try encoder.encode( |
| 86 | + try ConvertResponse( |
| 87 | + renderNodes: renderNodes.map(encoder.encode), |
| 88 | + renderReferenceStore: renderReferenceStore.map(encoder.encode) |
59 | 89 | )
|
60 | 90 | )
|
61 | 91 |
|
62 |
| - case .failure(let error): |
63 |
| - completion( |
64 |
| - DocumentationServer.Message( |
65 |
| - type: Self.convertResponseErrorMessageType, |
66 |
| - identifier: "\(message.identifier)-response-error", |
67 |
| - |
68 |
| - // Force trying because encoding known messages should never fail. |
69 |
| - payload: try! JSONEncoder().encode(error) |
70 |
| - ) |
| 92 | + return DocumentationServer.Message( |
| 93 | + type: Self.convertResponseMessageType, |
| 94 | + identifier: "\(message.identifier)-response", |
| 95 | + payload: encodedResponse |
71 | 96 | )
|
72 |
| - } |
73 |
| - } |
74 |
| - |
75 |
| - /// Attempts to retrieve the payload from the given message, returning a failure if the payload is missing. |
76 |
| - /// |
77 |
| - /// - Returns: A result with the message's payload if present, otherwise a ``ConvertServiceError/missingPayload`` |
78 |
| - /// failure. |
79 |
| - private func retrievePayload( |
80 |
| - _ message: DocumentationServer.Message |
81 |
| - ) -> Result<(payload: Data, messageIdentifier: String), ConvertServiceError> { |
82 |
| - message.payload.map { .success(($0, message.identifier)) } ?? .failure(.missingPayload()) |
83 |
| - } |
84 |
| - |
85 |
| - /// Attempts to decode the given request, returning a failure if decoding failed. |
86 |
| - /// |
87 |
| - /// - Returns: A result with the decoded request if the decoding succeeded, otherwise a |
88 |
| - /// ``ConvertServiceError/invalidRequest`` failure. |
89 |
| - private func decodeRequest( |
90 |
| - data: Data, |
91 |
| - messageIdentifier: String |
92 |
| - ) -> Result<(request: ConvertRequest, messageIdentifier: String), ConvertServiceError> { |
93 |
| - Result { |
94 |
| - return (try JSONDecoder().decode(ConvertRequest.self, from: data), messageIdentifier) |
95 |
| - }.mapErrorToConvertServiceError { |
96 |
| - .invalidRequest(underlyingError: $0.localizedDescription) |
| 97 | + } catch { |
| 98 | + return makeErrorResponse(.invalidResponseMessage(underlyingError: error.localizedDescription)) |
97 | 99 | }
|
98 | 100 | }
|
99 | 101 |
|
100 | 102 | /// Attempts to process the given convert request, returning a failure if the conversion failed.
|
101 | 103 | ///
|
102 |
| - /// - Returns: A result with the produced render nodes if the conversion was successful, otherwise a |
103 |
| - /// ``ConvertServiceError/conversionError`` failure. |
| 104 | + /// - Returns: A result with the produced render nodes if the conversion was successful |
104 | 105 | private func convert(
|
105 | 106 | request: ConvertRequest,
|
106 | 107 | messageIdentifier: String
|
107 |
| - ) -> Result<([RenderNode], RenderReferenceStore?), ConvertServiceError> { |
108 |
| - Result { |
| 108 | + ) async throws -> ([RenderNode], RenderReferenceStore?) { |
109 | 109 | // Update DocC's current feature flags based on the ones provided
|
110 | 110 | // in the request.
|
111 | 111 | FeatureFlags.current = request.featureFlags
|
@@ -155,7 +155,7 @@ public struct ConvertService: DocumentationService {
|
155 | 155 | (bundle, dataProvider) = Self.makeBundleAndInMemoryDataProvider(request)
|
156 | 156 | }
|
157 | 157 |
|
158 |
| - let context = try DocumentationContext(bundle: bundle, dataProvider: dataProvider, configuration: configuration) |
| 158 | + let context = try await DocumentationContext(bundle: bundle, dataProvider: dataProvider, configuration: configuration) |
159 | 159 |
|
160 | 160 | // Precompute the render context
|
161 | 161 | let renderContext = RenderContext(documentationContext: context, bundle: bundle)
|
@@ -228,30 +228,6 @@ public struct ConvertService: DocumentationService {
|
228 | 228 | }
|
229 | 229 |
|
230 | 230 | return (renderNodes, referenceStore)
|
231 |
| - }.mapErrorToConvertServiceError { |
232 |
| - .conversionError(underlyingError: $0.localizedDescription) |
233 |
| - } |
234 |
| - } |
235 |
| - |
236 |
| - /// Encodes a conversion response to send to the client. |
237 |
| - /// |
238 |
| - /// - Parameter renderNodes: The render nodes that were produced as part of the conversion. |
239 |
| - private func encodeResponse( |
240 |
| - renderNodes: [RenderNode], |
241 |
| - renderReferenceStore: RenderReferenceStore? |
242 |
| - ) -> Result<Data, ConvertServiceError> { |
243 |
| - Result { |
244 |
| - let encoder = JSONEncoder() |
245 |
| - |
246 |
| - return try encoder.encode( |
247 |
| - try ConvertResponse( |
248 |
| - renderNodes: renderNodes.map(encoder.encode), |
249 |
| - renderReferenceStore: renderReferenceStore.map(encoder.encode) |
250 |
| - ) |
251 |
| - ) |
252 |
| - }.mapErrorToConvertServiceError { |
253 |
| - .invalidResponseMessage(underlyingError: $0.localizedDescription) |
254 |
| - } |
255 | 231 | }
|
256 | 232 |
|
257 | 233 | /// Takes a base reference store and adds uncurated article references and documentation extensions.
|
@@ -297,25 +273,6 @@ public struct ConvertService: DocumentationService {
|
297 | 273 | }
|
298 | 274 | }
|
299 | 275 |
|
300 |
| -extension Result { |
301 |
| - /// Returns a new result, mapping any failure value using the given transformation if the error is not a conversion error. |
302 |
| - /// |
303 |
| - /// If the error value is a ``ConvertServiceError``, it is returned as-is. If it's not, the given transformation is called on the |
304 |
| - /// error. |
305 |
| - /// |
306 |
| - /// - Parameter transform: A closure that takes the failure value of the instance. |
307 |
| - func mapErrorToConvertServiceError( |
308 |
| - _ transform: (any Error) -> ConvertServiceError |
309 |
| - ) -> Result<Success, ConvertServiceError> { |
310 |
| - mapError { error in |
311 |
| - switch error { |
312 |
| - case let error as ConvertServiceError: return error |
313 |
| - default: return transform(error) |
314 |
| - } |
315 |
| - } |
316 |
| - } |
317 |
| -} |
318 |
| - |
319 | 276 | private extension SymbolGraph.LineList.Line {
|
320 | 277 | /// Creates a line given a convert request line.
|
321 | 278 | init(_ line: ConvertRequest.Line) {
|
|
0 commit comments