Skip to content

Commit ed492be

Browse files
authored
Deprecate two-step documentation context creation (#1059)
* Deprecate `DocumentationConverter` * Update DataProvider protocol to a be general purpose * Update DiagnosticConsoleWriter to use DataProvider protocol * Update LinkResolver to use DataProvider protocol * Update one test helper to use InputProvider to discover inputs * Update tests to load inputs using test helpers * Avoid loading same bundle twice in same test * Avoid creating unused workspace and context in tests * Use InMemoryDataProvider instead of custom type in test * Avoid force try in one test * Move additional global checks to context configuration * Avoid copying the test bundle when the catalog content isn't modified * Update ConvertActionIndexerTests to use InputProvider to discover inputs * Avoid using `_legacyDataProvider` in tests * Update tests to pass link dependency files instead of using `configureContext` * Update final test helper to use `InputProvider` to discover inputs Also, remove no longer used `configureContext` parameter * Use test file system for empty test bundle * Use test helper for setting feature flags * Deprecate `DocumentationWorkspace` rdar://136208312 * Update BundleDiscoveryTests to use test helpers for input discovery * Remove unused data provider parameter from convert action initializer * Stop conforming test file system to workspace data provider * Deprecate `GeneratedDataProvider` * Deprecate `PrebuiltLocalFileSystemDataProvider` * Remove unused SymbolGraphLoader initializer * Indicate in deprecated tests when they can be removed * Remove out-of-date deprecation warning for already removed code * Deprecate `DocumentationWorkspaceDataProvider` * Deprecate `DocumentationContextDataProvider` * Deprecate additional multi-bundle-related properties * Add comments to deprecated tests explaining that they aren't skipped * Update comment about why unexpected errors and turned into diagnostics and add FIXME to change this in the future
1 parent e600b1f commit ed492be

File tree

60 files changed

+537
-809
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+537
-809
lines changed

Sources/SwiftDocC/DocumentationService/Convert/ConvertService+DataProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ extension ConvertService {
4545
),
4646
InMemoryDataProvider(
4747
files: files,
48-
fallbackFileManager: FileManager.default
48+
fallback: FileManager.default
4949
)
5050
)
5151
}

Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ public struct ConvertService: DocumentationService {
138138
}
139139

140140
let bundle: DocumentationBundle
141-
let dataProvider: DocumentationBundleDataProvider
141+
let dataProvider: DataProvider
142142

143143
let inputProvider = DocumentationContext.InputsProvider()
144144
if let bundleLocation = request.bundleLocation,
@@ -267,7 +267,7 @@ public struct ConvertService: DocumentationService {
267267
.compactMap { (value, isDocumentationExtensionContent) -> (ResolvedTopicReference, RenderReferenceStore.TopicContent)? in
268268
let (topicReference, article) = value
269269

270-
guard let bundle = context.bundle(identifier: topicReference.bundleIdentifier) else { return nil }
270+
guard let bundle = context.bundle, bundle.identifier == topicReference.bundleIdentifier else { return nil }
271271
let renderer = DocumentationContentRenderer(documentationContext: context, bundle: bundle)
272272

273273
let documentationNodeKind: DocumentationNode.Kind = isDocumentationExtensionContent ? .unknownSymbol : .article

Sources/SwiftDocC/Infrastructure/Context/DocumentationContext+Configuration.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,15 @@ extension DocumentationContext {
9494
/// Controls whether the context stores the set of references that are manually curated.
9595
package var shouldStoreManuallyCuratedReferences: Bool = false
9696
}
97+
98+
// MARK: Topic analysis
99+
100+
/// Configuration related to topic analysis.
101+
var topicAnalysisConfiguration = TopicAnalysisConfiguration()
102+
103+
/// A collection of configuration related to topic analysis.
104+
struct TopicAnalysisConfiguration {
105+
var additionalChecks: [DocumentationContext.ReferenceCheck] = []
106+
}
97107
}
98108
}

Sources/SwiftDocC/Infrastructure/ConvertActionConverter.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,12 @@ package enum ConvertActionConverter {
6969

7070
// An inner function to gather problems for errors encountered during the conversion.
7171
//
72-
// These problems only represent unexpected thrown errors and aren't particularly user-facing but because
73-
// `DocumentationConverter.convert(outputConsumer:)` emits them as diagnostics we do the same here.
72+
// These problems only represent unexpected thrown errors and aren't particularly user-facing.
73+
// For now we emit them as diagnostics because `DocumentationConverter.convert(outputConsumer:)` (which this replaced) used to do that.
74+
//
75+
// FIXME: In the future we could simplify this control flow by not catching these errors and turning them into diagnostics.
76+
// Since both error-level diagnostics and thrown errors fail the documentation build,
77+
// the only practical different this would have is that we stop on the first unexpected error instead of processing all pages and gathering all unexpected errors.
7478
func recordProblem(from error: Swift.Error, in problems: inout [Problem], withIdentifier identifier: String) {
7579
let problem = Problem(diagnostic: Diagnostic(
7680
severity: .error,

Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,23 +33,23 @@ public final class DiagnosticConsoleWriter: DiagnosticFormattingConsumer {
3333
baseURL: URL? = nil,
3434
highlight: Bool? = nil
3535
) {
36-
self.init(stream, formattingOptions: options, baseURL: baseURL, highlight: highlight, fileManager: FileManager.default)
36+
self.init(stream, formattingOptions: options, baseURL: baseURL, highlight: highlight, dataProvider: FileManager.default)
3737
}
3838

3939
package init(
4040
_ stream: TextOutputStream = LogHandle.standardError,
4141
formattingOptions options: DiagnosticFormattingOptions = [],
4242
baseURL: URL? = nil,
4343
highlight: Bool? = nil,
44-
fileManager: FileManagerProtocol = FileManager.default
44+
dataProvider: DataProvider = FileManager.default
4545
) {
4646
outputStream = stream
4747
formattingOptions = options
4848
diagnosticFormatter = Self.makeDiagnosticFormatter(
4949
options,
5050
baseURL: baseURL,
5151
highlight: highlight ?? TerminalHelper.isConnectedToTerminal,
52-
fileManager: fileManager
52+
dataProvider: dataProvider
5353
)
5454
}
5555

@@ -79,12 +79,12 @@ public final class DiagnosticConsoleWriter: DiagnosticFormattingConsumer {
7979
_ options: DiagnosticFormattingOptions,
8080
baseURL: URL?,
8181
highlight: Bool,
82-
fileManager: FileManagerProtocol
82+
dataProvider: DataProvider
8383
) -> DiagnosticConsoleFormatter {
8484
if options.contains(.formatConsoleOutputForTools) {
8585
return IDEDiagnosticConsoleFormatter(options: options)
8686
} else {
87-
return DefaultDiagnosticConsoleFormatter(baseUrl: baseURL, highlight: highlight, options: options, fileManager: fileManager)
87+
return DefaultDiagnosticConsoleFormatter(baseUrl: baseURL, highlight: highlight, options: options, dataProvider: dataProvider)
8888
}
8989
}
9090
}
@@ -103,15 +103,15 @@ extension DiagnosticConsoleWriter {
103103
formattedDescription(for: problem, options: options, fileManager: FileManager.default)
104104
}
105105
package static func formattedDescription(for problem: Problem, options: DiagnosticFormattingOptions = [], fileManager: FileManagerProtocol = FileManager.default) -> String {
106-
let diagnosticFormatter = makeDiagnosticFormatter(options, baseURL: nil, highlight: TerminalHelper.isConnectedToTerminal, fileManager: fileManager)
106+
let diagnosticFormatter = makeDiagnosticFormatter(options, baseURL: nil, highlight: TerminalHelper.isConnectedToTerminal, dataProvider: fileManager)
107107
return diagnosticFormatter.formattedDescription(for: problem)
108108
}
109109

110110
public static func formattedDescription(for diagnostic: Diagnostic, options: DiagnosticFormattingOptions = []) -> String {
111111
formattedDescription(for: diagnostic, options: options, fileManager: FileManager.default)
112112
}
113113
package static func formattedDescription(for diagnostic: Diagnostic, options: DiagnosticFormattingOptions = [], fileManager: FileManagerProtocol) -> String {
114-
let diagnosticFormatter = makeDiagnosticFormatter(options, baseURL: nil, highlight: TerminalHelper.isConnectedToTerminal, fileManager: fileManager)
114+
let diagnosticFormatter = makeDiagnosticFormatter(options, baseURL: nil, highlight: TerminalHelper.isConnectedToTerminal, dataProvider: fileManager)
115115
return diagnosticFormatter.formattedDescription(for: diagnostic)
116116
}
117117
}
@@ -220,7 +220,7 @@ final class DefaultDiagnosticConsoleFormatter: DiagnosticConsoleFormatter {
220220
private let baseUrl: URL?
221221
private let highlight: Bool
222222
private var sourceLines: [URL: [String]] = [:]
223-
private var fileManager: FileManagerProtocol
223+
private var dataProvider: DataProvider
224224

225225
/// The number of additional lines from the source file that should be displayed both before and after the diagnostic source line.
226226
private static let contextSize = 2
@@ -229,12 +229,12 @@ final class DefaultDiagnosticConsoleFormatter: DiagnosticConsoleFormatter {
229229
baseUrl: URL?,
230230
highlight: Bool,
231231
options: DiagnosticFormattingOptions,
232-
fileManager: FileManagerProtocol
232+
dataProvider: DataProvider
233233
) {
234234
self.baseUrl = baseUrl
235235
self.highlight = highlight
236236
self.options = options
237-
self.fileManager = fileManager
237+
self.dataProvider = dataProvider
238238
}
239239

240240
func formattedDescription(for problems: some Sequence<Problem>) -> String {
@@ -507,7 +507,7 @@ extension DefaultDiagnosticConsoleFormatter {
507507
}
508508

509509
// TODO: Add support for also getting the source lines from the symbol graph files.
510-
guard let data = fileManager.contents(atPath: url.path),
510+
guard let data = try? dataProvider.contents(of: url),
511511
let content = String(data: data, encoding: .utf8)
512512
else {
513513
return []

Sources/SwiftDocC/Infrastructure/DocumentationContext.swift

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Markdown
1313
import SymbolKit
1414

1515
/// A type that provides information about documentation bundles and their content.
16+
@available(*, deprecated, message: "Pass the context its inputs at initialization instead. This deprecated API will be removed after 6.2 is released")
1617
public protocol DocumentationContextDataProvider {
1718
/// An object to notify when bundles are added or removed.
1819
var delegate: DocumentationContextDataProviderDelegate? { get set }
@@ -31,6 +32,7 @@ public protocol DocumentationContextDataProvider {
3132
}
3233

3334
/// An object that responds to changes in available documentation bundles for a specific provider.
35+
@available(*, deprecated, message: "Pass the context its inputs at initialization instead. This deprecated API will be removed after 6.2 is released")
3436
public protocol DocumentationContextDataProviderDelegate: AnyObject {
3537

3638
/// Called when the `dataProvider` has added a new documentation bundle to its list of `bundles`.
@@ -79,7 +81,7 @@ public typealias BundleIdentifier = String
7981
/// - ``children(of:kind:)``
8082
/// - ``parents(of:)``
8183
///
82-
public class DocumentationContext: DocumentationContextDataProviderDelegate {
84+
public class DocumentationContext {
8385

8486
/// An error that's encountered while interacting with a ``SwiftDocC/DocumentationContext``.
8587
public enum ContextError: DescribedError {
@@ -111,16 +113,18 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
111113
}
112114

113115
/// A class that resolves documentation links by orchestrating calls to other link resolver implementations.
114-
public var linkResolver = LinkResolver()
116+
public var linkResolver: LinkResolver
115117

116118
private enum _Provider {
119+
@available(*, deprecated, message: "Use 'DataProvider' instead. This deprecated API will be removed after 6.2 is released")
117120
case legacy(DocumentationContextDataProvider)
118-
case new(DocumentationBundleDataProvider)
121+
case new(DataProvider)
119122
}
120123
private var dataProvider: _Provider
121124

122125
/// The provider of documentation bundles for this context.
123-
var _legacyDataProvider: DocumentationContextDataProvider! {
126+
@available(*, deprecated, message: "Use 'DataProvider' instead. This deprecated API will be removed after 6.2 is released")
127+
private var _legacyDataProvider: DocumentationContextDataProvider! {
124128
get {
125129
switch dataProvider {
126130
case .legacy(let legacyDataProvider):
@@ -144,6 +148,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
144148
}
145149
}
146150

151+
/// The documentation bundle that is registered with the context.
147152
var bundle: DocumentationBundle?
148153

149154
/// A collection of configuration for this context.
@@ -285,6 +290,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
285290
/// - diagnosticEngine: The pre-configured engine that will collect problems encountered during compilation.
286291
/// - configuration: A collection of configuration for the created context.
287292
/// - Throws: If an error is encountered while registering a documentation bundle.
293+
@available(*, deprecated, message: "Pass the context its inputs at initialization instead. This deprecated API will be removed after 6.2 is released")
288294
public init(
289295
dataProvider: DocumentationContextDataProvider,
290296
diagnosticEngine: DiagnosticEngine = .init(),
@@ -293,6 +299,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
293299
self.dataProvider = .legacy(dataProvider)
294300
self.diagnosticEngine = diagnosticEngine
295301
self._configuration = configuration
302+
self.linkResolver = LinkResolver(dataProvider: FileManager.default)
296303

297304
_legacyDataProvider.delegate = self
298305

@@ -311,14 +318,15 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
311318
/// - Throws: If an error is encountered while registering a documentation bundle.
312319
package init(
313320
bundle: DocumentationBundle,
314-
dataProvider: DocumentationBundleDataProvider,
321+
dataProvider: DataProvider,
315322
diagnosticEngine: DiagnosticEngine = .init(),
316323
configuration: Configuration = .init()
317324
) throws {
318325
self.bundle = bundle
319326
self.dataProvider = .new(dataProvider)
320327
self.diagnosticEngine = diagnosticEngine
321328
self._configuration = configuration
329+
self.linkResolver = LinkResolver(dataProvider: dataProvider)
322330

323331
ResolvedTopicReference.enableReferenceCaching(for: bundle.identifier)
324332
try register(bundle)
@@ -329,6 +337,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
329337
/// - Parameters:
330338
/// - dataProvider: The provider that added this bundle.
331339
/// - bundle: The bundle that was added.
340+
@available(*, deprecated, message: "Pass the context its inputs at initialization instead. This deprecated API will be removed after 6.2 is released")
332341
public func dataProvider(_ dataProvider: DocumentationContextDataProvider, didAddBundle bundle: DocumentationBundle) throws {
333342
try benchmark(wrap: Benchmark.Duration(id: "bundle-registration")) {
334343
// Enable reference caching for this documentation bundle.
@@ -343,6 +352,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
343352
/// - Parameters:
344353
/// - dataProvider: The provider that removed this bundle.
345354
/// - bundle: The bundle that was removed.
355+
@available(*, deprecated, message: "Pass the context its inputs at initialization instead. This deprecated API will be removed after 6.2 is released")
346356
public func dataProvider(_ dataProvider: DocumentationContextDataProvider, didRemoveBundle bundle: DocumentationBundle) throws {
347357
linkResolver.localResolver?.unregisterBundle(identifier: bundle.identifier)
348358

@@ -354,7 +364,20 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
354364
}
355365

356366
/// The documentation bundles that are currently registered with the context.
367+
@available(*, deprecated, message: "Use 'bundle' instead. This deprecated API will be removed after 6.2 is released")
357368
public var registeredBundles: some Collection<DocumentationBundle> {
369+
_registeredBundles
370+
}
371+
372+
/// Returns the `DocumentationBundle` with the given `identifier` if it's registered with the context, otherwise `nil`.
373+
@available(*, deprecated, message: "Use 'bundle' instead. This deprecated API will be removed after 6.2 is released")
374+
public func bundle(identifier: String) -> DocumentationBundle? {
375+
_bundle(identifier: identifier)
376+
}
377+
378+
// Remove these when removing `registeredBundles` and `bundle(identifier:)`.
379+
// These exist so that internal code that need to be compatible with legacy data providers can access the bundles without deprecation warnings.
380+
var _registeredBundles: [DocumentationBundle] {
358381
switch dataProvider {
359382
case .legacy(let legacyDataProvider):
360383
Array(legacyDataProvider.bundles.values)
@@ -363,8 +386,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
363386
}
364387
}
365388

366-
/// Returns the `DocumentationBundle` with the given `identifier` if it's registered with the context, otherwise `nil`.
367-
public func bundle(identifier: String) -> DocumentationBundle? {
389+
func _bundle(identifier: String) -> DocumentationBundle? {
368390
switch dataProvider {
369391
case .legacy(let legacyDataProvider):
370392
return legacyDataProvider.bundles[identifier]
@@ -2551,14 +2573,13 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
25512573

25522574
/// A closure type getting the information about a reference in a context and returns any possible problems with it.
25532575
public typealias ReferenceCheck = (DocumentationContext, ResolvedTopicReference) -> [Problem]
2554-
2555-
private var checks: [ReferenceCheck] = []
25562576

25572577
/// Adds new checks to be run during the global topic analysis; after a bundle has been fully registered and its topic graph has been fully built.
25582578
///
25592579
/// - Parameter newChecks: The new checks to add.
2580+
@available(*, deprecated, message: "Use 'TopicAnalysisConfiguration.additionalChecks' instead. This deprecated API will be removed after 6.2 is released")
25602581
public func addGlobalChecks(_ newChecks: [ReferenceCheck]) {
2561-
checks.append(contentsOf: newChecks)
2582+
configuration.topicAnalysisConfiguration.additionalChecks.append(contentsOf: newChecks)
25622583
}
25632584

25642585
/// Crawls the hierarchy of the given list of nodes, adding relationships in the topic graph for all resolvable task group references.
@@ -2624,7 +2645,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
26242645
func topicGraphGlobalAnalysis() {
26252646
// Run any checks added to the context.
26262647
let problems = knownIdentifiers.flatMap { reference in
2627-
return checks.flatMap { check in
2648+
return configuration.topicAnalysisConfiguration.additionalChecks.flatMap { check in
26282649
return check(self, reference)
26292650
}
26302651
}
@@ -2672,7 +2693,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
26722693
- Throws: ``ContextError/notFound(_:)` if a resource with the given was not found.
26732694
*/
26742695
public func resource(with identifier: ResourceReference, trait: DataTraitCollection = .init()) throws -> Data {
2675-
guard let bundle = bundle(identifier: identifier.bundleIdentifier),
2696+
guard let bundle,
26762697
let assetManager = assetManagers[identifier.bundleIdentifier],
26772698
let asset = assetManager.allData(named: identifier.path) else {
26782699
throw ContextError.notFound(identifier.url)
@@ -3055,3 +3076,6 @@ extension DataAsset {
30553076
}
30563077
}
30573078
}
3079+
3080+
@available(*, deprecated, message: "This deprecated API will be removed after 6.2 is released")
3081+
extension DocumentationContext: DocumentationContextDataProviderDelegate {}

Sources/SwiftDocC/Infrastructure/DocumentationConverter.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Foundation
1717
/// ## See Also
1818
///
1919
/// - ``DocumentationConverter``
20+
@available(*, deprecated, message: "This deprecated API will be removed after 6.2 is released")
2021
public protocol DocumentationConverterProtocol {
2122
/// Converts documentation, outputting products using the given output consumer.
2223
/// - Parameter outputConsumer: The output consumer for content produced during conversion.
@@ -37,6 +38,7 @@ public protocol DocumentationConverterProtocol {
3738
///
3839
/// You can also configure the documentation converter to emit extra metadata such as linkable entities and indexing records
3940
/// information.
41+
@available(*, deprecated, message: "This deprecated API will be removed after 6.2 is released")
4042
public struct DocumentationConverter: DocumentationConverterProtocol {
4143
let rootURL: URL?
4244
let emitDigest: Bool

0 commit comments

Comments
 (0)