diff --git a/Sources/SwiftDocC/Checker/Checkers/DuplicateTopicsSection.swift b/Sources/SwiftDocC/Checker/Checkers/DuplicateTopicsSection.swift index d4ad680891..5e3662eef7 100644 --- a/Sources/SwiftDocC/Checker/Checkers/DuplicateTopicsSection.swift +++ b/Sources/SwiftDocC/Checker/Checkers/DuplicateTopicsSection.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -11,9 +11,7 @@ public import Foundation public import Markdown -/** - A `Document` may only have one level-2 "Topics" heading at the top level, since it serves as structured data for a documentation bundle's hierarchy. - */ +/// A document only supports a single level-2 "Topics" heading at the top level, because it's used to define the documentation's hierarchy. public struct DuplicateTopicsSections: Checker { /// The list of level-2 headings with the text "Topics" found in the document. public var foundTopicsHeadings = [Heading]() diff --git a/Sources/SwiftDocC/Converter/DocumentationContextConverter.swift b/Sources/SwiftDocC/Converter/DocumentationContextConverter.swift index 72e23665bb..03bcf45d03 100644 --- a/Sources/SwiftDocC/Converter/DocumentationContextConverter.swift +++ b/Sources/SwiftDocC/Converter/DocumentationContextConverter.swift @@ -20,9 +20,6 @@ public class DocumentationContextConverter { /// The context the converter uses to resolve references it finds in the documentation node's content. let context: DocumentationContext - /// The bundle that contains the content from which the documentation node originated. - let bundle: DocumentationBundle - /// A context that contains common pre-rendered pieces of content. let renderContext: RenderContext @@ -43,12 +40,11 @@ public class DocumentationContextConverter { /// The remote source control repository where the documented module's source is hosted. let sourceRepository: SourceRepository? - /// Creates a new node converter for the given bundle and context. + /// Creates a new node converter for the given context. /// - /// The converter uses bundle and context to resolve references to other documentation and describe the documentation hierarchy. + /// The converter uses the context to resolve references to other documentation and describe the documentation hierarchy. /// /// - Parameters: - /// - bundle: The bundle that contains the content from which the documentation node originated. /// - context: The context that the converter uses to to resolve references it finds in the documentation node's content. /// - renderContext: A context that contains common pre-rendered pieces of content. /// - emitSymbolSourceFileURIs: Whether the documentation converter should include @@ -61,7 +57,6 @@ public class DocumentationContextConverter { /// - sourceRepository: The source repository where the documentation's sources are hosted. /// - symbolIdentifiersWithExpandedDocumentation: A list of symbol IDs that have version of their documentation page with more content that a renderer can link to. public init( - bundle: DocumentationBundle, context: DocumentationContext, renderContext: RenderContext, emitSymbolSourceFileURIs: Bool = false, @@ -69,7 +64,6 @@ public class DocumentationContextConverter { sourceRepository: SourceRepository? = nil, symbolIdentifiersWithExpandedDocumentation: [String]? = nil ) { - self.bundle = bundle self.context = context self.renderContext = renderContext self.shouldEmitSymbolSourceFileURIs = emitSymbolSourceFileURIs @@ -78,6 +72,26 @@ public class DocumentationContextConverter { self.symbolIdentifiersWithExpandedDocumentation = symbolIdentifiersWithExpandedDocumentation } + @available(*, deprecated, renamed: "init(context:renderContext:emitSymbolSourceFileURIs:emitSymbolAccessLevels:sourceRepository:symbolIdentifiersWithExpandedDocumentation:)", message: "Use 'init(context:renderContext:emitSymbolSourceFileURIs:emitSymbolAccessLevels:sourceRepository:symbolIdentifiersWithExpandedDocumentation:)' instead. This deprecated API will be removed after 6.3 is released") + public convenience init( + bundle _: DocumentationBundle, + context: DocumentationContext, + renderContext: RenderContext, + emitSymbolSourceFileURIs: Bool = false, + emitSymbolAccessLevels: Bool = false, + sourceRepository: SourceRepository? = nil, + symbolIdentifiersWithExpandedDocumentation: [String]? = nil + ) { + self.init( + context: context, + renderContext: renderContext, + emitSymbolSourceFileURIs: emitSymbolSourceFileURIs, + emitSymbolAccessLevels: emitSymbolAccessLevels, + sourceRepository: sourceRepository, + symbolIdentifiersWithExpandedDocumentation: symbolIdentifiersWithExpandedDocumentation + ) + } + /// Converts a documentation node to a render node. /// /// Convert a documentation node into a render node to get a self-contained, persist-able representation of a given topic's data, so you can write it to disk, send it over a network, or otherwise process it. @@ -91,7 +105,6 @@ public class DocumentationContextConverter { var translator = RenderNodeTranslator( context: context, - bundle: bundle, identifier: node.reference, renderContext: renderContext, emitSymbolSourceFileURIs: shouldEmitSymbolSourceFileURIs, diff --git a/Sources/SwiftDocC/Converter/DocumentationNodeConverter.swift b/Sources/SwiftDocC/Converter/DocumentationNodeConverter.swift index 77804359e8..4844e7daba 100644 --- a/Sources/SwiftDocC/Converter/DocumentationNodeConverter.swift +++ b/Sources/SwiftDocC/Converter/DocumentationNodeConverter.swift @@ -15,21 +15,21 @@ public struct DocumentationNodeConverter { /// The context the converter uses to resolve references it finds in the documentation node's content. let context: DocumentationContext - /// The bundle that contains the content from which the documentation node originated. - let bundle: DocumentationBundle - - /// Creates a new node converter for the given bundle and context. + /// Creates a new node converter for the given context. /// - /// The converter uses bundle and context to resolve references to other documentation and describe the documentation hierarchy. + /// The converter uses context to resolve references to other documentation and describe the documentation hierarchy. /// /// - Parameters: - /// - bundle: The bundle that contains the content from which the documentation node originated. /// - context: The context that the converter uses to to resolve references it finds in the documentation node's content. - public init(bundle: DocumentationBundle, context: DocumentationContext) { - self.bundle = bundle + public init(context: DocumentationContext) { self.context = context } + @available(*, deprecated, renamed: "init(context:)", message: "Use 'init(context:)' instead. This deprecated API will be removed after 6.3 is released") + public init(bundle _: DocumentationBundle, context: DocumentationContext) { + self.init(context: context) + } + /// Converts a documentation node to a render node. /// /// Convert a documentation node into a render node to get a self-contained, persistable representation of a given topic's data, so you can write it to disk, send it over a network, or otherwise process it. @@ -37,7 +37,7 @@ public struct DocumentationNodeConverter { /// - node: The documentation node to convert. /// - Returns: The render node representation of the documentation node. public func convert(_ node: DocumentationNode) -> RenderNode { - var translator = RenderNodeTranslator(context: context, bundle: bundle, identifier: node.reference) + var translator = RenderNodeTranslator(context: context, identifier: node.reference) return translator.visit(node.semantic) as! RenderNode } } diff --git a/Sources/SwiftDocC/DocumentationService/Convert/ConvertService+DataProvider.swift b/Sources/SwiftDocC/DocumentationService/Convert/ConvertService+DataProvider.swift index 75fc4b0a72..81859f7b94 100644 --- a/Sources/SwiftDocC/DocumentationService/Convert/ConvertService+DataProvider.swift +++ b/Sources/SwiftDocC/DocumentationService/Convert/ConvertService+DataProvider.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ import Foundation extension ConvertService { /// Creates a bundle and an associated in-memory data provider from the information of a given convert request - static func makeBundleAndInMemoryDataProvider(_ request: ConvertRequest) -> (bundle: DocumentationBundle, provider: InMemoryDataProvider) { + static func makeBundleAndInMemoryDataProvider(_ request: ConvertRequest) -> (inputs: DocumentationContext.Inputs, provider: InMemoryDataProvider) { var files: [URL: Data] = [:] files.reserveCapacity( request.symbolGraphs.count @@ -21,10 +21,10 @@ extension ConvertService { + request.miscResourceURLs.count ) for markupFile in request.markupFiles { - files[makeURL().appendingPathExtension(DocumentationBundleFileTypes.referenceFileExtension)] = markupFile + files[makeURL().appendingPathExtension(DocumentationInputFileTypes.referenceFileExtension)] = markupFile } for tutorialFile in request.tutorialFiles { - files[makeURL().appendingPathExtension(DocumentationBundleFileTypes.tutorialFileExtension)] = tutorialFile + files[makeURL().appendingPathExtension(DocumentationInputFileTypes.tutorialFileExtension)] = tutorialFile } let markupFileURL = Array(files.keys) @@ -37,8 +37,8 @@ extension ConvertService { } return ( - DocumentationBundle( - info: request.bundleInfo, + DocumentationContext.Inputs( + info: request.info, symbolGraphURLs: symbolGraphURLs, markupURLs: markupFileURL, miscResourceURLs: request.miscResourceURLs diff --git a/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift b/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift index fc22a5c356..b63b083a04 100644 --- a/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift +++ b/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift @@ -128,7 +128,7 @@ public struct ConvertService: DocumentationService { if let linkResolvingServer { let resolver = try OutOfProcessReferenceResolver( - bundleID: request.bundleInfo.id, + bundleID: request.info.id, server: linkResolvingServer, convertRequestIdentifier: messageIdentifier ) @@ -137,28 +137,28 @@ public struct ConvertService: DocumentationService { configuration.externalDocumentationConfiguration.globalSymbolResolver = resolver } - let bundle: DocumentationBundle + let inputs: DocumentationContext.Inputs let dataProvider: any DataProvider let inputProvider = DocumentationContext.InputsProvider() - if let bundleLocation = request.bundleLocation, - let catalogURL = try inputProvider.findCatalog(startingPoint: bundleLocation, allowArbitraryCatalogDirectories: allowArbitraryCatalogDirectories) + if let catalogLocation = request.catalogLocation, + let catalogURL = try inputProvider.findCatalog(startingPoint: catalogLocation, allowArbitraryCatalogDirectories: allowArbitraryCatalogDirectories) { - let bundleDiscoveryOptions = try BundleDiscoveryOptions( - fallbackInfo: request.bundleInfo, + let bundleDiscoveryOptions = try CatalogDiscoveryOptions( + fallbackInfo: request.info, additionalSymbolGraphFiles: [] ) - bundle = try inputProvider.makeInputs(contentOf: catalogURL, options: bundleDiscoveryOptions) + inputs = try inputProvider.makeInputs(contentOf: catalogURL, options: bundleDiscoveryOptions) dataProvider = FileManager.default } else { - (bundle, dataProvider) = Self.makeBundleAndInMemoryDataProvider(request) + (inputs, dataProvider) = Self.makeBundleAndInMemoryDataProvider(request) } - let context = try await DocumentationContext(bundle: bundle, dataProvider: dataProvider, configuration: configuration) + let context = try await DocumentationContext(inputs: inputs, dataProvider: dataProvider, configuration: configuration) // Precompute the render context - let renderContext = RenderContext(documentationContext: context, bundle: bundle) + let renderContext = RenderContext(documentationContext: context) let symbolIdentifiersMeetingRequirementsForExpandedDocumentation: [String]? = request.symbolIdentifiersWithExpandedDocumentation?.compactMap { identifier, expandedDocsRequirement in guard let documentationNode = context.documentationCache[identifier] else { @@ -168,7 +168,6 @@ public struct ConvertService: DocumentationService { return documentationNode.meetsExpandedDocumentationRequirements(expandedDocsRequirement) ? identifier : nil } let converter = DocumentationContextConverter( - bundle: bundle, context: context, renderContext: renderContext, emitSymbolSourceFileURIs: request.emitSymbolSourceFileURIs, @@ -243,12 +242,12 @@ public struct ConvertService: DocumentationService { .compactMap { (value, isDocumentationExtensionContent) -> (ResolvedTopicReference, RenderReferenceStore.TopicContent)? in let (topicReference, article) = value - let bundle = context.bundle - guard bundle.id == topicReference.bundleID else { return nil } - let renderer = DocumentationContentRenderer(documentationContext: context, bundle: bundle) + let inputs = context.inputs + guard inputs.id == topicReference.bundleID else { return nil } + let renderer = DocumentationContentRenderer(documentationContext: context) let documentationNodeKind: DocumentationNode.Kind = isDocumentationExtensionContent ? .unknownSymbol : .article - let overridingDocumentationNode = DocumentationContext.documentationNodeAndTitle(for: article, kind: documentationNodeKind, in: bundle)?.node + let overridingDocumentationNode = DocumentationContext.documentationNodeAndTitle(for: article, kind: documentationNodeKind, in: inputs)?.node var dependencies = RenderReferenceDependencies() let renderReference = renderer.renderReference(for: topicReference, with: overridingDocumentationNode, dependencies: &dependencies) diff --git a/Sources/SwiftDocC/DocumentationService/Convert/Fallback Link Resolution/ConvertServiceFallbackResolver.swift b/Sources/SwiftDocC/DocumentationService/Convert/Fallback Link Resolution/ConvertServiceFallbackResolver.swift index 8ee83c262e..d96bef0fee 100644 --- a/Sources/SwiftDocC/DocumentationService/Convert/Fallback Link Resolution/ConvertServiceFallbackResolver.swift +++ b/Sources/SwiftDocC/DocumentationService/Convert/Fallback Link Resolution/ConvertServiceFallbackResolver.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2024 Apple Inc. and the Swift project authors + Copyright (c) 2024-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -26,7 +26,7 @@ protocol ConvertServiceFallbackResolver { /// The bundle identifier for the fallback resolver. /// /// The fallback resolver will only resolve links with this bundle identifier. - var bundleID: DocumentationBundle.Identifier { get } + var bundleID: DocumentationContext.Inputs.Identifier { get } // MARK: References diff --git a/Sources/SwiftDocC/DocumentationService/Models/Services/Convert/ConvertRequest.swift b/Sources/SwiftDocC/DocumentationService/Models/Services/Convert/ConvertRequest.swift index e09c124503..e12ea04175 100644 --- a/Sources/SwiftDocC/DocumentationService/Models/Services/Convert/ConvertRequest.swift +++ b/Sources/SwiftDocC/DocumentationService/Models/Services/Convert/ConvertRequest.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -13,11 +13,17 @@ public import Foundation /// A request to convert in-memory documentation. public struct ConvertRequest: Codable { - /// Information about the documentation bundle to convert. + /// Information about the documentation catalog to convert. /// /// ## See Also - /// - ``DocumentationBundle/Info`` - public var bundleInfo: DocumentationBundle.Info + /// - ``DocumentationContext/Inputs/Info`` + public var info: DocumentationContext.Inputs.Info + + @available(*, deprecated, renamed: "info", message: "Use 'info' instead. This deprecated API will be removed after 6.3 is released.") + public var bundleInfo: URL? { + get { catalogLocation } + set { catalogLocation = newValue } + } /// Feature flags to enable when performing this convert request. public var featureFlags: FeatureFlags @@ -51,16 +57,22 @@ public struct ConvertRequest: Codable { /// Whether the conversion's render reference store should be included in the response. /// /// The ``RenderReferenceStore`` contains compiled information for documentation nodes registered in a context. This - /// information can be used as a lightweight index of the available documentation content in the bundle that's been converted. + /// information can be used as a lightweight index of the available documentation content in the context that's been converted. public var includeRenderReferenceStore: Bool? - /// The file location of the bundle to convert, if any. - public var bundleLocation: URL? + /// The file location of the catalog to convert, if any. + public var catalogLocation: URL? + + @available(*, deprecated, renamed: "catalogLocation", message: "Use 'catalogLocation' instead. This deprecated API will be removed after 6.3 is released.") + public var bundleLocation: URL? { + get { catalogLocation } + set { catalogLocation = newValue } + } - /// The symbols graph data included in the documentation bundle to convert. + /// The symbols graph data included in the documentation catalog to convert. /// /// ## See Also - /// - ``DocumentationBundle/symbolGraphURLs`` + /// - ``DocumentationContext/Inputs/symbolGraphURLs`` public var symbolGraphs: [Data] /// The mapping of external symbol identifiers to lines of a documentation comment that overrides the value in the symbol graph. @@ -72,20 +84,20 @@ public struct ConvertRequest: Codable { /// Whether the conversion's rendered documentation should include source file location metadata. public var emitSymbolSourceFileURIs: Bool - /// The article and documentation extension file data included in the documentation bundle to convert. + /// The article and documentation extension file data included in the documentation catalog to convert. /// /// ## See Also - /// - ``DocumentationBundle/markupURLs`` + /// - ``DocumentationContext/Inputs/markupURLs`` public var markupFiles: [Data] - /// The tutorial file data included in the documentation bundle to convert. + /// The tutorial file data included in the documentation catalog to convert. public var tutorialFiles: [Data] - /// The on-disk resources in the documentation bundle to convert. + /// The on-disk resources in the documentation catalog to convert. /// /// ## See Also - /// - ``DocumentationBundle/miscResourceURLs`` + /// - ``DocumentationContext/Inputs/miscResourceURLs`` public var miscResourceURLs: [URL] /// The symbol identifiers that have an expanded documentation page available if they meet the associated access level requirement. @@ -97,31 +109,31 @@ public struct ConvertRequest: Codable { /// Creates a request to convert in-memory documentation. /// - Parameters: - /// - bundleInfo: Information about the bundle to convert. + /// - info: Information about the catalog to convert. /// - featureFlags: Feature flags to enable when performing this convert request. /// - externalIDsToConvert: The external IDs of the symbols to convert. /// - documentPathsToConvert: The paths of the documentation nodes to convert. /// - includeRenderReferenceStore: Whether the conversion's render reference store should be included in the /// response. - /// - bundleLocation: The file location of the documentation bundle to convert, if any. - /// - symbolGraphs: The symbols graph data included in the documentation bundle to convert. + /// - catalogLocation: The file location of the documentation catalog to convert, if any. + /// - symbolGraphs: The symbols graph data included in the documentation catalog to convert. /// - overridingDocumentationComments: The mapping of external symbol identifiers to lines of a /// documentation comment that overrides the value in the symbol graph. /// - emitSymbolSourceFileURIs: Whether the conversion's rendered documentation should include source file location metadata. /// - knownDisambiguatedSymbolPathComponents: The mapping of external symbol identifiers to /// known disambiguated symbol path components. - /// - markupFiles: The article and documentation extension file data included in the documentation bundle to convert. - /// - tutorialFiles: The tutorial file data included in the documentation bundle to convert. - /// - miscResourceURLs: The on-disk resources in the documentation bundle to convert. + /// - markupFiles: The article and documentation extension file data included in the documentation catalog to convert. + /// - tutorialFiles: The tutorial file data included in the documentation catalog to convert. + /// - miscResourceURLs: The on-disk resources in the documentation catalog to convert. /// - symbolIdentifiersWithExpandedDocumentation: A dictionary of identifiers to requirements for these symbols to have expanded /// documentation available. public init( - bundleInfo: DocumentationBundle.Info, + info: DocumentationContext.Inputs.Info, featureFlags: FeatureFlags = FeatureFlags(), externalIDsToConvert: [String]?, documentPathsToConvert: [String]? = nil, includeRenderReferenceStore: Bool? = nil, - bundleLocation: URL? = nil, + catalogLocation: URL? = nil, symbolGraphs: [Data], overridingDocumentationComments: [String: [Line]]? = nil, knownDisambiguatedSymbolPathComponents: [String: [String]]? = nil, @@ -134,7 +146,7 @@ public struct ConvertRequest: Codable { self.externalIDsToConvert = externalIDsToConvert self.documentPathsToConvert = documentPathsToConvert self.includeRenderReferenceStore = includeRenderReferenceStore - self.bundleLocation = bundleLocation + self.catalogLocation = catalogLocation self.symbolGraphs = symbolGraphs self.overridingDocumentationComments = overridingDocumentationComments self.knownDisambiguatedSymbolPathComponents = knownDisambiguatedSymbolPathComponents @@ -148,10 +160,45 @@ public struct ConvertRequest: Codable { self.markupFiles = markupFiles self.tutorialFiles = tutorialFiles self.miscResourceURLs = miscResourceURLs - self.bundleInfo = bundleInfo + self.info = info self.featureFlags = featureFlags self.symbolIdentifiersWithExpandedDocumentation = symbolIdentifiersWithExpandedDocumentation } + + @available(*, deprecated, renamed: "init(info:featureFlags:externalIDsToConvert:documentPathsToConvert:includeRenderReferenceStore:catalogLocation:symbolGraphs:overridingDocumentationComments:knownDisambiguatedSymbolPathComponents:emitSymbolSourceFileURIs:markupFiles:tutorialFiles:miscResourceURLs:symbolIdentifiersWithExpandedDocumentation:)", message: "Use 'init(info:featureFlags:externalIDsToConvert:documentPathsToConvert:includeRenderReferenceStore:catalogLocation:symbolGraphs:overridingDocumentationComments:knownDisambiguatedSymbolPathComponents:emitSymbolSourceFileURIs:markupFiles:tutorialFiles:miscResourceURLs:symbolIdentifiersWithExpandedDocumentation:)' instead. This deprecated API will be removed after 6.3 is released.") + public init( + bundleInfo: DocumentationContext.Inputs.Info, + featureFlags: FeatureFlags = FeatureFlags(), + externalIDsToConvert: [String]?, + documentPathsToConvert: [String]? = nil, + includeRenderReferenceStore: Bool? = nil, + bundleLocation: URL? = nil, + symbolGraphs: [Data], + overridingDocumentationComments: [String: [Line]]? = nil, + knownDisambiguatedSymbolPathComponents: [String: [String]]? = nil, + emitSymbolSourceFileURIs: Bool = true, + markupFiles: [Data], + tutorialFiles: [Data] = [], + miscResourceURLs: [URL], + symbolIdentifiersWithExpandedDocumentation: [String: ExpandedDocumentationRequirements]? = nil + ) { + self.init( + info: bundleInfo, + featureFlags: featureFlags, + externalIDsToConvert: externalIDsToConvert, + documentPathsToConvert: documentPathsToConvert, + includeRenderReferenceStore: includeRenderReferenceStore, + catalogLocation: bundleLocation, + symbolGraphs: symbolGraphs, + overridingDocumentationComments: overridingDocumentationComments, + knownDisambiguatedSymbolPathComponents: knownDisambiguatedSymbolPathComponents, + emitSymbolSourceFileURIs: emitSymbolSourceFileURIs, + markupFiles: markupFiles, + tutorialFiles: tutorialFiles, + miscResourceURLs: miscResourceURLs, + symbolIdentifiersWithExpandedDocumentation: symbolIdentifiersWithExpandedDocumentation + ) + } } extension ConvertRequest { diff --git a/Sources/SwiftDocC/DocumentationService/Models/Services/Convert/ConvertResponse.swift b/Sources/SwiftDocC/DocumentationService/Models/Services/Convert/ConvertResponse.swift index 264432825f..27071b2f62 100644 --- a/Sources/SwiftDocC/DocumentationService/Models/Services/Convert/ConvertResponse.swift +++ b/Sources/SwiftDocC/DocumentationService/Models/Services/Convert/ConvertResponse.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -18,10 +18,10 @@ public struct ConvertResponse: Codable { /// The render nodes that were created as part of the conversion, encoded as JSON. public var renderNodes: [Data] - /// The render reference store that was created as part of the bundle's conversion, encoded as JSON. + /// The render reference store that was created as part of the documentation's conversion, encoded as JSON. /// /// The ``RenderReferenceStore`` contains compiled information for documentation nodes that were registered as part of - /// the conversion. This information can be used as a lightweight index of the available documentation content in the bundle that's + /// the conversion. This information can be used as a lightweight index of the available documentation content in the context that's /// been converted. public var renderReferenceStore: Data? diff --git a/Sources/SwiftDocC/Indexing/Navigator/AvailabilityIndex+Ext.swift b/Sources/SwiftDocC/Indexing/Navigator/AvailabilityIndex+Ext.swift index 1309a484c7..3a6e8cc94d 100644 --- a/Sources/SwiftDocC/Indexing/Navigator/AvailabilityIndex+Ext.swift +++ b/Sources/SwiftDocC/Indexing/Navigator/AvailabilityIndex+Ext.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -63,7 +63,7 @@ extension AvailabilityIndex { // MARK: - InterfaceLanguage /** - Interface Language identifies a programming language used to index a content of a documentation bundle. + Interface Language identifies a programming language used to index a content of a documentation context. - Note: The name reflects what a render node JSON provides to identify a programming language. The name has been decided to avoid confusion with locale languages. diff --git a/Sources/SwiftDocC/Indexing/Navigator/NavigatorIndex.swift b/Sources/SwiftDocC/Indexing/Navigator/NavigatorIndex.swift index 4024bf3f93..334bfbf117 100644 --- a/Sources/SwiftDocC/Indexing/Navigator/NavigatorIndex.swift +++ b/Sources/SwiftDocC/Indexing/Navigator/NavigatorIndex.swift @@ -14,7 +14,7 @@ import Crypto /** A `NavigatorIndex` contains all the necessary information to display the data inside a navigator. The data ranges from the tree to the necessary pieces of information to filter the content and perform actions in a fast way. - A navigator index is created per bundle and needs a bundle identifier to correctly work. Anonymous bundles are allowed, but they limit + A navigator index is created per context and needs a bundle identifier to correctly work. Anonymous bundles are allowed, but they limit the functionalities of the index. A `NavigatorIndex` is composed by two main components: diff --git a/Sources/SwiftDocC/Infrastructure/Bundle Assets/BundleData.swift b/Sources/SwiftDocC/Infrastructure/Bundle Assets/BundleData.swift index afbd5893e5..49110d0b58 100644 --- a/Sources/SwiftDocC/Infrastructure/Bundle Assets/BundleData.swift +++ b/Sources/SwiftDocC/Infrastructure/Bundle Assets/BundleData.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -20,7 +20,7 @@ public struct BundleData { /// Creates a bundle data value given its location and an associated trait collection. /// - Parameters: - /// - url: The location of the resource in the documentation bundle. + /// - url: The location of the resource in the documentation catalog. /// - traitCollection: An optional trait collection associated with the resource. public init(url: URL, traitCollection: DataTraitCollection?) { self.url = url diff --git a/Sources/SwiftDocC/Infrastructure/Bundle Assets/DataAssetManager.swift b/Sources/SwiftDocC/Infrastructure/Bundle Assets/DataAssetManager.swift index c36f2542dc..86d2926fbc 100644 --- a/Sources/SwiftDocC/Infrastructure/Bundle Assets/DataAssetManager.swift +++ b/Sources/SwiftDocC/Infrastructure/Bundle Assets/DataAssetManager.swift @@ -348,10 +348,10 @@ public struct AssetReference: Hashable, Codable { public var assetName: String /// The identifier of the bundle the asset is apart of. - public let bundleID: DocumentationBundle.Identifier + public let bundleID: DocumentationContext.Inputs.Identifier /// Creates a reference from a given asset name and the bundle it is apart of. - public init(assetName: String, bundleID: DocumentationBundle.Identifier) { + public init(assetName: String, bundleID: DocumentationContext.Inputs.Identifier) { self.assetName = assetName self.bundleID = bundleID } diff --git a/Sources/SwiftDocC/Infrastructure/Context/DocumentationContext+Configuration.swift b/Sources/SwiftDocC/Infrastructure/Context/DocumentationContext+Configuration.swift index b7bcdb3293..a0ff4ddce3 100644 --- a/Sources/SwiftDocC/Infrastructure/Context/DocumentationContext+Configuration.swift +++ b/Sources/SwiftDocC/Infrastructure/Context/DocumentationContext+Configuration.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2024 Apple Inc. and the Swift project authors + Copyright (c) 2024-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -36,7 +36,7 @@ extension DocumentationContext { /// path components into the documentation context. var knownDisambiguatedSymbolPathComponents: [String: [String]]? - /// Controls whether bundle registration should allow registering articles when no technology root is defined. + /// Controls whether catalog registration should allow registering articles when no technology root is defined. /// /// Set this property to `true` to enable registering documentation for standalone articles, /// for example when using ``ConvertService``. @@ -76,7 +76,7 @@ extension DocumentationContext { /// A collection of configuration related to external sources of documentation. public struct ExternalDocumentationConfiguration { /// The lookup of external documentation sources by their bundle identifiers. - public var sources: [DocumentationBundle.Identifier: any ExternalDocumentationSource] = [:] + public var sources: [DocumentationContext.Inputs.Identifier: any ExternalDocumentationSource] = [:] /// A type that resolves all symbols that are referenced in symbol graph files but can't be found in any of the locally available symbol graph files. public var globalSymbolResolver: (any GlobalExternalSymbolResolver)? /// A list of URLs to documentation archives that the local documentation depends on. diff --git a/Sources/SwiftDocC/Infrastructure/ConvertActionConverter.swift b/Sources/SwiftDocC/Infrastructure/ConvertActionConverter.swift index 17a5db0a70..8e4c85a19a 100644 --- a/Sources/SwiftDocC/Infrastructure/ConvertActionConverter.swift +++ b/Sources/SwiftDocC/Infrastructure/ConvertActionConverter.swift @@ -21,18 +21,16 @@ package enum ConvertActionConverter { static package let signposter = NoOpSignposterShim() #endif - /// Converts the documentation bundle in the given context and passes its output to a given consumer. + /// Converts the documentation catalog in the given context and passes its output to a given consumer. /// /// - Parameters: - /// - bundle: The documentation bundle to convert. - /// - context: The context that the bundle is a part of. + /// - context: The context of documentation information to convert. /// - outputConsumer: The consumer that the conversion passes outputs of the conversion to. /// - sourceRepository: The source repository where the documentation's sources are hosted. /// - emitDigest: Whether the conversion should pass additional metadata output––such as linkable entities information, indexing information, or asset references by asset type––to the consumer. /// - documentationCoverageOptions: The level of experimental documentation coverage information that the conversion should pass to the consumer. /// - Returns: A list of problems that occurred during the conversion (excluding the problems that the context already encountered). package static func convert( - bundle: DocumentationBundle, context: DocumentationContext, outputConsumer: some ConvertOutputConsumer & ExternalNodeConsumer, sourceRepository: SourceRepository?, @@ -61,15 +59,14 @@ package enum ConvertActionConverter { // Precompute the render context let renderContext = signposter.withIntervalSignpost("Build RenderContext", id: signposter.makeSignpostID()) { - RenderContext(documentationContext: context, bundle: bundle) + RenderContext(documentationContext: context) } try outputConsumer.consume(renderReferenceStore: renderContext.store) // Copy images, sample files, and other static assets. - try outputConsumer.consume(assetsInBundle: bundle) + try outputConsumer.consume(assetsInInputs: context.inputs) let converter = DocumentationContextConverter( - bundle: bundle, context: context, renderContext: renderContext, sourceRepository: sourceRepository @@ -104,12 +101,14 @@ package enum ConvertActionConverter { let resultsSyncQueue = DispatchQueue(label: "Convert Serial Queue", qos: .unspecified, attributes: []) let resultsGroup = DispatchGroup() + let id = context.inputs.id + // Consume external links and add them into the sidebar. for externalLink in context.externalCache { - // Here we're associating the external node with the **current** bundle's bundle ID. + // Here we're associating the external node with the **current** local bundle ID. // This is needed because nodes are only considered children if the parent and child's bundle ID match. // Otherwise, the node will be considered as a separate root node and displayed separately. - let externalRenderNode = ExternalRenderNode(externalEntity: externalLink.value, bundleIdentifier: bundle.id) + let externalRenderNode = ExternalRenderNode(externalEntity: externalLink.value, bundleIdentifier: id) try outputConsumer.consume(externalRenderNode: externalRenderNode) } @@ -192,7 +191,7 @@ package enum ConvertActionConverter { if FeatureFlags.current.isExperimentalLinkHierarchySerializationEnabled { signposter.withIntervalSignpost("Serialize link hierarchy", id: signposter.makeSignpostID()) { do { - let serializableLinkInformation = try context.linkResolver.localResolver.prepareForSerialization(bundleID: bundle.id) + let serializableLinkInformation = try context.linkResolver.localResolver.prepareForSerialization(bundleID: id) try outputConsumer.consume(linkResolutionInformation: serializableLinkInformation) if !emitDigest { @@ -225,7 +224,7 @@ package enum ConvertActionConverter { break } - try outputConsumer.consume(buildMetadata: BuildMetadata(bundleDisplayName: bundle.displayName, bundleID: bundle.id)) + try outputConsumer.consume(buildMetadata: BuildMetadata(bundleDisplayName: context.inputs.displayName, bundleID: id)) // Log the finalized topic graph checksum. benchmark(add: Benchmark.TopicGraphHash(context: context)) diff --git a/Sources/SwiftDocC/Infrastructure/ConvertOutputConsumer.swift b/Sources/SwiftDocC/Infrastructure/ConvertOutputConsumer.swift index f5e1ebd432..54d0efe4cd 100644 --- a/Sources/SwiftDocC/Infrastructure/ConvertOutputConsumer.swift +++ b/Sources/SwiftDocC/Infrastructure/ConvertOutputConsumer.swift @@ -23,7 +23,10 @@ public protocol ConvertOutputConsumer { /// > Warning: This method might be called concurrently. func consume(renderNode: RenderNode) throws - /// Consumes a documentation bundle with the purpose of extracting its on-disk assets. + /// Consumes a collection of input files with the purpose of extracting its on-disk assets. + func consume(assetsInInputs inputs: DocumentationContext.Inputs) throws + + @available(*, deprecated, renamed: "consume(assetsInInputs:)", message: "Use 'consume(assetsInInputs:)' instead. This deprecated API will be removed after 6.3 is released") func consume(assetsInBundle bundle: DocumentationBundle) throws /// Consumes the linkable element summaries produced during a conversion. @@ -65,6 +68,16 @@ public extension ConvertOutputConsumer { func _deprecated_consume(problems: [Problem]) throws {} } +@available(*, deprecated, message: "This deprecated API will be removed after 6.3 is released") +public extension ConvertOutputConsumer { + func consume(assetsInBundle bundle: DocumentationBundle) throws { + try consume(assetsInInputs: bundle) + } + + // This is needed so that conforming types don't break. After 6.3 is released we can remove it. + func consume(assetsInInputs inputs: DocumentationContext.Inputs) throws {} +} + // A package-internal protocol that callers can cast to when they need to call `_consume(problems:)` for backwards compatibility (until `consume(problems:)` is removed). package protocol _DeprecatedConsumeProblemsAccess { func _consume(problems: [Problem]) throws diff --git a/Sources/SwiftDocC/Infrastructure/DocumentationContext.swift b/Sources/SwiftDocC/Infrastructure/DocumentationContext.swift index cd7fca83d7..22ff632cfd 100644 --- a/Sources/SwiftDocC/Infrastructure/DocumentationContext.swift +++ b/Sources/SwiftDocC/Infrastructure/DocumentationContext.swift @@ -12,13 +12,7 @@ public import Foundation import Markdown import SymbolKit -/// The documentation context manages the in-memory model for the built documentation. -/// -/// A ``DocumentationWorkspace`` discovers serialized documentation bundles from a variety of sources (files on disk, databases, or web services), provides them to the `DocumentationContext`, -/// and notifies the context when bundles are added or removed using the ``DocumentationContextDataProviderDelegate`` protocol. -/// -/// When a documentation bundle is registered with the context, all of its content is loaded into memory and relationships between documentation entities are built. When this is done, the context can be queried -/// about documentation entities, resources, and relationships between entities. +/// An in-memory model for the built documentation. /// /// ## Topics /// @@ -47,7 +41,7 @@ public class DocumentationContext { /// but if such a declaration is found the symbol can have only one declaration. case unexpectedEmptyPlatformName(String) - /// The bundle registration operation is cancelled externally. + /// The context creation was cancelled externally. case registrationDisabled public var errorDescription: String { @@ -59,7 +53,7 @@ public class DocumentationContext { case .unexpectedEmptyPlatformName(let symbolIdentifier): return "Declaration without operating system name for symbol \(symbolIdentifier) cannot be merged with more declarations with operating system name for the same symbol" case .registrationDisabled: - return "The bundle registration operation is cancelled externally." + return "The context creation was cancelled externally." } } } @@ -67,11 +61,11 @@ public class DocumentationContext { /// A class that resolves documentation links by orchestrating calls to other link resolver implementations. public var linkResolver: LinkResolver - /// The data provider that the context can use to read the contents of files that belong to ``bundle``. + /// The data provider that the context can use to read the contents of files that belong to ``inputs``. let dataProvider: any DataProvider - /// The documentation bundle that is registered with the context. - let bundle: DocumentationBundle + /// The collection of input files that the context was created from. + let inputs: DocumentationContext.Inputs /// A collection of configuration for this context. public let configuration: Configuration @@ -97,9 +91,9 @@ public class DocumentationContext { } } - /// The root module nodes of the Topic Graph. + /// The root module nodes of the topic graph. /// - /// This property is initialized during the registration of a documentation bundle. + /// This property is initialized during the context's initialization. public private(set) var rootModules: [ResolvedTopicReference]! /// The topic reference of the root module, if it's the only registered module. @@ -128,8 +122,8 @@ public class DocumentationContext { /// nodes by their symbol's ID when it builds up in-memory relationships between symbols. Later, the context adds articles and other conceptual content with only their /// references for lookup. var documentationCache = LocalCache() - /// The asset managers for each documentation bundle, keyed by the bundle's identifier. - var assetManagers = [DocumentationBundle.Identifier: DataAssetManager]() + /// The asset managers for each unit of documentation, keyed by their identifiers. + var assetManagers = [DocumentationContext.Inputs.Identifier: DataAssetManager]() /// A list of non-topic links that can be resolved. var nodeAnchorSections = [ResolvedTopicReference: AnchorSection]() @@ -147,12 +141,12 @@ public class DocumentationContext { documentationCache.reference(symbolID: symbolID) ?? externalCache.reference(symbolID: symbolID) } - /// A list of all the problems that was encountered while registering and processing the documentation bundles in this context. + /// A list of all the problems that was encountered while initializing the documentation context. public var problems: [Problem] { return diagnosticEngine.problems } - /// The engine that collects problems encountered while registering and processing the documentation bundles in this context. + /// The engine that collects problems encountered while initializing the documentation context public var diagnosticEngine: DiagnosticEngine /// All the link references that have been resolved from external sources, either successfully or not. @@ -162,8 +156,7 @@ public class DocumentationContext { /// A temporary structure to hold a semantic value that hasn't yet had its links resolved. /// - /// These temporary values are only expected to exist while the documentation is being built. Once the documentation bundles have been fully registered and the topic graph - /// has been built, the documentation context shouldn't hold any semantic result values anymore. + /// These temporary values are only expected to exist while the documentation is being initialized. Once the context has been fully initialized, it shouldn't hold any semantic result values anymore. struct SemanticResult { /// The ``Semantic`` value with unresolved links. var value: S @@ -177,16 +170,14 @@ public class DocumentationContext { /// Temporary storage for articles before they are curated and moved to the documentation cache. /// - /// This storage is only used while the documentation context is being built. Once the documentation bundles have been fully registered and the topic graph - /// has been built, this list of uncurated articles will be empty. + /// This storage is only used while the documentation context is being built. Once the documentation context has been fully initialized, this list of uncurated articles will be empty. /// /// The key to lookup an article is the reference to the article itself. var uncuratedArticles = [ResolvedTopicReference: SemanticResult
]() /// Temporary storage for documentation extension files before they are curated and moved to the documentation cache. /// - /// This storage is only used while the documentation context is being built. Once the documentation bundles have been fully registered and the topic graph - /// has been built, this list of uncurated documentation extensions will be empty. + /// This storage is only used while the documentation context is being built. Once the documentation context has been fully initialized, this list of uncurated documentation extensions will be empty. /// /// The key to lookup a documentation extension file is the symbol reference from its title (level 1 heading). var uncuratedDocumentationExtensions = [ResolvedTopicReference: SemanticResult
]() @@ -194,41 +185,28 @@ public class DocumentationContext { /// Mentions of symbols within articles. var articleSymbolMentions = ArticleSymbolMentions() - /// Initializes a documentation context with a given `bundle`. + /// Initializes a documentation context with a given collection of input files. /// /// - Parameters: - /// - bundle: The bundle to register with the context. - /// - fileManager: The file manager that the context uses to read files from the bundle. + /// - inputs: The collection of documentation inputs files to register with the context. + /// - fileManager: The file manager that the context uses to read files from the inputs. /// - diagnosticEngine: The pre-configured engine that will collect problems encountered during compilation. /// - configuration: A collection of configuration for the created context. - /// - Throws: If an error is encountered while registering a documentation bundle. + /// - Throws: If an error is encountered while creating the context. package init( - bundle: DocumentationBundle, + inputs: DocumentationContext.Inputs, dataProvider: any DataProvider, diagnosticEngine: DiagnosticEngine = .init(), configuration: Configuration = .init() ) async throws { - self.bundle = bundle + self.inputs = inputs self.dataProvider = dataProvider self.diagnosticEngine = diagnosticEngine self.configuration = configuration self.linkResolver = LinkResolver(dataProvider: dataProvider) - ResolvedTopicReference.enableReferenceCaching(for: bundle.id) - try register(bundle) - } - - // Remove these when removing `registeredBundles` and `bundle(identifier:)`. - // These exist so that internal code that need to be compatible with legacy data providers can access the bundles without deprecation warnings. - @available(*, deprecated, renamed: "bundle", message: "REMOVE THIS") - var _registeredBundles: [DocumentationBundle] { - [bundle] - } - - @available(*, deprecated, renamed: "bundle", message: "REMOVE THIS") - func _bundle(identifier: String) -> DocumentationBundle? { - assert(bundle.id.rawValue == identifier, "New code shouldn't pass unknown bundle identifiers to 'DocumentationContext.bundle(identifier:)'.") - return bundle.id.rawValue == identifier ? bundle : nil + ResolvedTopicReference.enableReferenceCaching(for: inputs.id) + try register(inputs) } /// Perform semantic analysis on a given `document` at a given `source` location and append any problems found to `problems`. @@ -236,11 +214,10 @@ public class DocumentationContext { /// - Parameters: /// - document: The document to analyze. /// - source: The location of the document. - /// - bundle: The bundle that the document belongs to. /// - problems: A mutable collection of problems to update with any problem encountered during the semantic analysis. /// - Returns: The result of the semantic analysis. - private func analyze(_ document: Document, at source: URL, in bundle: DocumentationBundle, engine: DiagnosticEngine) -> Semantic? { - var analyzer = SemanticAnalyzer(source: source, bundle: bundle) + private func analyze(_ document: Document, at source: URL, engine: DiagnosticEngine) -> Semantic? { + var analyzer = SemanticAnalyzer(source: source, inputs: inputs) let result = analyzer.visit(document) engine.emit(analyzer.problems) return result @@ -281,7 +258,7 @@ public class DocumentationContext { /// Find the known plain string module name for a given module reference. /// - /// - Note: Looking up module names requires that the module names have been pre-resolved. This happens automatically at the end of bundle registration. + /// - Note: Looking up module names requires that the module names have been pre-resolved. This happens automatically at the end of the context's initialization. /// /// - Parameter moduleReference: The module reference to find the module name for. /// - Returns: The plain string name for the referenced module. @@ -292,7 +269,7 @@ public class DocumentationContext { // If no name is found it's considered a programmer error; either that the names haven't been resolved yet // or that the passed argument isn't a reference to a known module. if moduleNameCache.isEmpty { - fatalError("Incorrect use of API: '\(#function)' requires that bundles have finished registering.") + fatalError("Incorrect use of API: '\(#function)' requires that the context has fully initialized.") } fatalError("Incorrect use of API: '\(#function)' can only be used with known module references") } @@ -310,14 +287,14 @@ public class DocumentationContext { } } - /// Attempts to resolve links external to the given bundle. + /// Attempts to resolve links external to the local unit of documentation. /// /// The link resolution results are collected in ``externallyResolvedLinks``. /// /// - Parameters: /// - references: A list of references to local nodes to visit to collect links. /// - localBundleID: The local bundle ID, used to identify and skip absolute fully qualified local links. - private func preResolveExternalLinks(references: [ResolvedTopicReference], localBundleID: DocumentationBundle.Identifier) { + private func preResolveExternalLinks(references: [ResolvedTopicReference], localBundleID: DocumentationContext.Inputs.Identifier) { preResolveExternalLinks(semanticObjects: references.compactMap({ reference -> ReferencedSemanticObject? in guard let node = try? entity(with: reference), let semantic = node.semantic else { return nil } return (reference: reference, semantic: semantic) @@ -332,18 +309,18 @@ public class DocumentationContext { return (reference: from.topicGraphNode.reference, semantic: from.value) } - /// Attempts to resolve links external to the given bundle by visiting the given list of semantic objects. + /// Attempts to resolve links external to the local unit of documentation by visiting the given list of semantic objects. /// /// The resolved references are collected in ``externallyResolvedLinks``. /// /// - Parameters: /// - semanticObjects: A list of semantic objects to visit to collect links. /// - localBundleID: The local bundle ID, used to identify and skip absolute fully qualified local links. - private func preResolveExternalLinks(semanticObjects: [ReferencedSemanticObject], localBundleID: DocumentationBundle.Identifier) { + private func preResolveExternalLinks(semanticObjects: [ReferencedSemanticObject], localBundleID: DocumentationContext.Inputs.Identifier) { // If there are no external resolvers added we will not resolve any links. guard !configuration.externalDocumentationConfiguration.sources.isEmpty else { return } - let collectedExternalLinks = Synchronized([DocumentationBundle.Identifier: Set]()) + let collectedExternalLinks = Synchronized([DocumentationContext.Inputs.Identifier: Set]()) semanticObjects.concurrentPerform { _, semantic in autoreleasepool { // Walk the node and extract external link references. @@ -396,7 +373,7 @@ public class DocumentationContext { /** Attempt to resolve links in curation-only documentation, converting any ``TopicReferences`` from `.unresolved` to `.resolved` where possible. */ - private func resolveLinks(curatedReferences: Set, bundle: DocumentationBundle) { + private func resolveLinks(curatedReferences: Set, inputs: DocumentationContext.Inputs) { let signpostHandle = signposter.beginInterval("Resolve links", id: signposter.makeSignpostID()) defer { signposter.endInterval("Resolve links", signpostHandle) @@ -442,7 +419,7 @@ public class DocumentationContext { return } - var resolver = ReferenceResolver(context: self, bundle: bundle, rootReference: reference, inheritanceParentReference: symbolOriginReference) + var resolver = ReferenceResolver(context: self, rootReference: reference, inheritanceParentReference: symbolOriginReference) // Update the node with the markup that contains resolved references instead of authored links. documentationNode.semantic = autoreleasepool { @@ -456,7 +433,7 @@ public class DocumentationContext { for alternateRepresentation in alternateRepresentations { let resolutionResult = resolver.resolve( alternateRepresentation.reference, - in: bundle.rootReference, + in: inputs.rootReference, range: alternateRepresentation.originalMarkup.range, severity: .warning ) @@ -553,12 +530,12 @@ public class DocumentationContext { /// - tutorialTableOfContentsResults: The list of temporary 'tutorial table-of-contents' pages. /// - tutorials: The list of temporary 'tutorial' pages. /// - tutorialArticles: The list of temporary 'tutorialArticle' pages. - /// - bundle: The bundle to resolve links against. + /// - inputs: The collection of input files that the content for the tutorial files originate from. private func resolveLinks( tutorialTableOfContents tutorialTableOfContentsResults: [SemanticResult], tutorials: [SemanticResult], tutorialArticles: [SemanticResult], - bundle: DocumentationBundle + inputs: DocumentationContext.Inputs ) { let signpostHandle = signposter.beginInterval("Resolve links", id: signposter.makeSignpostID()) defer { @@ -572,7 +549,7 @@ public class DocumentationContext { for tableOfContentsResult in tutorialTableOfContentsResults { autoreleasepool { let url = tableOfContentsResult.source - var resolver = ReferenceResolver(context: self, bundle: bundle) + var resolver = ReferenceResolver(context: self) let tableOfContents = resolver.visit(tableOfContentsResult.value) as! TutorialTableOfContents diagnosticEngine.emit(resolver.problems) @@ -644,7 +621,7 @@ public class DocumentationContext { autoreleasepool { let url = tutorialResult.source let unresolvedTutorial = tutorialResult.value - var resolver = ReferenceResolver(context: self, bundle: bundle) + var resolver = ReferenceResolver(context: self) let tutorial = resolver.visit(unresolvedTutorial) as! Tutorial diagnosticEngine.emit(resolver.problems) @@ -678,7 +655,7 @@ public class DocumentationContext { autoreleasepool { let url = articleResult.source let unresolvedTutorialArticle = articleResult.value - var resolver = ReferenceResolver(context: self, bundle: bundle) + var resolver = ReferenceResolver(context: self) let article = resolver.visit(unresolvedTutorialArticle) as! TutorialArticle diagnosticEngine.emit(resolver.problems) @@ -709,7 +686,7 @@ public class DocumentationContext { // Articles are resolved in a separate pass } - private func registerDocuments(from bundle: DocumentationBundle) throws -> ( + private func registerDocuments(from inputs: DocumentationContext.Inputs) throws -> ( tutorialTableOfContentsResults: [SemanticResult], tutorials: [SemanticResult], tutorialArticles: [SemanticResult], @@ -729,7 +706,7 @@ public class DocumentationContext { let decodeError = Synchronized<(any Error)?>(nil) // Load and analyze documents concurrently - let analyzedDocuments: [(URL, Semantic)] = bundle.markupURLs.concurrentPerform { url, results in + let analyzedDocuments: [(URL, Semantic)] = inputs.markupURLs.concurrentPerform { url, results in guard decodeError.sync({ $0 == nil }) else { return } do { @@ -744,7 +721,7 @@ public class DocumentationContext { diagnosticEngine.emit(langChecker.problems) } - guard let analyzed = analyze(document, at: url, in: bundle, engine: diagnosticEngine) else { + guard let analyzed = analyze(document, at: url, engine: diagnosticEngine) else { return } @@ -771,8 +748,8 @@ public class DocumentationContext { // Store the references we encounter to ensure they're unique. The file name is currently the only part of the URL considered for the topic reference, so collisions may occur. let (url, analyzed) = analyzedDocument - let path = NodeURLGenerator.pathForSemantic(analyzed, source: url, bundle: bundle) - let reference = ResolvedTopicReference(bundleID: bundle.id, path: path, sourceLanguage: .swift) + let path = NodeURLGenerator.pathForSemantic(analyzed, source: url, inputInfo: inputs.info) + let reference = ResolvedTopicReference(bundleID: inputs.id, path: path, sourceLanguage: .swift) // Since documentation extensions' filenames have no impact on the URL of pages, there is no need to enforce unique filenames for them. // At this point we consider all articles with an H1 containing link a "documentation extension." @@ -897,7 +874,7 @@ public class DocumentationContext { private func nodeWithInitializedContent( reference: ResolvedTopicReference, match foundDocumentationExtension: DocumentationContext.SemanticResult
?, - bundle: DocumentationBundle + inputs: DocumentationContext.Inputs ) -> DocumentationNode { guard var updatedNode = documentationCache[reference] else { fatalError("A topic reference that has already been resolved should always exist in the cache.") @@ -907,7 +884,7 @@ public class DocumentationContext { updatedNode.initializeSymbolContent( documentationExtension: foundDocumentationExtension?.value, engine: diagnosticEngine, - bundle: bundle + inputs: inputs ) // After merging the documentation extension into the symbol, warn about deprecation summary for non-deprecated symbols. @@ -998,12 +975,8 @@ public class DocumentationContext { diagnosticEngine.emit(result.problems) } - /// Loads all graph files from a given `bundle` and merges them together while building the symbol relationships and loading any available markdown documentation for those symbols. - /// - /// - Parameter bundle: The bundle to load symbol graph files from. - /// - Returns: A pair of the references to all loaded modules and the hierarchy of all the loaded symbol's references. + /// Loads all symbol graph files from context's inputs and merges them together while building the symbol relationships and loading any available markdown documentation for those symbols. private func registerSymbols( - from bundle: DocumentationBundle, symbolGraphLoader: SymbolGraphLoader, documentationExtensions: [SemanticResult
] ) throws { @@ -1025,7 +998,7 @@ public class DocumentationContext { // Build references for all symbols in all of this module's symbol graphs. let symbolReferences = signposter.withIntervalSignpost("Disambiguate references") { - linkResolver.localResolver.referencesForSymbols(in: symbolGraphLoader.unifiedGraphs, bundle: bundle, context: self) + linkResolver.localResolver.referencesForSymbols(in: symbolGraphLoader.unifiedGraphs, context: self) } // Set the index and cache storage capacity to avoid ad-hoc storage resizing. @@ -1078,9 +1051,9 @@ public class DocumentationContext { interfaceLanguage: moduleInterfaceLanguages.first!.id ) - // Use the default module kind for this bundle if one was provided, + // Use the default module kind for this catalog if one was provided, // otherwise fall back to 'Framework' - let moduleKindDisplayName = bundle.info.defaultModuleKind ?? "Framework" + let moduleKindDisplayName = inputs.info.defaultModuleKind ?? "Framework" let moduleSymbol = SymbolGraph.Symbol( identifier: moduleIdentifier, names: SymbolGraph.Symbol.Names(title: moduleName, navigator: nil, subHeading: nil, prose: nil), @@ -1090,7 +1063,7 @@ public class DocumentationContext { kind: SymbolGraph.Symbol.Kind(parsedIdentifier: .module, displayName: moduleKindDisplayName), mixins: [:]) let moduleSymbolReference = SymbolReference(moduleName, interfaceLanguages: moduleInterfaceLanguages, defaultSymbol: moduleSymbol) - moduleReference = ResolvedTopicReference(symbolReference: moduleSymbolReference, moduleName: moduleName, bundle: bundle) + moduleReference = ResolvedTopicReference(symbolReference: moduleSymbolReference, moduleName: moduleName, inputs: inputs) signposter.withIntervalSignpost("Add symbols to topic graph", id: signposter.makeSignpostID()) { addSymbolsToTopicGraph(symbolGraph: unifiedSymbolGraph, url: fileURL, symbolReferences: symbolReferences, moduleReference: moduleReference) @@ -1181,7 +1154,7 @@ public class DocumentationContext { // FIXME: Resolve the link relative to the module https://github.com/swiftlang/swift-docc/issues/516 let reference = TopicReference.unresolved(.init(topicURL: url)) - switch resolve(reference, in: bundle.rootReference, fromSymbolLink: true) { + switch resolve(reference, in: inputs.rootReference, fromSymbolLink: true) { case .success(let resolved): if let existing = uncuratedDocumentationExtensions[resolved] { if symbolsWithMultipleDocumentationExtensionMatches[resolved] == nil { @@ -1242,7 +1215,7 @@ public class DocumentationContext { try GeneratedDocumentationTopics.createInheritedSymbolsAPICollections( relationships: uniqueRelationships, context: self, - bundle: bundle + inputs: inputs ) // Parse and prepare the nodes' content concurrently. @@ -1253,7 +1226,7 @@ public class DocumentationContext { let updatedNode = nodeWithInitializedContent( reference: finalReference, match: match, - bundle: bundle + inputs: inputs ) return (( @@ -1285,14 +1258,14 @@ public class DocumentationContext { } // Resolve any external references first - preResolveExternalLinks(references: Array(moduleReferences.values) + combinedSymbols.keys.compactMap({ documentationCache.reference(symbolID: $0) }), localBundleID: bundle.id) + preResolveExternalLinks(references: Array(moduleReferences.values) + combinedSymbols.keys.compactMap({ documentationCache.reference(symbolID: $0) }), localBundleID: inputs.id) // Look up and add symbols that are _referenced_ in the symbol graph but don't exist in the symbol graph. try resolveExternalSymbols(in: combinedSymbols, relationships: combinedRelationshipsBySelector) for (selector, relationships) in combinedRelationshipsBySelector { // Build relationships in the completed graph - buildRelationships(relationships, selector: selector, bundle: bundle) + buildRelationships(relationships, selector: selector, bundle: inputs) // Merge into target symbols the member symbols that get rendered on the same page as target. populateOnPageMemberRelationships(from: relationships, selector: selector) } @@ -1315,7 +1288,7 @@ public class DocumentationContext { func buildRelationships( _ relationships: Set, selector: UnifiedSymbolGraph.Selector, - bundle: DocumentationBundle + bundle: DocumentationContext.Inputs ) { // Find all of the relationships which refer to an extended module. let extendedModuleRelationships = ExtendedTypeFormatTransformation.collapsedExtendedModuleRelationships(from: relationships) @@ -1345,7 +1318,6 @@ public class DocumentationContext { SymbolGraphRelationshipsBuilder.addImplementationRelationship( edge: edge, selector: selector, - in: bundle, context: self, localCache: documentationCache, engine: diagnosticEngine @@ -1614,7 +1586,7 @@ public class DocumentationContext { private static let supportedImageExtensions: Set = ["png", "jpg", "jpeg", "svg", "gif"] private static let supportedVideoExtensions: Set = ["mov", "mp4"] - // TODO: Move this functionality to ``DocumentationBundleFileTypes`` (rdar://68156425). + // TODO: Move this functionality to ``DocumentationInputFileTypes`` (rdar://68156425). /// A type of asset. public enum AssetType: CustomStringConvertible { @@ -1647,12 +1619,12 @@ public class DocumentationContext { } } - private func registerMiscResources(from bundle: DocumentationBundle) throws { + private func registerMiscResources(from bundle: DocumentationContext.Inputs) throws { let miscResources = Set(bundle.miscResourceURLs) try assetManagers[bundle.id, default: DataAssetManager()].register(data: miscResources) } - private func registeredAssets(withExtensions extensions: Set? = nil, inContexts contexts: [DataAsset.Context] = DataAsset.Context.allCases, forBundleID bundleID: DocumentationBundle.Identifier) -> [DataAsset] { + private func registeredAssets(withExtensions extensions: Set? = nil, inContexts contexts: [DataAsset.Context] = DataAsset.Context.allCases, forBundleID bundleID: DocumentationContext.Inputs.Identifier) -> [DataAsset] { guard let resources = assetManagers[bundleID]?.storage.values else { return [] } @@ -1673,7 +1645,7 @@ public class DocumentationContext { /// /// - Parameter bundleID: The identifier of the bundle to return image assets for. /// - Returns: A list of all the image assets for the given bundle. - public func registeredImageAssets(for bundleID: DocumentationBundle.Identifier) -> [DataAsset] { + public func registeredImageAssets(for bundleID: DocumentationContext.Inputs.Identifier) -> [DataAsset] { registeredAssets(withExtensions: DocumentationContext.supportedImageExtensions, forBundleID: bundleID) } @@ -1681,7 +1653,7 @@ public class DocumentationContext { /// /// - Parameter bundleID: The identifier of the bundle to return video assets for. /// - Returns: A list of all the video assets for the given bundle. - public func registeredVideoAssets(for bundleID: DocumentationBundle.Identifier) -> [DataAsset] { + public func registeredVideoAssets(for bundleID: DocumentationContext.Inputs.Identifier) -> [DataAsset] { registeredAssets(withExtensions: DocumentationContext.supportedVideoExtensions, forBundleID: bundleID) } @@ -1689,7 +1661,7 @@ public class DocumentationContext { /// /// - Parameter bundleID: The identifier of the bundle to return download assets for. /// - Returns: A list of all the download assets for the given bundle. - public func registeredDownloadsAssets(for bundleID: DocumentationBundle.Identifier) -> [DataAsset] { + public func registeredDownloadsAssets(for bundleID: DocumentationContext.Inputs.Identifier) -> [DataAsset] { registeredAssets(inContexts: [DataAsset.Context.download], forBundleID: bundleID) } @@ -1706,7 +1678,7 @@ public class DocumentationContext { } } - private func registerRootPages(from articles: Articles, in bundle: DocumentationBundle) { + private func registerRootPages(from articles: Articles, in bundle: DocumentationContext.Inputs) { // Create a root leaf node for all root page articles for article in articles { // Create the documentation data @@ -1743,7 +1715,7 @@ public class DocumentationContext { /// - Returns: The articles that were registered, with their topic graph node updated to what's been added to the topic graph. private func registerArticles( _ articles: DocumentationContext.Articles, - in bundle: DocumentationBundle + in bundle: DocumentationContext.Inputs ) -> DocumentationContext.Articles { articles.map { article in guard let (documentation, title) = DocumentationContext.documentationNodeAndTitle( @@ -1784,7 +1756,7 @@ public class DocumentationContext { /// - Parameters: /// - articles: On input, a list of articles. If an article is used as a root it is removed from this list. /// - bundle: The bundle containing the articles. - private func synthesizeArticleOnlyRootPage(articles: inout [DocumentationContext.SemanticResult
], bundle: DocumentationBundle) { + private func synthesizeArticleOnlyRootPage(articles: inout [DocumentationContext.SemanticResult
], bundle: DocumentationContext.Inputs) { let title = bundle.displayName // An inner helper function to register a new root node from an article @@ -1865,19 +1837,19 @@ public class DocumentationContext { /// - Parameters: /// - article: The article that will be used to create the returned documentation node. /// - kind: The kind that should be used to create the returned documentation node. - /// - bundle: The documentation bundle this article belongs to. + /// - inputs: The collection of inputs files that this article belongs to. /// - Returns: A documentation node and title for the given article semantic result. static func documentationNodeAndTitle( for article: DocumentationContext.SemanticResult
, availableSourceLanguages: Set? = nil, kind: DocumentationNode.Kind, - in bundle: DocumentationBundle + in inputs: DocumentationContext.Inputs ) -> (node: DocumentationNode, title: String)? { guard let articleMarkup = article.value.markup else { return nil } - let path = NodeURLGenerator.pathForSemantic(article.value, source: article.source, bundle: bundle) + let path = NodeURLGenerator.pathForSemantic(article.value, source: article.source, inputInfo: inputs.info) // Use the languages specified by the `@SupportedLanguage` directives if present. let availableSourceLanguages = article.value @@ -1897,7 +1869,7 @@ public class DocumentationContext { let defaultSourceLanguage = defaultLanguage(in: availableSourceLanguages) let reference = ResolvedTopicReference( - bundleID: bundle.id, + bundleID: inputs.id, path: path, sourceLanguages: availableSourceLanguages // FIXME: Pages in article-only catalogs should not be inferred as "Swift" as a fallback @@ -1972,20 +1944,18 @@ public class DocumentationContext { return articleReferences } - /** - Register a documentation bundle with this context. - */ - private func register(_ bundle: DocumentationBundle) throws { + /// Register a collection of documentation inputs with this context. + private func register(_ inputs: DocumentationContext.Inputs) throws { try shouldContinueRegistration() let currentFeatureFlags: FeatureFlags? - if let bundleFlags = bundle.info.featureFlags { + if let inputFileFlags = inputs.info.featureFlags { currentFeatureFlags = FeatureFlags.current - FeatureFlags.current.loadFlagsFromBundle(bundleFlags) + FeatureFlags.current.loadFlagsFromInputs(inputFileFlags) - for unknownFeatureFlag in bundleFlags.unknownFeatureFlags { + for unknownFeatureFlag in inputFileFlags.unknownFeatureFlags { let suggestions = NearMiss.bestMatches( - for: DocumentationBundle.Info.BundleFeatureFlags.CodingKeys.allCases.map({ $0.stringValue }), + for: DocumentationContext.Inputs.Info.BundleFeatureFlags.CodingKeys.allCases.map({ $0.stringValue }), against: unknownFeatureFlag) var summary: String = "Unknown feature flag in Info.plist: \(unknownFeatureFlag.singleQuoted)" if !suggestions.isEmpty { @@ -2007,22 +1977,21 @@ public class DocumentationContext { } } - // Note: Each bundle is registered and processed separately. - // Documents and symbols may both reference each other so the bundle is registered in 4 steps + // Note: It's possible for both documents and symbols to reference each other so the inputs are registered in 4 steps - // In the bundle discovery phase all tasks run in parallel as they don't depend on each other. + // In the discovery phase all tasks run in parallel as they don't depend on each other. let discoveryGroup = DispatchGroup() let discoveryQueue = DispatchQueue(label: "org.swift.docc.Discovery", qos: .unspecified, attributes: .concurrent, autoreleaseFrequency: .workItem) let discoveryError = Synchronized<(any Error)?>(nil) - // Load all bundle symbol graphs into the loader. + // Load all the inputs' symbol graphs into the loader. var symbolGraphLoader: SymbolGraphLoader! var hierarchyBasedResolver: PathHierarchyBasedLinkResolver! discoveryGroup.async(queue: discoveryQueue) { [unowned self] in symbolGraphLoader = SymbolGraphLoader( - bundle: bundle, + inputs: inputs, dataProvider: dataProvider, symbolGraphTransformer: configuration.convertServiceConfiguration.symbolGraphTransformer ) @@ -2034,7 +2003,7 @@ public class DocumentationContext { hierarchyBasedResolver = signposter.withIntervalSignpost("Build PathHierarchy", id: signposter.makeSignpostID()) { PathHierarchyBasedLinkResolver(pathHierarchy: PathHierarchy( symbolGraphLoader: symbolGraphLoader, - bundleName: urlReadablePath(bundle.displayName), + catalogName: urlReadablePath(inputs.displayName), knownDisambiguatedPathComponents: configuration.convertServiceConfiguration.knownDisambiguatedSymbolPathComponents )) } @@ -2050,7 +2019,7 @@ public class DocumentationContext { discoveryGroup.async(queue: discoveryQueue) { [unowned self] in do { try signposter.withIntervalSignpost("Load resources", id: signposter.makeSignpostID()) { - try self.registerMiscResources(from: bundle) + try self.registerMiscResources(from: inputs) } } catch { // Pipe the error out of the dispatch queue. @@ -2076,7 +2045,7 @@ public class DocumentationContext { discoveryGroup.async(queue: discoveryQueue) { [unowned self] in do { result = try signposter.withIntervalSignpost("Load documents", id: signposter.makeSignpostID()) { - try self.registerDocuments(from: bundle) + try self.registerDocuments(from: inputs) } } catch { // Pipe the error out of the dispatch queue. @@ -2150,7 +2119,7 @@ public class DocumentationContext { } self.linkResolver.localResolver = hierarchyBasedResolver - hierarchyBasedResolver.addMappingForRoots(bundle: bundle) + hierarchyBasedResolver.addMappingForRoots(inputs: inputs) for tutorial in tutorials { hierarchyBasedResolver.addTutorial(tutorial) } @@ -2161,8 +2130,8 @@ public class DocumentationContext { hierarchyBasedResolver.addTutorialTableOfContents(tutorialTableOfContents) } - registerRootPages(from: rootPageArticles, in: bundle) - try registerSymbols(from: bundle, symbolGraphLoader: symbolGraphLoader, documentationExtensions: documentationExtensions) + registerRootPages(from: rootPageArticles, in: inputs) + try registerSymbols(symbolGraphLoader: symbolGraphLoader, documentationExtensions: documentationExtensions) // We don't need to keep the loader in memory after we've registered all symbols. symbolGraphLoader = nil @@ -2172,7 +2141,7 @@ public class DocumentationContext { !otherArticles.isEmpty, !configuration.convertServiceConfiguration.allowsRegisteringArticlesWithoutTechnologyRoot { - synthesizeArticleOnlyRootPage(articles: &otherArticles, bundle: bundle) + synthesizeArticleOnlyRootPage(articles: &otherArticles, bundle: inputs) } // Keep track of the root modules registered from symbol graph files, we'll need them to automatically @@ -2187,7 +2156,7 @@ public class DocumentationContext { // Articles that will be automatically curated can be resolved but they need to be pre registered before resolving links. let rootNodeForAutomaticCuration = soleRootModuleReference.flatMap(topicGraph.nodeWithReference(_:)) if configuration.convertServiceConfiguration.allowsRegisteringArticlesWithoutTechnologyRoot || rootNodeForAutomaticCuration != nil { - otherArticles = registerArticles(otherArticles, in: bundle) + otherArticles = registerArticles(otherArticles, in: inputs) try shouldContinueRegistration() } @@ -2196,13 +2165,13 @@ public class DocumentationContext { tutorialTableOfContentsResults.map(referencedSemanticObject) + tutorials.map(referencedSemanticObject) + tutorialArticles.map(referencedSemanticObject), - localBundleID: bundle.id) + localBundleID: inputs.id) resolveLinks( tutorialTableOfContents: tutorialTableOfContentsResults, tutorials: tutorials, tutorialArticles: tutorialArticles, - bundle: bundle + inputs: inputs ) // After the resolving links in tutorial content all the local references are known and can be added to the referenceIndex for fast lookup. @@ -2215,7 +2184,7 @@ public class DocumentationContext { } try shouldContinueRegistration() - var allCuratedReferences = try crawlSymbolCuration(in: linkResolver.localResolver.topLevelSymbols(), bundle: bundle) + var allCuratedReferences = try crawlSymbolCuration(in: linkResolver.localResolver.topLevelSymbols()) // Store the list of manually curated references if doc coverage is on. if configuration.experimentalCoverageConfiguration.shouldStoreManuallyCuratedReferences { @@ -2230,13 +2199,13 @@ public class DocumentationContext { } // Crawl the rest of the symbols that haven't been crawled so far in hierarchy pre-order. - allCuratedReferences = try crawlSymbolCuration(in: automaticallyCurated.map(\.symbol), bundle: bundle, initial: allCuratedReferences) + allCuratedReferences = try crawlSymbolCuration(in: automaticallyCurated.map(\.symbol), initial: allCuratedReferences) // Automatically curate articles that haven't been manually curated // Article curation is only done automatically if there is only one root module if let rootNode = rootNodeForAutomaticCuration { let articleReferences = try autoCurateArticles(otherArticles, startingFrom: rootNode) - allCuratedReferences = try crawlSymbolCuration(in: articleReferences, bundle: bundle, initial: allCuratedReferences) + allCuratedReferences = try crawlSymbolCuration(in: articleReferences, initial: allCuratedReferences) } // Remove curation paths that have been created automatically above @@ -2254,14 +2223,14 @@ public class DocumentationContext { linkResolver.localResolver.addAnchorForSymbols(localCache: documentationCache) // Fifth, resolve links in nodes that are added solely via curation - preResolveExternalLinks(references: Array(allCuratedReferences), localBundleID: bundle.id) - resolveLinks(curatedReferences: allCuratedReferences, bundle: bundle) + preResolveExternalLinks(references: Array(allCuratedReferences), localBundleID: inputs.id) + resolveLinks(curatedReferences: allCuratedReferences, inputs: inputs) if configuration.convertServiceConfiguration.fallbackResolver != nil { // When the ``ConvertService`` builds documentation for a single page there won't be a module or root // reference to auto-curate the page under, so the regular local link resolution code path won't visit // the single page. To ensure that links are resolved, explicitly visit all pages. - resolveLinks(curatedReferences: Set(knownPages), bundle: bundle) + resolveLinks(curatedReferences: Set(knownPages), inputs: inputs) } // We should use a read-only context during render time (rdar://65130130). @@ -2460,17 +2429,16 @@ public class DocumentationContext { /// Crawls the hierarchy of the given list of nodes, adding relationships in the topic graph for all resolvable task group references. /// - Parameters: /// - references: A list of references to crawl. - /// - bundle: A documentation bundle. /// - initial: A list of references to skip when crawling. /// - Returns: The references of all the symbols that were curated. @discardableResult - func crawlSymbolCuration(in references: [ResolvedTopicReference], bundle: DocumentationBundle, initial: Set = []) throws -> Set { + func crawlSymbolCuration(in references: [ResolvedTopicReference], initial: Set = []) throws -> Set { let signpostHandle = signposter.beginInterval("Curate symbols", id: signposter.makeSignpostID()) defer { signposter.endInterval("Curate symbols", signpostHandle) } - var crawler = DocumentationCurator(in: self, bundle: bundle, initial: initial) + var crawler = DocumentationCurator(in: self, initial: initial) for reference in references { try crawler.crawlChildren( @@ -2642,7 +2610,7 @@ public class DocumentationContext { /** Unregister a documentation bundle with this context and clear any cached resources associated with it. */ - private func unregister(_ bundle: DocumentationBundle) { + private func unregister(_ bundle: DocumentationContext.Inputs) { let referencesToRemove = topicGraph.nodes.keys.filter { $0.bundleID == bundle.id } @@ -2657,7 +2625,7 @@ public class DocumentationContext { // MARK: - Getting documentation relationships /** - Look for a secondary resource among the registered bundles. + Look for a secondary resource among the registered assets. The context tracks resources by file name. If the documentation author specified a resource reference using a qualified path, instead of a file name, the context will fail to find that resource. @@ -2698,7 +2666,7 @@ public class DocumentationContext { } /** - Look for a documentation node among the registered bundles and via any external resolvers. + Look for a documentation node among the registered content and via any external resolvers. - Returns: A ``DocumentationNode`` with the given identifier. - Throws: ``ContextError/notFound(_:)`` if a documentation node with the given identifier was not found. @@ -2873,7 +2841,7 @@ public class DocumentationContext { resolveAsset(named: name, bundleID: parent.bundleID, withType: type) } - func resolveAsset(named name: String, bundleID: DocumentationBundle.Identifier, withType expectedType: AssetType?) -> DataAsset? { + func resolveAsset(named name: String, bundleID: DocumentationContext.Inputs.Identifier, withType expectedType: AssetType?) -> DataAsset? { if let localAsset = assetManagers[bundleID]?.allData(named: name) { if let expectedType { guard localAsset.hasVariant(withAssetType: expectedType) else { diff --git a/Sources/SwiftDocC/Infrastructure/DocumentationCurator.swift b/Sources/SwiftDocC/Infrastructure/DocumentationCurator.swift index 1519965672..c93ce84c0a 100644 --- a/Sources/SwiftDocC/Infrastructure/DocumentationCurator.swift +++ b/Sources/SwiftDocC/Infrastructure/DocumentationCurator.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -17,14 +17,10 @@ struct DocumentationCurator { /// The documentation context to crawl. private let context: DocumentationContext - /// The current bundle. - private let bundle: DocumentationBundle - private(set) var problems = [Problem]() - init(in context: DocumentationContext, bundle: DocumentationBundle, initial: Set = []) { + init(in context: DocumentationContext, initial: Set = []) { self.context = context - self.bundle = bundle self.curatedNodes = initial } @@ -80,7 +76,7 @@ struct DocumentationCurator { } // Check if the link has been externally resolved already. - if let bundleID = unresolved.topicURL.components.host.map({ DocumentationBundle.Identifier(rawValue: $0) }), + if let bundleID = unresolved.topicURL.components.host.map({ DocumentationContext.Inputs.Identifier(rawValue: $0) }), context.configuration.externalDocumentationConfiguration.sources[bundleID] != nil || context.configuration.convertServiceConfiguration.fallbackResolver != nil { if case .success(let resolvedExternalReference) = context.externallyResolvedLinks[unresolved.topicURL] { return resolvedExternalReference @@ -99,7 +95,7 @@ struct DocumentationCurator { // - "documentation/CatalogName/ArticleName" switch path.components(separatedBy: "/").count { case 0,1: - return NodeURLGenerator.Path.article(bundleName: bundle.displayName, articleName: path).stringValue + return NodeURLGenerator.Path.article(bundleName: context.inputs.displayName, articleName: path).stringValue case 2: return "\(NodeURLGenerator.Path.documentationFolder)/\(path)" default: diff --git a/Sources/SwiftDocC/Infrastructure/DocumentationBundleFileTypes.swift b/Sources/SwiftDocC/Infrastructure/DocumentationInputFileTypes.swift similarity index 91% rename from Sources/SwiftDocC/Infrastructure/DocumentationBundleFileTypes.swift rename to Sources/SwiftDocC/Infrastructure/DocumentationInputFileTypes.swift index 18af82c395..f739ca23ff 100644 --- a/Sources/SwiftDocC/Infrastructure/DocumentationBundleFileTypes.swift +++ b/Sources/SwiftDocC/Infrastructure/DocumentationInputFileTypes.swift @@ -10,8 +10,8 @@ public import Foundation -/// A collection of functions to check if a file is one of the documentation bundle files types. -public enum DocumentationBundleFileTypes { +/// A collection of functions to check if a file is one of the documentation catalog's files types. +public enum DocumentationInputFileTypes { static let referenceFileExtension = "md" /// Checks if a file is a reference documentation file. @@ -85,3 +85,7 @@ public enum DocumentationBundleFileTypes { return url.lastPathComponent == themeSettingsFileName } } + +@available(*, deprecated, renamed: "DocumentationInputFileTypes", message: "Use 'DocumentationInputFileTypes' instead. This deprecated API will be removed after 6.3 is released") +public typealias DocumentationBundleFileTypes = DocumentationInputFileTypes + diff --git a/Sources/SwiftDocC/Infrastructure/DocumentationBundle+Identifier.swift b/Sources/SwiftDocC/Infrastructure/DocumentationInputs+Identifier.swift similarity index 78% rename from Sources/SwiftDocC/Infrastructure/DocumentationBundle+Identifier.swift rename to Sources/SwiftDocC/Infrastructure/DocumentationInputs+Identifier.swift index a2afc9d699..1e978b9cd7 100644 --- a/Sources/SwiftDocC/Infrastructure/DocumentationBundle+Identifier.swift +++ b/Sources/SwiftDocC/Infrastructure/DocumentationInputs+Identifier.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2024 Apple Inc. and the Swift project authors + Copyright (c) 2024-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ import Foundation -extension DocumentationBundle { +extension DocumentationContext.Inputs { /// A stable and locally unique identifier for a collection of documentation inputs. public struct Identifier: RawRepresentable { public let rawValue: String @@ -28,32 +28,32 @@ extension DocumentationBundle { } } -extension DocumentationBundle.Identifier: Hashable {} -extension DocumentationBundle.Identifier: Sendable {} +extension DocumentationContext.Inputs.Identifier: Hashable {} +extension DocumentationContext.Inputs.Identifier: Sendable {} // Support creating an identifier from a string literal. -extension DocumentationBundle.Identifier: ExpressibleByStringLiteral { +extension DocumentationContext.Inputs.Identifier: ExpressibleByStringLiteral { public init(stringLiteral value: StringLiteralType) { self.init(rawValue: value) } } // Sort identifiers based on their raw string value. -extension DocumentationBundle.Identifier: Comparable { +extension DocumentationContext.Inputs.Identifier: Comparable { public static func < (lhs: Self, rhs: Self) -> Bool { lhs.rawValue < rhs.rawValue } } // Print as a single string value -extension DocumentationBundle.Identifier: CustomStringConvertible { +extension DocumentationContext.Inputs.Identifier: CustomStringConvertible { public var description: String { rawValue } } // Encode and decode the identifier as a single string value. -extension DocumentationBundle.Identifier: Codable { +extension DocumentationContext.Inputs.Identifier: Codable { public init(from decoder: any Decoder) throws { let container = try decoder.singleValueContainer() let rawValue = try container.decode(String.self) diff --git a/Sources/SwiftDocC/Infrastructure/DocumentationBundle.swift b/Sources/SwiftDocC/Infrastructure/DocumentationInputs.swift similarity index 86% rename from Sources/SwiftDocC/Infrastructure/DocumentationBundle.swift rename to Sources/SwiftDocC/Infrastructure/DocumentationInputs.swift index 11cc3ef426..1363e6b222 100644 --- a/Sources/SwiftDocC/Infrastructure/DocumentationBundle.swift +++ b/Sources/SwiftDocC/Infrastructure/DocumentationInputs.swift @@ -10,6 +10,8 @@ public import Foundation +extension DocumentationContext { + /// A collection of the build inputs for a unit of documentation. /// /// A unit of documentation may for example cover a framework, library, or tool. @@ -33,18 +35,18 @@ public import Foundation /// /// - ``info`` /// - ``displayName`` -/// - ``identifier`` -public struct DocumentationBundle { +/// - ``id`` +public struct Inputs { public enum PropertyListError: DescribedError { case invalidVersionString(String) case keyNotFound(String) public var errorDescription: String { switch self { - case .invalidVersionString(let versionString): - return "'\(versionString)' is not a valid version string" - case .keyNotFound(let name): - return "Expected key \(name.singleQuoted) not found" + case .invalidVersionString(let versionString): + return "'\(versionString)' is not a valid version string" + case .keyNotFound(let name): + return "Expected key \(name.singleQuoted) not found" } } } @@ -57,8 +59,8 @@ public struct DocumentationBundle { info.displayName } - /// The documentation bundle's stable and locally unique identifier. - public var id: DocumentationBundle.Identifier { + /// The unit of documentation's stable and locally unique identifier. + public var id: Identifier { info.id } @@ -68,7 +70,7 @@ public struct DocumentationBundle { /// /// ## See Also /// - /// - ``DocumentationBundleFileTypes/isSymbolGraphFile(_:)`` + /// - ``DocumentationInputFileTypes/isSymbolGraphFile(_:)`` public let symbolGraphURLs: [URL] /// Documentation markup input files for this unit of documentation. @@ -77,7 +79,7 @@ public struct DocumentationBundle { /// /// ## See Also /// - /// - ``DocumentationBundleFileTypes/isMarkupFile(_:)`` + /// - ``DocumentationInputFileTypes/isMarkupFile(_:)`` public let markupURLs: [URL] /// Miscellaneous resources (for example images, videos, or downloadable assets) for this unit of documentation. @@ -133,16 +135,21 @@ public struct DocumentationBundle { } public private(set) var rootReference: ResolvedTopicReference - + /// Default path to resolve symbol links. public private(set) var documentationRootReference: ResolvedTopicReference - + /// Default path to resolve tutorial table-of-contents links. public var tutorialTableOfContentsContainer: ResolvedTopicReference - + /// Default path to resolve tutorial links. public var tutorialsContainerReference: ResolvedTopicReference - + /// Default path to resolve articles. public var articlesDocumentationRootReference: ResolvedTopicReference } + +} + +@available(*, deprecated, renamed: "DocumentationContext.Inputs", message: "Use 'DocumentationContext.Inputs' instead. This deprecated API will be removed after 6.3 is released") +public typealias DocumentationBundle = DocumentationContext.Inputs diff --git a/Sources/SwiftDocC/Infrastructure/External Data/ExternalDocumentationSource.swift b/Sources/SwiftDocC/Infrastructure/External Data/ExternalDocumentationSource.swift index b6e40e272b..3b5c08b7ac 100644 --- a/Sources/SwiftDocC/Infrastructure/External Data/ExternalDocumentationSource.swift +++ b/Sources/SwiftDocC/Infrastructure/External Data/ExternalDocumentationSource.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -20,7 +20,7 @@ import Foundation /// ``DocumentationContext/externalDocumentationSources`` for the bundle identifier of the unresolved reference. If there is, that source is asked to attempt to resolve the reference. /// /// If the referenced documentation exists in the external source, the source returns a resolved reference to the context. Later, the context uses this resolved reference to ask the source -/// for the external entity with the documentation content for that reference. Because this content isn't part of the compiled bundle, it won't have its own page in the build output. +/// for the external entity with the documentation content for that reference. Because this content isn't part of the compiled catalog, it won't have its own page in the build output. /// /// If the reference doesn't exist in the external source of documentation or if an error occurs while attempting to resolve the reference, the external source returns information about the error. /// diff --git a/Sources/SwiftDocC/Infrastructure/External Data/ExternalMetadata.swift b/Sources/SwiftDocC/Infrastructure/External Data/ExternalMetadata.swift index 9360fb25ce..4566150e74 100644 --- a/Sources/SwiftDocC/Infrastructure/External Data/ExternalMetadata.swift +++ b/Sources/SwiftDocC/Infrastructure/External Data/ExternalMetadata.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -76,8 +76,14 @@ public struct ExternalMetadata { /// If `true`, inherited symbols retain their original docs. public var inheritDocs = false - /// If `true`, there is no source bundle on disk and the inputs were passed via command line parameters. - public var isGeneratedBundle = false + /// If `true`, there is no source catalog on disk and the inputs were passed via command line parameters. + public var isGeneratedCatalog = false + + @available(*, deprecated, renamed: "isGeneratedCatalog", message: "Use 'isGeneratedCatalog' instead. This deprecated API will be removed after 6.3 is released.") + public var isGeneratedBundle: Bool { + get { isGeneratedCatalog } + set { isGeneratedCatalog = newValue } + } /// The granularity of diagnostics to emit via the engine. public var diagnosticLevel: DiagnosticSeverity = .warning diff --git a/Sources/SwiftDocC/Infrastructure/External Data/GlobalExternalSymbolResolver.swift b/Sources/SwiftDocC/Infrastructure/External Data/GlobalExternalSymbolResolver.swift index acf37d2f00..617b2bf7eb 100644 --- a/Sources/SwiftDocC/Infrastructure/External Data/GlobalExternalSymbolResolver.swift +++ b/Sources/SwiftDocC/Infrastructure/External Data/GlobalExternalSymbolResolver.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -17,10 +17,9 @@ import Foundation /// /// If a symbol in a symbol graph file references a symbol in another module---for example, when the symbol conforms to a protocol from another module, when the /// symbol inherits from a class in another module, or the symbol has arguments or return values that are types from other modules---then this resolver is used to -/// look up those symbols by their unique identifier. This allows references in symbol declarations to be turned into links for external symbols, just like in-bundle -/// symbol references. +/// look up those symbols by their unique identifier. This allows references in symbol declarations to be turned into links for external symbols, just like local symbol references. /// -/// Because symbol identifiers don't specify what bundle the symbol belongs to, a documentation context can only have one global external symbol resolver. +/// Because symbol identifiers don't specify what module the symbol belongs to, a documentation context can only have one global external symbol resolver. /// /// ## See Also /// - ``DocumentationContext/globalExternalSymbolResolver`` diff --git a/Sources/SwiftDocC/Infrastructure/External Data/OutOfProcessReferenceResolver.swift b/Sources/SwiftDocC/Infrastructure/External Data/OutOfProcessReferenceResolver.swift index 1988f8b074..07f40c4164 100644 --- a/Sources/SwiftDocC/Infrastructure/External Data/OutOfProcessReferenceResolver.swift +++ b/Sources/SwiftDocC/Infrastructure/External Data/OutOfProcessReferenceResolver.swift @@ -52,7 +52,7 @@ public class OutOfProcessReferenceResolver: ExternalDocumentationSource, GlobalE private let externalLinkResolvingClient: any ExternalLinkResolving /// The bundle identifier for the reference resolver in the other process. - public let bundleID: DocumentationBundle.Identifier + public let bundleID: DocumentationContext.Inputs.Identifier /// Creates a new reference resolver that interacts with another executable. /// @@ -89,7 +89,7 @@ public class OutOfProcessReferenceResolver: ExternalDocumentationSource, GlobalE /// - bundleID: The bundle identifier the server can resolve references for. /// - server: The server to send link resolution requests to. /// - convertRequestIdentifier: The identifier that the resolver will use for convert requests that it sends to the server. - public init(bundleID: DocumentationBundle.Identifier, server: DocumentationServer, convertRequestIdentifier: String?) throws { + public init(bundleID: DocumentationContext.Inputs.Identifier, server: DocumentationServer, convertRequestIdentifier: String?) throws { self.bundleID = bundleID self.externalLinkResolvingClient = LongRunningService( server: server, convertRequestIdentifier: convertRequestIdentifier) diff --git a/Sources/SwiftDocC/Infrastructure/Input Discovery/DocumentationInputsProvider.swift b/Sources/SwiftDocC/Infrastructure/Input Discovery/DocumentationInputsProvider.swift index 681d32dada..b104cc9b30 100644 --- a/Sources/SwiftDocC/Infrastructure/Input Discovery/DocumentationInputsProvider.swift +++ b/Sources/SwiftDocC/Infrastructure/Input Discovery/DocumentationInputsProvider.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2024 Apple Inc. and the Swift project authors + Copyright (c) 2024-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -15,19 +15,19 @@ extension DocumentationContext { /// A type that provides inputs for a unit of documentation. /// - /// The inputs provider discovers documentation catalogs on the file system and creates a ``DocumentationBundle`` from the discovered catalog content. + /// The inputs provider discovers documentation catalogs on the file system and creates a ``DocumentationContext/Inputs`` from the discovered catalog content. /// - /// The input provider categorizes the catalog content based on corresponding ``DocumentationBundleFileTypes`` conditions: + /// The input provider categorizes the catalog content based on corresponding ``DocumentationInputFileTypes`` conditions: /// - /// Category | Condition - /// ---------------------------------------- | ------------------------------------------------- - /// ``DocumentationBundle/markupURLs`` | ``DocumentationBundleFileTypes/isMarkupFile(_:)`` - /// ``DocumentationBundle/symbolGraphURLs`` | ``DocumentationBundleFileTypes/isSymbolGraphFile(_:)`` - /// ``DocumentationBundle/info`` | ``DocumentationBundleFileTypes/isInfoPlistFile(_:)`` - /// ``DocumentationBundle/themeSettings`` | ``DocumentationBundleFileTypes/isThemeSettingsFile(_:)`` - /// ``DocumentationBundle/customHeader`` | ``DocumentationBundleFileTypes/isCustomHeader(_:)`` - /// ``DocumentationBundle/customFooter`` | ``DocumentationBundleFileTypes/isCustomFooter(_:)`` - /// ``DocumentationBundle/miscResourceURLs`` | Any file not already matched above. + /// Category | Condition + /// ------------------------------------------------ | ------------------------------------------------- + /// ``DocumentationContext/Inputs/markupURLs`` | ``DocumentationInputFileTypes/isMarkupFile(_:)`` + /// ``DocumentationContext/Inputs/symbolGraphURLs`` | ``DocumentationInputFileTypes/isSymbolGraphFile(_:)`` + /// ``DocumentationContext/Inputs/info`` | ``DocumentationInputFileTypes/isInfoPlistFile(_:)`` + /// ``DocumentationContext/Inputs/themeSettings`` | ``DocumentationInputFileTypes/isThemeSettingsFile(_:)`` + /// ``DocumentationContext/Inputs/customHeader`` | ``DocumentationInputFileTypes/isCustomHeader(_:)`` + /// ``DocumentationContext/Inputs/customFooter`` | ``DocumentationInputFileTypes/isCustomFooter(_:)`` + /// ``DocumentationContext/Inputs/miscResourceURLs`` | Any file not already matched above. /// /// ## Topics /// @@ -72,7 +72,7 @@ extension DocumentationContext { extension DocumentationContext.InputsProvider { - private typealias FileTypes = DocumentationBundleFileTypes + private typealias FileTypes = DocumentationInputFileTypes /// A discovered documentation catalog. struct CatalogURL { @@ -130,13 +130,9 @@ extension DocumentationContext.InputsProvider { // MARK: Create from catalog -extension DocumentationContext { - package typealias Inputs = DocumentationBundle -} - extension DocumentationContext.InputsProvider { - package typealias Options = BundleDiscoveryOptions + package typealias Options = CatalogDiscoveryOptions /// Creates a collection of documentation inputs from the content of the given documentation catalog. /// @@ -153,7 +149,7 @@ extension DocumentationContext.InputsProvider { let info = try DocumentationContext.Inputs.Info( from: infoPlistData, - bundleDiscoveryOptions: options, + catalogDiscoveryOptions: options, derivedDisplayName: url.deletingPathExtension().lastPathComponent ) @@ -219,7 +215,7 @@ extension DocumentationContext.InputsProvider { } let derivedDisplayName = moduleNames.count == 1 ? moduleNames.first : nil - let info = try DocumentationContext.Inputs.Info(bundleDiscoveryOptions: options, derivedDisplayName: derivedDisplayName) + let info = try DocumentationContext.Inputs.Info(catalogDiscoveryOptions: options, derivedDisplayName: derivedDisplayName) let topLevelPages: [URL] let provider: any DataProvider @@ -243,7 +239,7 @@ extension DocumentationContext.InputsProvider { } return ( - inputs: DocumentationBundle( + inputs: DocumentationContext.Inputs( info: info, symbolGraphURLs: options.additionalSymbolGraphFiles, markupURLs: topLevelPages, diff --git a/Sources/SwiftDocC/Infrastructure/Link Resolution/LinkResolver+NavigatorIndex.swift b/Sources/SwiftDocC/Infrastructure/Link Resolution/LinkResolver+NavigatorIndex.swift index 8f0966fc79..e102a5be79 100644 --- a/Sources/SwiftDocC/Infrastructure/Link Resolution/LinkResolver+NavigatorIndex.swift +++ b/Sources/SwiftDocC/Infrastructure/Link Resolution/LinkResolver+NavigatorIndex.swift @@ -17,9 +17,9 @@ package struct ExternalRenderNode { private var externalEntity: LinkResolver.ExternalEntity /// The bundle identifier for this external node. - private var bundleIdentifier: DocumentationBundle.Identifier + private var bundleIdentifier: DocumentationContext.Inputs.Identifier - init(externalEntity: LinkResolver.ExternalEntity, bundleIdentifier: DocumentationBundle.Identifier) { + init(externalEntity: LinkResolver.ExternalEntity, bundleIdentifier: DocumentationContext.Inputs.Identifier) { self.externalEntity = externalEntity self.bundleIdentifier = bundleIdentifier } diff --git a/Sources/SwiftDocC/Infrastructure/Link Resolution/LinkResolver.swift b/Sources/SwiftDocC/Infrastructure/Link Resolution/LinkResolver.swift index 20291f286d..9a2d7a8544 100644 --- a/Sources/SwiftDocC/Infrastructure/Link Resolution/LinkResolver.swift +++ b/Sources/SwiftDocC/Infrastructure/Link Resolution/LinkResolver.swift @@ -18,7 +18,7 @@ public class LinkResolver { self.dataProvider = dataProvider } - /// The link resolver to use to resolve links in the local bundle + /// The link resolver to use to resolve links in the local documentation. var localResolver: PathHierarchyBasedLinkResolver! /// A fallback resolver to use when the local resolver fails to resolve a link. /// @@ -106,8 +106,8 @@ public class LinkResolver { // Check if this is a link to an external documentation source that should have previously been resolved in `DocumentationContext.preResolveExternalLinks(...)` if let bundleID = unresolvedReference.bundleID, - context.bundle.id != bundleID, - urlReadablePath(context.bundle.displayName) != bundleID.rawValue + context.inputs.id != bundleID, + urlReadablePath(context.inputs.displayName) != bundleID.rawValue { return .failure(unresolvedReference, TopicReferenceResolutionErrorInfo("No external resolver registered for '\(bundleID)'.")) } @@ -185,8 +185,8 @@ private final class FallbackResolverBasedLinkResolver { // Check if a fallback reference resolver should resolve this let referenceBundleID = unresolvedReference.bundleID ?? parent.bundleID guard let fallbackResolver = context.configuration.convertServiceConfiguration.fallbackResolver, - fallbackResolver.bundleID == context.bundle.id, - context.bundle.id == referenceBundleID || urlReadablePath(context.bundle.displayName) == referenceBundleID.rawValue + fallbackResolver.bundleID == context.inputs.id, + context.inputs.id == referenceBundleID || urlReadablePath(context.inputs.displayName) == referenceBundleID.rawValue else { return nil } @@ -204,7 +204,7 @@ private final class FallbackResolverBasedLinkResolver { ) allCandidateURLs.append(alreadyResolved.url) - let currentBundle = context.bundle + let currentBundle = context.inputs if !isCurrentlyResolvingSymbolLink { // First look up articles path allCandidateURLs.append(contentsOf: [ diff --git a/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy+Serialization.swift b/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy+Serialization.swift index d1cfe15985..0c806131e5 100644 --- a/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy+Serialization.swift +++ b/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy+Serialization.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2023 Apple Inc. and the Swift project authors + Copyright (c) 2023-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -150,7 +150,7 @@ public struct SerializableLinkResolutionInformation: Codable { // This type is public so that it can be an argument to a function in `ConvertOutputConsumer` var version: SemanticVersion - var bundleID: DocumentationBundle.Identifier + var bundleID: DocumentationContext.Inputs.Identifier var pathHierarchy: PathHierarchy.FileRepresentation // Separate storage of node data because the path hierarchy doesn't know the resolved references for articles. var nonSymbolPaths: [Int: String] @@ -160,7 +160,7 @@ extension PathHierarchyBasedLinkResolver { /// Create a file representation of the link resolver. /// /// The file representation can be decoded in later documentation builds to resolve external links to the content where the link resolver was originally created for. - func prepareForSerialization(bundleID: DocumentationBundle.Identifier) throws -> SerializableLinkResolutionInformation { + func prepareForSerialization(bundleID: DocumentationContext.Inputs.Identifier) throws -> SerializableLinkResolutionInformation { var nonSymbolPaths: [Int: String] = [:] let hierarchyFileRepresentation = PathHierarchy.FileRepresentation(pathHierarchy) { identifiers in nonSymbolPaths.reserveCapacity(identifiers.count) diff --git a/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy.swift b/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy.swift index d4891efab4..ed8e4b8513 100644 --- a/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy.swift +++ b/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy.swift @@ -54,12 +54,12 @@ struct PathHierarchy { /// /// - Parameters: /// - loader: The symbol graph loader that provides all symbols. - /// - bundleName: The name of the documentation bundle, used as a container for articles and tutorials. + /// - catalogName: The name of the documentation catalog, used as a container for articles and tutorials. /// - moduleKindDisplayName: The display name for the "module" kind of symbol. /// - knownDisambiguatedPathComponents: A list of path components with known required disambiguations. init( symbolGraphLoader loader: SymbolGraphLoader, - bundleName: String, + catalogName: String, moduleKindDisplayName: String = "Framework", knownDisambiguatedPathComponents: [String: [String]]? = nil ) { @@ -420,8 +420,8 @@ struct PathHierarchy { lookup[id] = node return node } - self.articlesContainer = roots[bundleName] ?? newNode(bundleName) - self.tutorialContainer = newNode(bundleName) + self.articlesContainer = roots[catalogName] ?? newNode(catalogName) + self.tutorialContainer = newNode(catalogName) self.tutorialOverviewContainer = newNode("tutorials") assert( diff --git a/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchyBasedLinkResolver.swift b/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchyBasedLinkResolver.swift index 4dc85a2968..d647804215 100644 --- a/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchyBasedLinkResolver.swift +++ b/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchyBasedLinkResolver.swift @@ -99,10 +99,10 @@ final class PathHierarchyBasedLinkResolver { // MARK: - Adding non-symbols /// Map the resolved identifiers to resolved topic references for a given bundle's article, tutorial, and technology root pages. - func addMappingForRoots(bundle: DocumentationBundle) { - resolvedReferenceMap[pathHierarchy.tutorialContainer.identifier] = bundle.tutorialsContainerReference - resolvedReferenceMap[pathHierarchy.articlesContainer.identifier] = bundle.articlesDocumentationRootReference - resolvedReferenceMap[pathHierarchy.tutorialOverviewContainer.identifier] = bundle.tutorialTableOfContentsContainer + func addMappingForRoots(inputs: DocumentationContext.Inputs) { + resolvedReferenceMap[pathHierarchy.tutorialContainer.identifier] = inputs.tutorialsContainerReference + resolvedReferenceMap[pathHierarchy.articlesContainer.identifier] = inputs.articlesDocumentationRootReference + resolvedReferenceMap[pathHierarchy.tutorialOverviewContainer.identifier] = inputs.tutorialTableOfContentsContainer } /// Map the resolved identifiers to resolved topic references for all symbols in the given symbol index. @@ -264,14 +264,14 @@ final class PathHierarchyBasedLinkResolver { /// /// - Parameters: /// - symbolGraph: The complete symbol graph to walk through. - /// - bundle: The bundle to use when creating symbol references. - func referencesForSymbols(in unifiedGraphs: [String: UnifiedSymbolGraph], bundle: DocumentationBundle, context: DocumentationContext) -> [SymbolGraph.Symbol.Identifier: ResolvedTopicReference] { + /// - context: The context that the symbols belong to. + func referencesForSymbols(in unifiedGraphs: [String: UnifiedSymbolGraph], context: DocumentationContext) -> [SymbolGraph.Symbol.Identifier: ResolvedTopicReference] { let disambiguatedPaths = pathHierarchy.caseInsensitiveDisambiguatedPaths(includeDisambiguationForUnambiguousChildren: true, includeLanguage: true, allowAdvancedDisambiguation: false) var result: [SymbolGraph.Symbol.Identifier: ResolvedTopicReference] = [:] for (moduleName, symbolGraph) in unifiedGraphs { - let paths: [ResolvedTopicReference?] = Array(symbolGraph.symbols.values).concurrentMap { unifiedSymbol -> ResolvedTopicReference? in + let paths: [ResolvedTopicReference?] = Array(symbolGraph.symbols.values).concurrentMap { (unifiedSymbol: UnifiedSymbolGraph.Symbol) -> ResolvedTopicReference? in let symbol = unifiedSymbol let uniqueIdentifier = unifiedSymbol.uniqueIdentifier @@ -280,7 +280,7 @@ final class PathHierarchyBasedLinkResolver { pathComponents.count == componentsCount { let symbolReference = SymbolReference(pathComponents: pathComponents, interfaceLanguages: symbol.sourceLanguages) - return ResolvedTopicReference(symbolReference: symbolReference, moduleName: moduleName, bundle: bundle) + return ResolvedTopicReference(symbolReference: symbolReference, moduleName: moduleName, inputs: context.inputs) } guard let path = disambiguatedPaths[uniqueIdentifier] else { @@ -288,7 +288,7 @@ final class PathHierarchyBasedLinkResolver { } return ResolvedTopicReference( - bundleID: bundle.documentationRootReference.bundleID, + bundleID: context.inputs.documentationRootReference.bundleID, path: NodeURLGenerator.Path.documentationFolder + path, sourceLanguages: symbol.sourceLanguages ) diff --git a/Sources/SwiftDocC/Infrastructure/NodeURLGenerator.swift b/Sources/SwiftDocC/Infrastructure/NodeURLGenerator.swift index f58a4a32cc..4996e790ab 100644 --- a/Sources/SwiftDocC/Infrastructure/NodeURLGenerator.swift +++ b/Sources/SwiftDocC/Infrastructure/NodeURLGenerator.swift @@ -117,25 +117,30 @@ public struct NodeURLGenerator { } /// Returns a string path appropriate for the given semantic node. - public static func pathForSemantic(_ semantic: Semantic, source: URL, bundle: DocumentationBundle) -> String { + public static func pathForSemantic(_ semantic: Semantic, source: URL, inputInfo: DocumentationContext.Inputs.Info) -> String { let fileName = source.deletingPathExtension().lastPathComponent switch semantic { case is TutorialTableOfContents: return Path.tutorialTableOfContents(name: fileName).stringValue case is Tutorial, is TutorialArticle: - return Path.tutorial(bundleName: bundle.displayName, tutorialName: fileName).stringValue + return Path.tutorial(bundleName: inputInfo.displayName, tutorialName: fileName).stringValue case let article as Article: if article.metadata?.technologyRoot != nil { return Path.documentation(path: fileName).stringValue } else { - return Path.article(bundleName: bundle.displayName, articleName: fileName).stringValue + return Path.article(bundleName: inputInfo.displayName, articleName: fileName).stringValue } default: return fileName } } + @available(*, deprecated, renamed: "pathForSemantic(_:source:inputInfo:)", message: "Use 'pathForSemantic(_:source:inputInfo:)' instead. This deprecated API will be removed after 6.3 is released") + public static func pathForSemantic(_ semantic: Semantic, source: URL, bundle: DocumentationBundle) -> String { + pathForSemantic(semantic, source: source, inputInfo: bundle.info) + } + /// Returns the reference's path in a format that is safe for writing to disk. public static func fileSafeReferencePath( _ reference: ResolvedTopicReference, diff --git a/Sources/SwiftDocC/Infrastructure/Symbol Graph/GeneratedDocumentationTopics.swift b/Sources/SwiftDocC/Infrastructure/Symbol Graph/GeneratedDocumentationTopics.swift index 4ceb41fa38..19e0ede338 100644 --- a/Sources/SwiftDocC/Infrastructure/Symbol Graph/GeneratedDocumentationTopics.swift +++ b/Sources/SwiftDocC/Infrastructure/Symbol Graph/GeneratedDocumentationTopics.swift @@ -96,7 +96,7 @@ enum GeneratedDocumentationTopics { private static let defaultImplementationGroupTitle = "Default Implementations" - private static func createCollectionNode(parent: ResolvedTopicReference, title: String, identifiers: [ResolvedTopicReference], context: DocumentationContext, bundle: DocumentationBundle) throws { + private static func createCollectionNode(parent: ResolvedTopicReference, title: String, identifiers: [ResolvedTopicReference], context: DocumentationContext, inputs: DocumentationContext.Inputs) throws { let automaticCurationSourceLanguage: SourceLanguage let automaticCurationSourceLanguages: Set automaticCurationSourceLanguage = identifiers.first?.sourceLanguage ?? .swift @@ -104,7 +104,7 @@ enum GeneratedDocumentationTopics { // Create the collection topic reference let collectionReference = ResolvedTopicReference( - bundleID: bundle.id, + bundleID: inputs.id, path: NodeURLGenerator.Path.documentationCuration( parentPath: parent.path, articleName: title @@ -227,8 +227,8 @@ enum GeneratedDocumentationTopics { /// - relationships: A set of relationships to inspect. /// - symbolsURLHierarchy: A symbol graph hierarchy as created during symbol registration. /// - context: A documentation context to update. - /// - bundle: The current documentation bundle. - static func createInheritedSymbolsAPICollections(relationships: Set, context: DocumentationContext, bundle: DocumentationBundle) throws { + /// - inputs: The current collection of input files. + static func createInheritedSymbolsAPICollections(relationships: Set, context: DocumentationContext, inputs: DocumentationContext.Inputs) throws { var inheritanceIndex = InheritedSymbols() // Walk the symbol graph relationships and look for parent <-> child links that stem in a different module. @@ -258,7 +258,7 @@ enum GeneratedDocumentationTopics { for (typeReference, collections) in inheritanceIndex.implementingTypes where !collections.inheritedFromTypeName.isEmpty { for (_, collection) in collections.inheritedFromTypeName where !collection.identifiers.isEmpty { // Create a collection for the given provider type's inherited symbols - try createCollectionNode(parent: typeReference, title: collection.title, identifiers: collection.identifiers, context: context, bundle: bundle) + try createCollectionNode(parent: typeReference, title: collection.title, identifiers: collection.identifiers, context: context, inputs: inputs) } } } diff --git a/Sources/SwiftDocC/Infrastructure/Symbol Graph/ResolvedTopicReference+Symbol.swift b/Sources/SwiftDocC/Infrastructure/Symbol Graph/ResolvedTopicReference+Symbol.swift index c03c5d306f..b8253172af 100644 --- a/Sources/SwiftDocC/Infrastructure/Symbol Graph/ResolvedTopicReference+Symbol.swift +++ b/Sources/SwiftDocC/Infrastructure/Symbol Graph/ResolvedTopicReference+Symbol.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -15,13 +15,13 @@ extension ResolvedTopicReference { /// - Parameters: /// - symbolReference: A reference to a symbol. /// - moduleName: The module, to which the symbol belongs. - /// - bundle: A documentation bundle, to which the symbol belongs. - init(symbolReference: SymbolReference, moduleName: String, bundle: DocumentationBundle) { + /// - inputs: A collection of documentation inputs that the symbol belongs to. + init(symbolReference: SymbolReference, moduleName: String, inputs: DocumentationContext.Inputs) { let path = symbolReference.path.isEmpty ? "" : "/" + symbolReference.path self.init( - bundleID: bundle.documentationRootReference.bundleID, - path: bundle.documentationRootReference.appendingPath(moduleName + path).path, + bundleID: inputs.documentationRootReference.bundleID, + path: inputs.documentationRootReference.appendingPath(moduleName + path).path, fragment: nil, sourceLanguages: symbolReference.interfaceLanguages ) diff --git a/Sources/SwiftDocC/Infrastructure/Symbol Graph/SymbolGraphLoader.swift b/Sources/SwiftDocC/Infrastructure/Symbol Graph/SymbolGraphLoader.swift index 4418b6ad60..8a3e613302 100644 --- a/Sources/SwiftDocC/Infrastructure/Symbol Graph/SymbolGraphLoader.swift +++ b/Sources/SwiftDocC/Infrastructure/Symbol Graph/SymbolGraphLoader.swift @@ -11,29 +11,29 @@ import Foundation import SymbolKit -/// Loads symbol graph files from a documentation bundle. +/// Loads symbol graph files from a collection of inputs. /// -/// A type that groups a bundle's symbol graphs by the module they describe, +/// A type that groups a catalogs's symbol graphs by the module they describe, /// which makes detecting symbol collisions and overloads easier. struct SymbolGraphLoader { private(set) var symbolGraphs: [URL: SymbolKit.SymbolGraph] = [:] private(set) var unifiedGraphs: [String: SymbolKit.UnifiedSymbolGraph] = [:] private(set) var graphLocations: [String: [SymbolKit.GraphCollector.GraphKind]] = [:] private let dataProvider: any DataProvider - private let bundle: DocumentationBundle + private let inputs: DocumentationContext.Inputs private let symbolGraphTransformer: ((inout SymbolGraph) -> ())? /// Creates a new symbol graph loader /// - Parameters: - /// - bundle: The documentation bundle from which to load symbol graphs. + /// - inputs: The collection of inputs files from which to load symbol graphs. /// - dataProvider: A provider that the loader uses to read symbol graph data. /// - symbolGraphTransformer: An optional closure that transforms the symbol graph after the loader decodes it. init( - bundle: DocumentationBundle, + inputs: DocumentationContext.Inputs, dataProvider: any DataProvider, symbolGraphTransformer: ((inout SymbolGraph) -> ())? = nil ) { - self.bundle = bundle + self.inputs = inputs self.dataProvider = dataProvider self.symbolGraphTransformer = symbolGraphTransformer } @@ -49,7 +49,7 @@ struct SymbolGraphLoader { /// The symbol graph decoding strategy to use. private(set) var decodingStrategy: DecodingConcurrencyStrategy = .concurrentlyEachFileInBatches - /// Loads all symbol graphs in the given bundle. + /// Loads all symbol graphs in the given catalog. /// /// - Throws: If loading and decoding any of the symbol graph files throws, this method re-throws one of the encountered errors. mutating func loadAll() throws { @@ -82,7 +82,7 @@ struct SymbolGraphLoader { symbolGraphTransformer?(&symbolGraph) let (moduleName, isMainSymbolGraph) = Self.moduleNameFor(symbolGraph, at: symbolGraphURL) - // If the bundle provides availability defaults add symbol availability data. + // If the catalog provides availability defaults add symbol availability data. self.addDefaultAvailability(to: &symbolGraph, moduleName: moduleName) // main symbol graphs are ambiguous @@ -113,22 +113,22 @@ struct SymbolGraphLoader { // This strategy benchmarks better when we have multiple // "larger" symbol graphs. #if os(macOS) || os(iOS) - if bundle.symbolGraphURLs.filter({ !$0.lastPathComponent.contains("@") }).count > 1 { + if inputs.symbolGraphURLs.filter({ !$0.lastPathComponent.contains("@") }).count > 1 { // There are multiple main symbol graphs, better parallelize all files decoding. decodingStrategy = .concurrentlyAllFiles } #endif - let numberOfSymbolGraphs = bundle.symbolGraphURLs.count + let numberOfSymbolGraphs = inputs.symbolGraphURLs.count let decodeSignpostHandle = signposter.beginInterval("Decode symbol graphs", id: signposter.makeSignpostID(), "Decode \(numberOfSymbolGraphs) symbol graphs") switch decodingStrategy { case .concurrentlyAllFiles: // Concurrently load and decode all symbol graphs - bundle.symbolGraphURLs.concurrentPerform(block: loadGraphAtURL) + inputs.symbolGraphURLs.concurrentPerform(block: loadGraphAtURL) case .concurrentlyEachFileInBatches: // Serially load and decode all symbol graphs, each one in concurrent batches. - bundle.symbolGraphURLs.forEach(loadGraphAtURL) + inputs.symbolGraphURLs.forEach(loadGraphAtURL) } signposter.endInterval("Decode symbol graphs", decodeSignpostHandle) @@ -166,7 +166,7 @@ struct SymbolGraphLoader { var defaultUnavailablePlatforms = [PlatformName]() var defaultAvailableInformation = [DefaultAvailability.ModuleAvailability]() - if let defaultAvailabilities = bundle.info.defaultAvailability?.modules[unifiedGraph.moduleName] { + if let defaultAvailabilities = inputs.info.defaultAvailability?.modules[unifiedGraph.moduleName] { let (unavailablePlatforms, availablePlatforms) = defaultAvailabilities.categorize(where: { $0.versionInformation == .unavailable }) defaultUnavailablePlatforms = unavailablePlatforms.map(\.platformName) defaultAvailableInformation = availablePlatforms @@ -264,11 +264,11 @@ struct SymbolGraphLoader { } } - /// If the bundle defines default availability for the symbols in the given symbol graph + /// If the catalog defines default availability for the symbols in the given symbol graph /// this method adds them to each of the symbols in the graph. private func addDefaultAvailability(to symbolGraph: inout SymbolGraph, moduleName: String) { // Check if there are defined default availabilities for the current module - if let defaultAvailabilities = bundle.info.defaultAvailability?.modules[moduleName], + if let defaultAvailabilities = inputs.info.defaultAvailability?.modules[moduleName], let platformName = symbolGraph.module.platform.name.map(PlatformName.init) { // Prepare a default availability versions lookup for this module. @@ -465,7 +465,7 @@ extension SymbolGraph.Symbol.Availability.AvailabilityItem { in from the `defaults`. If the defaults do not have a version for this item's domain/platform, also try the `fallbackPlatform`. - - parameter defaults: Default module availabilities for each platform mentioned in a documentation bundle's `Info.plist` + - parameter defaults: Default module availabilities for each platform mentioned in a documentation catalog's `Info.plist` - parameter fallbackPlatform: An optional fallback platform name if this item's domain isn't found in the `defaults`. */ func fillingMissingIntroducedVersion(from defaults: [PlatformName: SymbolGraph.SemanticVersion], diff --git a/Sources/SwiftDocC/Infrastructure/Symbol Graph/SymbolGraphRelationshipsBuilder.swift b/Sources/SwiftDocC/Infrastructure/Symbol Graph/SymbolGraphRelationshipsBuilder.swift index 836b84775d..96698aae9e 100644 --- a/Sources/SwiftDocC/Infrastructure/Symbol Graph/SymbolGraphRelationshipsBuilder.swift +++ b/Sources/SwiftDocC/Infrastructure/Symbol Graph/SymbolGraphRelationshipsBuilder.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -52,14 +52,12 @@ struct SymbolGraphRelationshipsBuilder { /// - Parameters: /// - edge: A symbol graph relationship with a source and a target. /// - selector: The symbol graph selector in which the relationship is relevant. - /// - bundle: A documentation bundle. /// - context: A documentation context. /// - localCache: A cache of local documentation content. /// - engine: A diagnostic collecting engine. static func addImplementationRelationship( edge: SymbolGraph.Relationship, selector: UnifiedSymbolGraph.Selector, - in bundle: DocumentationBundle, context: DocumentationContext, localCache: DocumentationContext.LocalCache, engine: DiagnosticEngine @@ -83,7 +81,7 @@ struct SymbolGraphRelationshipsBuilder { ?? implementorNode.reference.sourceLanguage let symbolReference = SymbolReference(edge.target, interfaceLanguage: language, symbol: localCache[edge.target]?.symbol) - guard let unresolved = UnresolvedTopicReference(symbolReference: symbolReference, bundle: bundle) else { + guard let unresolved = UnresolvedTopicReference(symbolReference: symbolReference, inputs: context.inputs) else { // The symbol reference format is invalid. assertionFailure(AssertionMessages.invalidSymbolReference(symbolReference)) return @@ -137,14 +135,14 @@ struct SymbolGraphRelationshipsBuilder { /// - Parameters: /// - edge: A symbol-graph relationship with a source and a target. /// - selector: The symbol graph selector in which the relationship is relevant. - /// - bundle: A documentation bundle. + /// - inputs: The collection of inputs files that the context was created from. /// - localCache: A cache of local documentation content. /// - externalCache: A cache of external documentation content. /// - engine: A diagnostic collecting engine. static func addConformanceRelationship( edge: SymbolGraph.Relationship, selector: UnifiedSymbolGraph.Selector, - in bundle: DocumentationBundle, + in inputs: DocumentationContext.Inputs, localCache: DocumentationContext.LocalCache, externalCache: DocumentationContext.ExternalCache, engine: DiagnosticEngine @@ -173,7 +171,7 @@ struct SymbolGraphRelationshipsBuilder { ?? conformingNode.reference.sourceLanguage let symbolReference = SymbolReference(edge.target, interfaceLanguage: language, symbol: localCache[edge.target]?.symbol) - guard let unresolved = UnresolvedTopicReference(symbolReference: symbolReference, bundle: bundle) else { + guard let unresolved = UnresolvedTopicReference(symbolReference: symbolReference, inputs: inputs) else { // The symbol reference format is invalid. assertionFailure(AssertionMessages.invalidSymbolReference(symbolReference)) return @@ -226,14 +224,14 @@ struct SymbolGraphRelationshipsBuilder { /// - Parameters: /// - edge: A symbol graph relationship with a source and a target. /// - selector: The symbol graph selector in which the relationship is relevant. - /// - bundle: A documentation bundle. + /// - inputs: The collection of inputs files that the context was created from. /// - localCache: A cache of local documentation content. /// - externalCache: A cache of external documentation content. /// - engine: A diagnostic collecting engine. static func addInheritanceRelationship( edge: SymbolGraph.Relationship, selector: UnifiedSymbolGraph.Selector, - in bundle: DocumentationBundle, + in inputs: DocumentationContext.Inputs, localCache: DocumentationContext.LocalCache, externalCache: DocumentationContext.ExternalCache, engine: DiagnosticEngine @@ -260,7 +258,7 @@ struct SymbolGraphRelationshipsBuilder { let language = childNode.reference.sourceLanguage let symbolReference = SymbolReference(edge.target, interfaceLanguage: language, symbol: nil) - guard let unresolved = UnresolvedTopicReference(symbolReference: symbolReference, bundle: bundle) else { + guard let unresolved = UnresolvedTopicReference(symbolReference: symbolReference, inputs: inputs) else { // The symbol reference format is invalid. assertionFailure(AssertionMessages.invalidSymbolReference(symbolReference)) return diff --git a/Sources/SwiftDocC/Infrastructure/Symbol Graph/UnresolvedTopicReference+Symbol.swift b/Sources/SwiftDocC/Infrastructure/Symbol Graph/UnresolvedTopicReference+Symbol.swift index 42cacab44e..5d49a41e37 100644 --- a/Sources/SwiftDocC/Infrastructure/Symbol Graph/UnresolvedTopicReference+Symbol.swift +++ b/Sources/SwiftDocC/Infrastructure/Symbol Graph/UnresolvedTopicReference+Symbol.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -14,11 +14,11 @@ extension UnresolvedTopicReference { /// Creates an unresolved reference out of a symbol reference. /// - Parameters: /// - symbolReference: A reference to a symbol. - /// - bundle: A documentation bundle. - init?(symbolReference: SymbolReference, bundle: DocumentationBundle) { + /// - inputs: A collection of inputs files that the symbol is from. + init?(symbolReference: SymbolReference, inputs: DocumentationContext.Inputs) { guard var components = URLComponents(string: symbolReference.path) else { return nil } components.scheme = ResolvedTopicReference.urlScheme - components.host = bundle.id.rawValue + components.host = inputs.id.rawValue if !components.path.hasPrefix("/") { components.path.insert("/", at: components.path.startIndex) } diff --git a/Sources/SwiftDocC/Infrastructure/Topic Graph/AutomaticCuration.swift b/Sources/SwiftDocC/Infrastructure/Topic Graph/AutomaticCuration.swift index be5516727a..0501f3d04c 100644 --- a/Sources/SwiftDocC/Infrastructure/Topic Graph/AutomaticCuration.swift +++ b/Sources/SwiftDocC/Infrastructure/Topic Graph/AutomaticCuration.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -148,14 +148,12 @@ public struct AutomaticCuration { /// - Parameters: /// - node: A node for which to generate a See Also group. /// - context: A documentation context. - /// - bundle: A documentation bundle. /// - Returns: A group title and the group's references or links. /// `nil` if the method can't find any relevant links to automatically generate a See Also content. static func seeAlso( for node: DocumentationNode, withTraits variantsTraits: Set, context: DocumentationContext, - bundle: DocumentationBundle, renderContext: RenderContext?, renderer: DocumentationContentRenderer ) -> TaskGroup? { diff --git a/Sources/SwiftDocC/Infrastructure/Workspace/DefaultAvailability.swift b/Sources/SwiftDocC/Infrastructure/Workspace/DefaultAvailability.swift index 4f4bcb49d7..f6170906e4 100644 --- a/Sources/SwiftDocC/Infrastructure/Workspace/DefaultAvailability.swift +++ b/Sources/SwiftDocC/Infrastructure/Workspace/DefaultAvailability.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -14,7 +14,7 @@ import Foundation /// /// Default availability is used as a fallback value for symbols without explicit availability information. /// -/// This information can be authored in the bundle's Info.plist file, as a dictionary of module names to arrays of platform "name" and "version" pairs, +/// This information can be authored in the catalog's Info.plist file, as a dictionary of module names to arrays of platform "name" and "version" pairs, /// or in the case where the platform in unconditionally unavailable, "name" and "unavailable" pairs: /// /// ``` @@ -107,7 +107,7 @@ public struct DefaultAvailability: Codable, Equatable { // semantic version. if let introducedVersion { guard let version = Version(versionString: introducedVersion), (2...3).contains(version.count) else { - throw DocumentationBundle.PropertyListError.invalidVersionString(introducedVersion) + throw DocumentationContext.Inputs.PropertyListError.invalidVersionString(introducedVersion) } } } diff --git a/Sources/SwiftDocC/Infrastructure/Workspace/DocumentationBundle+Info.swift b/Sources/SwiftDocC/Infrastructure/Workspace/DocumentationBundle+Info.swift index 28d4490c80..a46a5bc4a0 100644 --- a/Sources/SwiftDocC/Infrastructure/Workspace/DocumentationBundle+Info.swift +++ b/Sources/SwiftDocC/Infrastructure/Workspace/DocumentationBundle+Info.swift @@ -10,27 +10,27 @@ public import Foundation -extension DocumentationBundle { - /// Information about a documentation bundle that's unrelated to its documentation content. +extension DocumentationContext.Inputs { + /// Information about a documentation catalog that's unrelated to its documentation content. /// - /// This information is meant to be decoded from the bundle's Info.plist file. + /// This information is meant to be decoded from the catalog's Info.plist file. public struct Info: Codable, Equatable { - /// The display name of the bundle. + /// The display name of the catalog. public var displayName: String - /// The unique identifier of the bundle. - public var id: DocumentationBundle.Identifier + /// The unique identifier of the catalog. + public var id: DocumentationContext.Inputs.Identifier - /// The default language identifier for code listings in the bundle. + /// The default language identifier for code listings in the catalog. public var defaultCodeListingLanguage: String? - /// The default availability for the various modules in the bundle. + /// The default availability for the various modules in the catalog. public var defaultAvailability: DefaultAvailability? - /// The default kind for the various modules in the bundle. + /// The default kind for the various modules in the catalog. public var defaultModuleKind: String? - /// The parsed feature flags that were set for this bundle. + /// The parsed feature flags that were set for this catalog. internal var featureFlags: BundleFeatureFlags? /// The keys that must be present in an Info.plist file in order for doc compilation to proceed. @@ -76,16 +76,16 @@ extension DocumentationBundle { } } - /// Creates a new documentation bundle information value. + /// Creates a new documentation information value. /// - Parameters: - /// - displayName: The display name of the bundle. - /// - id: The unique identifier of the bundle. - /// - defaultCodeListingLanguage: The default language identifier for code listings in the bundle. - /// - defaultAvailability: The default availability for the various modules in the bundle. - /// - defaultModuleKind: The default kind for the various modules in the bundle. + /// - displayName: The display name of the catalog. + /// - id: The unique identifier of the catalog. + /// - defaultCodeListingLanguage: The default language identifier for code listings in the catalog. + /// - defaultAvailability: The default availability for the various modules in the catalog. + /// - defaultModuleKind: The default kind for the various modules in the catalog. public init( displayName: String, - id: DocumentationBundle.Identifier, + id: DocumentationContext.Inputs.Identifier, defaultCodeListingLanguage: String?, defaultAvailability: DefaultAvailability?, defaultModuleKind: String? @@ -100,11 +100,10 @@ extension DocumentationBundle { ) } - /// Creates documentation bundle information from the given Info.plist data, falling back to the values - /// in the given bundle discovery options if necessary. + /// Creates documentation information from the given Info.plist data, falling back to the values in the given discovery options if necessary. init( from infoPlist: Data? = nil, - bundleDiscoveryOptions options: BundleDiscoveryOptions? = nil, + catalogDiscoveryOptions options: CatalogDiscoveryOptions? = nil, derivedDisplayName: String? = nil ) throws { if let infoPlist { @@ -120,7 +119,7 @@ extension DocumentationBundle { do { self = try propertyListDecoder.decode( - DocumentationBundle.Info.self, + DocumentationContext.Inputs.Info.self, from: infoPlist ) } catch DecodingError.dataCorrupted(let context) { @@ -130,26 +129,26 @@ extension DocumentationBundle { } else { try self.init( with: nil, - bundleDiscoveryOptions: options, + catalogDiscoveryOptions: options, derivedDisplayName: derivedDisplayName ) } } public init(from decoder: any Decoder) throws { - let bundleDiscoveryOptions = decoder.userInfo[.bundleDiscoveryOptions] as? BundleDiscoveryOptions + let catalogDiscoveryOptions = decoder.userInfo[.bundleDiscoveryOptions] as? CatalogDiscoveryOptions let derivedDisplayName = decoder.userInfo[.derivedDisplayName] as? String try self.init( with: decoder.container(keyedBy: CodingKeys.self), - bundleDiscoveryOptions: bundleDiscoveryOptions, + catalogDiscoveryOptions: catalogDiscoveryOptions, derivedDisplayName: derivedDisplayName ) } private init( - with values: KeyedDecodingContainer?, - bundleDiscoveryOptions: BundleDiscoveryOptions?, + with values: KeyedDecodingContainer?, + catalogDiscoveryOptions: CatalogDiscoveryOptions?, derivedDisplayName: String? ) throws { // Here we define two helper functions that simplify @@ -164,7 +163,7 @@ extension DocumentationBundle { with key: CodingKeys ) throws -> T? where T : Decodable { try values?.decodeIfPresent(T.self, forKey: key) - ?? bundleDiscoveryOptions?.infoPlistFallbacks.decodeIfPresent(T.self, forKey: key.rawValue) + ?? catalogDiscoveryOptions?.infoPlistFallbacks.decodeIfPresent(T.self, forKey: key.rawValue) } /// Helper function that decodes a value of the given type for the given key @@ -173,13 +172,13 @@ extension DocumentationBundle { _ expectedType: T.Type, with key: CodingKeys ) throws -> T where T : Decodable { - if let bundleDiscoveryOptions { + if let catalogDiscoveryOptions { return try values?.decodeIfPresent(T.self, forKey: key) - ?? bundleDiscoveryOptions.infoPlistFallbacks.decode(T.self, forKey: key.rawValue) + ?? catalogDiscoveryOptions.infoPlistFallbacks.decode(T.self, forKey: key.rawValue) } else if let values { return try values.decode(T.self, forKey: key) } else { - throw DocumentationBundle.PropertyListError.keyNotFound(key.rawValue) + throw DocumentationContext.Inputs.PropertyListError.keyNotFound(key.rawValue) } } @@ -190,7 +189,7 @@ extension DocumentationBundle { // **all** missing required keys, instead of just the first one hit. var givenKeys = Set(values?.allKeys ?? []).union( - bundleDiscoveryOptions?.infoPlistFallbacks.keys.compactMap { + catalogDiscoveryOptions?.infoPlistFallbacks.keys.compactMap { CodingKeys(stringValue: $0) } ?? [] ) @@ -232,7 +231,7 @@ extension DocumentationBundle { init( displayName: String, - id: DocumentationBundle.Identifier, + id: DocumentationContext.Inputs.Identifier, defaultCodeListingLanguage: String? = nil, defaultModuleKind: String? = nil, defaultAvailability: DefaultAvailability? = nil, @@ -248,19 +247,18 @@ extension DocumentationBundle { } } -extension BundleDiscoveryOptions { - /// Creates new bundle discovery options with the given information. - /// - /// The given fallback values will be used if any of the discovered bundles are missing that - /// value in their Info.plist configuration file. - /// +extension CatalogDiscoveryOptions { + /// Creates new catalog discovery options with the given information. + /// + /// The given fallback values will be used if the discovered catalog is missing that value in its Info.plist configuration file. + /// /// - Parameters: - /// - fallbackDisplayName: A fallback display name for the bundle. - /// - fallbackIdentifier: A fallback identifier for the bundle. - /// - fallbackDefaultCodeListingLanguage: A fallback default code listing language for the bundle. - /// - fallbackDefaultModuleKind: A fallback default module kind for the bundle. - /// - fallbackDefaultAvailability: A fallback default availability for the bundle. - /// - additionalSymbolGraphFiles: Additional symbol graph files to augment any discovered bundles. + /// - fallbackDisplayName: A fallback display name for the catalog. + /// - fallbackIdentifier: A fallback identifier for the catalog. + /// - fallbackDefaultCodeListingLanguage: A fallback default code listing language for the catalog. + /// - fallbackDefaultModuleKind: A fallback default module kind for the catalog. + /// - fallbackDefaultAvailability: A fallback default availability for the catalog. + /// - additionalSymbolGraphFiles: Additional symbol graph files to augment the discovered catalog. public init( fallbackDisplayName: String? = nil, fallbackIdentifier: String? = nil, @@ -274,7 +272,7 @@ extension BundleDiscoveryOptions { // This ensures that when new coding keys are added, the compiler will enforce // that we handle them here as well. - let fallbacks = DocumentationBundle.Info.CodingKeys.allCases.compactMap { key -> (String, Any)? in + let fallbacks = DocumentationContext.Inputs.Info.CodingKeys.allCases.compactMap { key -> (String, Any)? in let value: Any? switch key { @@ -307,7 +305,7 @@ extension BundleDiscoveryOptions { } private extension CodingUserInfoKey { - /// A user info key to store bundle discovery options in the decoder. + /// A user info key to store catalog discovery options in the decoder. static let bundleDiscoveryOptions = CodingUserInfoKey(rawValue: "bundleDiscoveryOptions")! /// A user info key to store derived display name in the decoder. static let derivedDisplayName = CodingUserInfoKey(rawValue: "derivedDisplayName")! diff --git a/Sources/SwiftDocC/Infrastructure/Workspace/DocumentationWorkspaceDataProvider.swift b/Sources/SwiftDocC/Infrastructure/Workspace/DocumentationWorkspaceDataProvider.swift index e068262975..686cfb17eb 100644 --- a/Sources/SwiftDocC/Infrastructure/Workspace/DocumentationWorkspaceDataProvider.swift +++ b/Sources/SwiftDocC/Infrastructure/Workspace/DocumentationWorkspaceDataProvider.swift @@ -10,25 +10,22 @@ public import Foundation - -/// Options to configure the discovery of documentation bundles -public struct BundleDiscoveryOptions { +/// Options to configure the discovery of a documentation catalog +public struct CatalogDiscoveryOptions { // When adding new configuration, remember to include a default value in the initializer so that an options // value can be created without passing any arguments, resulting in the "default" configuration. - // - // The provider uses the default configuration in the `DocumentationWorkspaceDataProvider.bundles()` function. - /// Fallback values for information that's missing in the bundle's Info.plist file. + /// Fallback values for information that's missing in the catalog's Info.plist file. public let infoPlistFallbacks: [String: Any] - /// Additional symbol graph files that the provider should include in the discovered bundles. + /// Additional symbol graph files that the provider should include in the discovered catalog. public let additionalSymbolGraphFiles: [URL] /// Creates a new options value with the given configurations. /// /// - Parameters: - /// - infoPlistFallbacks: Fallback values for information that's missing in the bundle's Info.plist file. - /// - additionalSymbolGraphFiles: Additional symbol graph files that the provider should include in the discovered bundles. + /// - infoPlistFallbacks: Fallback values for information that's missing in the catalog's Info.plist file. + /// - additionalSymbolGraphFiles: Additional symbol graph files that the provider should include in the discovered catalog. public init( infoPlistFallbacks: [String: Any] = [:], additionalSymbolGraphFiles: [URL] = [] @@ -37,25 +34,24 @@ public struct BundleDiscoveryOptions { self.additionalSymbolGraphFiles = additionalSymbolGraphFiles } - /// Creates new bundle discovery options with the provided documentation bundle info - /// as Info.plist fallback values. + /// Creates new catalog discovery options with the provided documentation info as Info.plist fallback values. /// /// - Parameters: - /// - fallbackInfo: Fallback documentation bundle information to use if any discovered bundles are missing an Info.plist. - /// - additionalSymbolGraphFiles: Additional symbol graph files to augment any discovered bundles. + /// - fallbackInfo: Fallback documentation information to use if the discovered catalog is missing an Info.plist file. + /// - additionalSymbolGraphFiles: Additional symbol graph files to augment the discovered catalog. public init( - fallbackInfo: DocumentationBundle.Info, + fallbackInfo: DocumentationContext.Inputs.Info, additionalSymbolGraphFiles: [URL] = [] ) throws { // Use JSONEncoder to dynamically create the Info.plist fallback - // dictionary the `BundleDiscoveryOption`s expect from given DocumentationBundle.Info + // dictionary the `CatalogDiscoveryOption`s expect from given DocumentationContext.Inputs.Info // model. let data = try JSONEncoder().encode(fallbackInfo) let serializedFallbackInfo = try JSONSerialization.jsonObject(with: data) guard let fallbackInfoDictionary = serializedFallbackInfo as? [String: Any] else { - throw DocumentationBundle.Info.Error.wrongType( + throw DocumentationContext.Inputs.Info.Error.wrongType( expected: [String: Any].Type.self, actual: type(of: serializedFallbackInfo) ) @@ -67,3 +63,6 @@ public struct BundleDiscoveryOptions { ) } } + +@available(*, deprecated, renamed: "CatalogDiscoveryOptions", message: "Use 'CatalogDiscoveryOptions' instead. This deprecated type will be removed after 6.3 is released.") +public typealias BundleDiscoveryOptions = CatalogDiscoveryOptions diff --git a/Sources/SwiftDocC/Infrastructure/Workspace/FeatureFlags+Info.swift b/Sources/SwiftDocC/Infrastructure/Workspace/FeatureFlags+Info.swift index dd62465ddd..bc44d2e339 100644 --- a/Sources/SwiftDocC/Infrastructure/Workspace/FeatureFlags+Info.swift +++ b/Sources/SwiftDocC/Infrastructure/Workspace/FeatureFlags+Info.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2024 Apple Inc. and the Swift project authors + Copyright (c) 2024-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -10,11 +10,11 @@ import Foundation -extension DocumentationBundle.Info { - /// A collection of feature flags that can be enabled from a bundle's Info.plist. +extension DocumentationContext.Inputs.Info { + /// A collection of feature flags that can be enabled from a catalog's Info.plist. /// /// This is a subset of flags from ``FeatureFlags`` that can influence how a documentation - /// bundle is written, and so can be considered a property of the documentation itself, rather + /// catalog is written, and so can be considered a property of the documentation itself, rather /// than as an experimental behavior that can be enabled for one-off builds. /// /// ```xml diff --git a/Sources/SwiftDocC/LinkTargets/LinkDestinationSummary.swift b/Sources/SwiftDocC/LinkTargets/LinkDestinationSummary.swift index 8c6112dbb1..b2e0fdac4b 100644 --- a/Sources/SwiftDocC/LinkTargets/LinkDestinationSummary.swift +++ b/Sources/SwiftDocC/LinkTargets/LinkDestinationSummary.swift @@ -14,13 +14,13 @@ import SymbolKit // Link resolution works in two parts: // -// 1. When DocC compiles a documentation bundle and encounters an "external" reference it will call out to -// resolve that reference using the external resolver that's been registered for that bundle identifier. -// The reference may be a page in another documentation bundle or a page from another source. +// 1. When DocC compiles a documentation catalog and encounters an "external" reference it will call out to +// resolve that reference using the external resolver that's been registered for that identifier. +// The reference may be a page in another documentation catalog or a page from another source. // -// 2. Once DocC has finished compiling the documentation bundle it will summarize all the pages and on-page +// 2. Once DocC has finished compiling the documentation catalog it will summarize all the pages and on-page // elements that can be linked to. -// This information is returned when another documentation bundle resolves a reference for that page. +// This information is returned when another unit of documentation resolves a reference for that page. // // // DocC Backend endpoint @@ -28,7 +28,7 @@ import SymbolKit // │ ┌──────────────────────────┐ │ │ │ // │ │ │ │ │ │ // │ │ DocumentationContext │ │ │ │ -// │ │ Register bundle │ │ │ │ +// │ │ Register catalog │ │ │ │ // │ │ │ │ │ │ // │ └──────────────────────────┘ Resolve external │ │ │ // │ │ references │ │ │ @@ -63,9 +63,9 @@ import SymbolKit // │ │ └───────────────────────┘ │ │ // └──────────────────────────────────────────────────────────┘ └───────────────────────────────┘ -/// A summary of an element that you can link to from outside the documentation bundle. +/// A summary of an element that you can link to from outside the unit of documentation. /// -/// The non-optional properties of this summary are all the information needed when another bundle references this element. +/// The non-optional properties of this summary are all the information needed when another catalog references this element. /// /// Various information from the summary is used depending on what content references the summarized element. For example: /// - In a paragraph of text, a link to this element will use the ``title`` as the link text and style the tile in code font if the ``kind`` is a type of symbol. @@ -299,7 +299,7 @@ public struct LinkDestinationSummary: Codable, Equatable { // MARK: - Accessing the externally linkable elements public extension DocumentationNode { - /// Summarizes the node and all of its child elements that you can link to from outside the bundle. + /// Summarizes the node and all of its child elements that you can link to from outside the local unit of documentation. /// /// - Parameters: /// - context: The context in which references that are found the node's content are resolved in. @@ -311,15 +311,15 @@ public extension DocumentationNode { renderNode: RenderNode, includeTaskGroups: Bool = true ) -> [LinkDestinationSummary] { - let bundle = context.bundle - guard bundle.id == reference.bundleID else { + let inputs = context.inputs + guard inputs.id == reference.bundleID else { // Don't return anything for external references that don't have a bundle in the context. return [] } - let urlGenerator = PresentationURLGenerator(context: context, baseURL: bundle.baseURL) + let urlGenerator = PresentationURLGenerator(context: context, baseURL: inputs.baseURL) let relativePresentationURL = urlGenerator.presentationURLForReference(reference).withoutHostAndPortAndScheme() - var compiler = RenderContentCompiler(context: context, bundle: bundle, identifier: reference) + var compiler = RenderContentCompiler(context: context, identifier: reference) let platforms = renderNode.metadata.platforms @@ -523,7 +523,7 @@ extension LinkDestinationSummary { /// /// - Parameters: /// - landmark: The landmark to summarize. - /// - relativeParentPresentationURL: The bundle-relative path of the page that contain this section. + /// - relativeParentPresentationURL: The relative path of the page that contain this section. /// - page: The topic reference of the page that contain this section. /// - compiler: The content compiler that's used to render the section's abstract. init?(landmark: any Landmark, relativeParentPresentationURL: URL, page: DocumentationNode, platforms: [PlatformAvailability]?, compiler: inout RenderContentCompiler) { diff --git a/Sources/SwiftDocC/Model/BuildMetadata.swift b/Sources/SwiftDocC/Model/BuildMetadata.swift index 39a83aa468..a3c91f482a 100644 --- a/Sources/SwiftDocC/Model/BuildMetadata.swift +++ b/Sources/SwiftDocC/Model/BuildMetadata.swift @@ -10,7 +10,7 @@ import Foundation -/// A value that encapsulates metadata for a documentation bundle that DocC built. +/// A value that encapsulates metadata for a documentation archive that DocC built. public struct BuildMetadata: Codable { /// The current version of the build metadata schema. @@ -20,18 +20,18 @@ public struct BuildMetadata: Codable { patch: 0 ) - /// The display name of the documentation bundle that DocC built. + /// The display name of the documentation archive that DocC built. public var bundleDisplayName: String - /// The bundle identifier of the documentation bundle that DocC built. - public let bundleID: DocumentationBundle.Identifier + /// The stable identifier of the documentation archive that DocC built. + public let bundleID: DocumentationContext.Inputs.Identifier - /// Creates a build metadata value for a documentation bundle built by DocC. + /// Creates a build metadata value for a documentation archive built by DocC. /// /// - Parameters: - /// - bundleDisplayName: The display name of the documentation bundle. - /// - bundleID: The bundle identifier of the documentation bundle. - public init(bundleDisplayName: String, bundleID: DocumentationBundle.Identifier) { + /// - bundleDisplayName: The display name of the documentation archive. + /// - bundleID: The bundle identifier of the documentation archive. + public init(bundleDisplayName: String, bundleID: DocumentationContext.Inputs.Identifier) { self.bundleDisplayName = bundleDisplayName self.bundleID = bundleID } diff --git a/Sources/SwiftDocC/Model/DocumentationNode.swift b/Sources/SwiftDocC/Model/DocumentationNode.swift index 803ddb7761..da4bc6751f 100644 --- a/Sources/SwiftDocC/Model/DocumentationNode.swift +++ b/Sources/SwiftDocC/Model/DocumentationNode.swift @@ -332,14 +332,14 @@ public struct DocumentationNode { mutating func initializeSymbolContent( documentationExtension: Article?, engine: DiagnosticEngine, - bundle: DocumentationBundle + inputs: DocumentationContext.Inputs ) { precondition(unifiedSymbol != nil && symbol != nil, "You can only call initializeSymbolContent() on a symbol node.") let (markup, docChunks, metadataFromDocumentationComment) = Self.contentFrom( documentedSymbol: unifiedSymbol?.documentedSymbol, documentationExtension: documentationExtension, - bundle: bundle, + inputs: inputs, engine: engine ) @@ -500,7 +500,7 @@ public struct DocumentationNode { static func contentFrom( documentedSymbol: SymbolGraph.Symbol?, documentationExtension: Article?, - bundle: DocumentationBundle? = nil, + inputs: DocumentationContext.Inputs? = nil, engine: DiagnosticEngine ) -> ( markup: any Markup, @@ -543,14 +543,14 @@ public struct DocumentationNode { var problems = [Problem]() - if let bundle { + if let inputs { metadata = DirectiveParser() .parseSingleDirective( Metadata.self, from: &docCommentMarkupElements, parentType: Symbol.self, source: docCommentLocation?.url, - bundle: bundle, + inputs: inputs, problems: &problems ) diff --git a/Sources/SwiftDocC/Model/Identifier.swift b/Sources/SwiftDocC/Model/Identifier.swift index 469af2f4ca..fa5020aa52 100644 --- a/Sources/SwiftDocC/Model/Identifier.swift +++ b/Sources/SwiftDocC/Model/Identifier.swift @@ -140,7 +140,7 @@ extension TopicReferenceResolutionErrorInfo { /// > Important: This type has copy-on-write semantics and wraps an underlying class to store /// > its data. public struct ResolvedTopicReference: Hashable, Codable, Equatable, CustomStringConvertible { - typealias ReferenceBundleIdentifier = DocumentationBundle.Identifier + typealias ReferenceBundleIdentifier = DocumentationContext.Inputs.Identifier private struct ReferenceKey: Hashable { var path: String var fragment: String? @@ -150,13 +150,13 @@ public struct ResolvedTopicReference: Hashable, Codable, Equatable, CustomString /// A synchronized reference cache to store resolved references. private static var sharedPool = Synchronized([ReferenceBundleIdentifier: [ReferenceKey: ResolvedTopicReference]]()) - /// Clears cached references belonging to the bundle with the given identifier. - /// - Parameter id: The identifier of the bundle to which the method should clear belonging references. + /// Clears cached references belonging to the unit of documentation with the given identifier. + /// - Parameter id: The identifier of the unit of documentation to which the method should clear belonging references. static func purgePool(for id: ReferenceBundleIdentifier) { sharedPool.sync { $0.removeValue(forKey: id) } } - /// Enables reference caching for any identifiers created with the given bundle identifier. + /// Enables reference caching for any identifiers created with the given identifier. static func enableReferenceCaching(for id: ReferenceBundleIdentifier) { sharedPool.sync { sharedPool in if !sharedPool.keys.contains(id) { @@ -176,12 +176,12 @@ public struct ResolvedTopicReference: Hashable, Codable, Equatable, CustomString /// The storage for the resolved topic reference's state. let _storage: Storage - /// The identifier of the bundle that owns this documentation topic. - public var bundleID: DocumentationBundle.Identifier { + /// The identifier of the unit of documentation that owns this documentation topic. + public var bundleID: DocumentationContext.Inputs.Identifier { _storage.bundleID } - /// The absolute path from the bundle to this topic, delimited by `/`. + /// The path from the root of documentation to this topic, delimited by `/`. public var path: String { return _storage.path } @@ -207,11 +207,11 @@ public struct ResolvedTopicReference: Hashable, Codable, Equatable, CustomString } /// - Note: The `path` parameter is escaped to a path readable string. - public init(bundleID: DocumentationBundle.Identifier, path: String, fragment: String? = nil, sourceLanguage: SourceLanguage) { + public init(bundleID: DocumentationContext.Inputs.Identifier, path: String, fragment: String? = nil, sourceLanguage: SourceLanguage) { self.init(bundleID: bundleID, path: path, fragment: fragment, sourceLanguages: [sourceLanguage]) } - public init(bundleID: DocumentationBundle.Identifier, path: String, fragment: String? = nil, sourceLanguages: Set) { + public init(bundleID: DocumentationContext.Inputs.Identifier, path: String, fragment: String? = nil, sourceLanguages: Set) { self.init( bundleID: bundleID, urlReadablePath: urlReadablePath(path), @@ -220,7 +220,7 @@ public struct ResolvedTopicReference: Hashable, Codable, Equatable, CustomString ) } - private init(bundleID: DocumentationBundle.Identifier, urlReadablePath: String, urlReadableFragment: String? = nil, sourceLanguages: Set) { + private init(bundleID: DocumentationContext.Inputs.Identifier, urlReadablePath: String, urlReadableFragment: String? = nil, sourceLanguages: Set) { precondition(!sourceLanguages.isEmpty, "ResolvedTopicReference.sourceLanguages cannot be empty") // Check for a cached instance of the reference let key = ReferenceKey(path: urlReadablePath, fragment: urlReadableFragment, sourceLanguages: sourceLanguages) @@ -440,7 +440,7 @@ public struct ResolvedTopicReference: Hashable, Codable, Equatable, CustomString /// /// This is a reference type which allows ``ResolvedTopicReference`` to have copy-on-write behavior. class Storage: Hashable { - let bundleID: DocumentationBundle.Identifier + let bundleID: DocumentationContext.Inputs.Identifier let path: String let fragment: String? let sourceLanguages: Set @@ -452,7 +452,7 @@ public struct ResolvedTopicReference: Hashable, Codable, Equatable, CustomString let absoluteString: String init( - bundleID: DocumentationBundle.Identifier, + bundleID: DocumentationContext.Inputs.Identifier, path: String, fragment: String? = nil, sourceLanguages: Set @@ -521,7 +521,7 @@ extension ResolvedTopicReference: RenderJSONDiffable { /// You can create unresolved references from partial information if that information can be derived from the enclosing context when the /// reference is resolved. For example: /// -/// - The bundle identifier can be inferred from the documentation bundle that owns the document from which the unresolved reference came. +/// - The identifier can be inferred from the unit of documentation that owns the document from which the unresolved reference came. /// - The URL scheme of topic references is always "doc". /// - The symbol precise identifier suffix can be left out when there are no known overloads or name collisions for the symbol. public struct UnresolvedTopicReference: Hashable, CustomStringConvertible { @@ -529,7 +529,7 @@ public struct UnresolvedTopicReference: Hashable, CustomStringConvertible { public let topicURL: ValidatedURL /// The bundle identifier, if one was provided in the host name component of the original URL. - public var bundleID: DocumentationBundle.Identifier? { + public var bundleID: DocumentationContext.Inputs.Identifier? { topicURL.components.host.map { .init(rawValue: $0) } } @@ -589,17 +589,17 @@ public struct UnresolvedTopicReference: Hashable, CustomStringConvertible { /// A reference to an auxiliary resource such as an image. public struct ResourceReference: Hashable { - /// The documentation bundle identifier for the bundle in which this resource resides. - public let bundleID: DocumentationBundle.Identifier + /// The identifier for the unit of documentation in which this resource resides. + public let bundleID: DocumentationContext.Inputs.Identifier - /// The path of the resource local to its bundle. + /// The path of the resource local to its unit of documentation. public let path: String /// Creates a new resource reference. /// - Parameters: /// - bundleID: The documentation bundle identifier for the bundle in which this resource resides. /// - path: The path of the resource local to its bundle. - init(bundleID: DocumentationBundle.Identifier, path: String) { + init(bundleID: DocumentationContext.Inputs.Identifier, path: String) { self.bundleID = bundleID self.path = path.removingPercentEncoding ?? path } diff --git a/Sources/SwiftDocC/Model/Rendering/DocumentationContentRenderer.swift b/Sources/SwiftDocC/Model/Rendering/DocumentationContentRenderer.swift index 2ad9f43a8b..6a27f929e9 100644 --- a/Sources/SwiftDocC/Model/Rendering/DocumentationContentRenderer.swift +++ b/Sources/SwiftDocC/Model/Rendering/DocumentationContentRenderer.swift @@ -48,17 +48,19 @@ extension RenderReferenceDependencies: Codable { public class DocumentationContentRenderer { let documentationContext: DocumentationContext - let bundle: DocumentationBundle let urlGenerator: PresentationURLGenerator - /// Creates a new content renderer for the given documentation context and bundle. + /// Creates a new content renderer for the given documentation context and inputs. /// - Parameters: /// - documentationContext: A documentation context. - /// - bundle: A documentation bundle. - public init(documentationContext: DocumentationContext, bundle: DocumentationBundle) { + public init(documentationContext: DocumentationContext) { self.documentationContext = documentationContext - self.bundle = bundle - self.urlGenerator = PresentationURLGenerator(context: documentationContext, baseURL: bundle.baseURL) + self.urlGenerator = PresentationURLGenerator(context: documentationContext, baseURL: documentationContext.inputs.baseURL) + } + + @available(*, deprecated, renamed: "init(documentationContext:)", message: "Use 'init(documentationContext:)' instead. This deprecated API will be removed after 6.3 is released") + public convenience init(documentationContext: DocumentationContext, bundle _: DocumentationBundle) { + self.init(documentationContext: documentationContext) } /// For symbol nodes, returns the declaration render section if any. @@ -324,7 +326,7 @@ public class DocumentationContentRenderer { // Topic render references require the URLs to be relative, even if they're external. let presentationURL = urlGenerator.presentationURLForReference(reference) - var contentCompiler = RenderContentCompiler(context: documentationContext, bundle: bundle, identifier: reference) + var contentCompiler = RenderContentCompiler(context: documentationContext, identifier: reference) let abstractContent: VariantCollection<[RenderInlineContent]> var abstractedNode = node @@ -516,7 +518,7 @@ public class DocumentationContentRenderer { } let supportedLanguages = group.directives[SupportedLanguage.directiveName]?.compactMap { - SupportedLanguage(from: $0, source: nil, for: bundle)?.language + SupportedLanguage(from: $0, source: nil, for: documentationContext.inputs)?.language } return ReferenceGroup( diff --git a/Sources/SwiftDocC/Model/Rendering/LinkTitleResolver.swift b/Sources/SwiftDocC/Model/Rendering/LinkTitleResolver.swift index 73f85a43f4..2aceb26ecf 100644 --- a/Sources/SwiftDocC/Model/Rendering/LinkTitleResolver.swift +++ b/Sources/SwiftDocC/Model/Rendering/LinkTitleResolver.swift @@ -31,11 +31,11 @@ struct LinkTitleResolver { var problems = [Problem]() switch directive.name { case Tutorial.directiveName: - if let tutorial = Tutorial(from: directive, source: source, for: context.bundle, problems: &problems) { + if let tutorial = Tutorial(from: directive, source: source, for: context.inputs, problems: &problems) { return .init(defaultVariantValue: tutorial.intro.title) } case TutorialTableOfContents.directiveName: - if let overview = TutorialTableOfContents(from: directive, source: source, for: context.bundle, problems: &problems) { + if let overview = TutorialTableOfContents(from: directive, source: source, for: context.inputs, problems: &problems) { return .init(defaultVariantValue: overview.name) } default: break diff --git a/Sources/SwiftDocC/Model/Rendering/Navigation Tree/RenderHierarchyTranslator.swift b/Sources/SwiftDocC/Model/Rendering/Navigation Tree/RenderHierarchyTranslator.swift index 25c6708333..9dc9716365 100644 --- a/Sources/SwiftDocC/Model/Rendering/Navigation Tree/RenderHierarchyTranslator.swift +++ b/Sources/SwiftDocC/Model/Rendering/Navigation Tree/RenderHierarchyTranslator.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -13,18 +13,14 @@ import Foundation /// A hierarchy translator that converts a part of the topic graph into a hierarchy tree. struct RenderHierarchyTranslator { var context: DocumentationContext - var bundle: DocumentationBundle var collectedTopicReferences = Set() var linkReferences = [String: LinkReference]() - /// Creates a new translator for the given bundle in the given context. - /// - Parameters: - /// - context: The documentation context for the conversion. - /// - bundle: The documentation bundle for the conversion. - init(context: DocumentationContext, bundle: DocumentationBundle) { + /// Creates a new translator for the given context. + /// - Parameter context: The documentation context for the conversion. + init(context: DocumentationContext) { self.context = context - self.bundle = bundle } static let assessmentsAnchor = urlReadableFragment(TutorialAssessmentsRenderSection.title) @@ -164,7 +160,7 @@ struct RenderHierarchyTranslator { let assessmentReference = ResolvedTopicReference(bundleID: tutorialReference.bundleID, path: tutorialReference.path, fragment: RenderHierarchyTranslator.assessmentsAnchor, sourceLanguage: .swift) renderHierarchyTutorial.landmarks.append(RenderHierarchyLandmark(reference: RenderReferenceIdentifier(assessmentReference.absoluteString), kind: .assessment)) - let urlGenerator = PresentationURLGenerator(context: context, baseURL: bundle.baseURL) + let urlGenerator = PresentationURLGenerator(context: context, baseURL: context.inputs.baseURL) let assessmentLinkReference = LinkReference( identifier: RenderReferenceIdentifier(assessmentReference.absoluteString), title: "Check Your Understanding", diff --git a/Sources/SwiftDocC/Model/Rendering/PresentationURLGenerator.swift b/Sources/SwiftDocC/Model/Rendering/PresentationURLGenerator.swift index b8333a03e8..9d33f00359 100644 --- a/Sources/SwiftDocC/Model/Rendering/PresentationURLGenerator.swift +++ b/Sources/SwiftDocC/Model/Rendering/PresentationURLGenerator.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -17,14 +17,14 @@ import SymbolKit public struct PresentationURLGenerator { /// The documentation context the URL generator queries for external reference resolvers. var context: DocumentationContext - /// The URL generator for in-bundle references. + /// The URL generator for local documentation references. let urlGenerator: NodeURLGenerator /// Creates a new URL generator. /// /// - Parameters: /// - context: The documentation context the URL generator will queries for external reference resolvers. - /// - baseURL: The base URL for in-bundle references. + /// - baseURL: The base URL for local documentation references. public init(context: DocumentationContext, baseURL: URL) { self.context = context self.urlGenerator = NodeURLGenerator(baseURL: baseURL) diff --git a/Sources/SwiftDocC/Model/Rendering/References/RenderReference.swift b/Sources/SwiftDocC/Model/Rendering/References/RenderReference.swift index 05daf761d1..35936801e4 100644 --- a/Sources/SwiftDocC/Model/Rendering/References/RenderReference.swift +++ b/Sources/SwiftDocC/Model/Rendering/References/RenderReference.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ public import Foundation /// A reference to a resource. /// -/// The reference can refer to a resource within a documentation bundle (e.g., another symbol) or an external resource (e.g., a web URL). +/// The reference can refer to a resource within a unit of documentation (e.g., another symbol) or an external resource (e.g., a web URL). /// Check the conforming types to browse the different kinds of references. public protocol RenderReference: Codable { /// The type of the reference. diff --git a/Sources/SwiftDocC/Model/Rendering/RenderContentCompiler.swift b/Sources/SwiftDocC/Model/Rendering/RenderContentCompiler.swift index 58fabccede..119a3d763c 100644 --- a/Sources/SwiftDocC/Model/Rendering/RenderContentCompiler.swift +++ b/Sources/SwiftDocC/Model/Rendering/RenderContentCompiler.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -20,7 +20,6 @@ extension RenderInlineContent: RenderContent {} struct RenderContentCompiler: MarkupVisitor { var context: DocumentationContext - var bundle: DocumentationBundle var identifier: ResolvedTopicReference var imageReferences: [String: ImageReference] = [:] var videoReferences: [String: VideoReference] = [:] @@ -28,9 +27,8 @@ struct RenderContentCompiler: MarkupVisitor { var collectedTopicReferences = GroupedSequence { $0.absoluteString } var linkReferences: [String: LinkReference] = [:] - init(context: DocumentationContext, bundle: DocumentationBundle, identifier: ResolvedTopicReference) { + init(context: DocumentationContext, identifier: ResolvedTopicReference) { self.context = context - self.bundle = bundle self.identifier = identifier } @@ -47,7 +45,7 @@ struct RenderContentCompiler: MarkupVisitor { mutating func visitCodeBlock(_ codeBlock: CodeBlock) -> [any RenderContent] { // Default to the bundle's code listing syntax if one is not explicitly declared in the code block. - return [RenderBlockContent.codeListing(.init(syntax: codeBlock.language ?? bundle.info.defaultCodeListingLanguage, code: codeBlock.code.splitByNewlines, metadata: nil))] + return [RenderBlockContent.codeListing(.init(syntax: codeBlock.language ?? context.inputs.info.defaultCodeListingLanguage, code: codeBlock.code.splitByNewlines, metadata: nil))] } mutating func visitHeading(_ heading: Heading) -> [any RenderContent] { diff --git a/Sources/SwiftDocC/Model/Rendering/RenderContentConvertible.swift b/Sources/SwiftDocC/Model/Rendering/RenderContentConvertible.swift index 6e7325c800..18e358d94c 100644 --- a/Sources/SwiftDocC/Model/Rendering/RenderContentConvertible.swift +++ b/Sources/SwiftDocC/Model/Rendering/RenderContentConvertible.swift @@ -24,7 +24,7 @@ extension RenderableDirectiveConvertible { _ blockDirective: BlockDirective, with contentCompiler: inout RenderContentCompiler ) -> [any RenderContent] { - guard let directive = Self.init(from: blockDirective, for: contentCompiler.bundle) else { + guard let directive = Self.init(from: blockDirective, for: contentCompiler.context.inputs) else { return [] } diff --git a/Sources/SwiftDocC/Model/Rendering/RenderContext.swift b/Sources/SwiftDocC/Model/Rendering/RenderContext.swift index dade49b7a0..8ab4cfd100 100644 --- a/Sources/SwiftDocC/Model/Rendering/RenderContext.swift +++ b/Sources/SwiftDocC/Model/Rendering/RenderContext.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -17,21 +17,22 @@ import SymbolKit /// converting nodes in bulk, i.e. when converting a complete documentation model for example. public struct RenderContext { let documentationContext: DocumentationContext - let bundle: DocumentationBundle let renderer: DocumentationContentRenderer /// Creates a new render context. /// - Warning: Creating a render context pre-renders all content that the context provides. - /// - Parameters: - /// - documentationContext: A documentation context. - /// - bundle: A documentation bundle. - public init(documentationContext: DocumentationContext, bundle: DocumentationBundle) { + /// - Parameter documentationContext: A documentation context. + public init(documentationContext: DocumentationContext) { self.documentationContext = documentationContext - self.bundle = bundle - self.renderer = DocumentationContentRenderer(documentationContext: documentationContext, bundle: bundle) + self.renderer = DocumentationContentRenderer(documentationContext: documentationContext) createRenderedContent() } + @available(*, deprecated, renamed: "init(documentationContext:)", message: "Use 'init(documentationContext:)' instead. This deprecated API will be removed after 6.3 is released") + public init(documentationContext: DocumentationContext, bundle _: DocumentationContext.Inputs) { + self.init(documentationContext: documentationContext) + } + /// The pre-rendered content per node reference. private(set) public var store = RenderReferenceStore() diff --git a/Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift b/Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift index 1fd747b15a..876cd5cd2e 100644 --- a/Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift +++ b/Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift @@ -22,7 +22,7 @@ public struct RenderNodeTranslator: SemanticVisitor { /// Resolved topic references that were seen by the visitor. These should be used to populate the references dictionary. var collectedTopicReferences: [ResolvedTopicReference] = [] - /// Unresolvable topic references outside the current bundle. + /// Unresolvable topic references outside the current unit of documentation. var collectedUnresolvedTopicReferences: [UnresolvedTopicReference] = [] /// Any collected constraints to symbol relationships. @@ -134,7 +134,7 @@ public struct RenderNodeTranslator: SemanticVisitor { public mutating func visitTutorial(_ tutorial: Tutorial) -> (any RenderTree)? { var node = RenderNode(identifier: identifier, kind: .tutorial) - var hierarchyTranslator = RenderHierarchyTranslator(context: context, bundle: bundle) + var hierarchyTranslator = RenderHierarchyTranslator(context: context) if let hierarchy = hierarchyTranslator.visitTutorialTableOfContentsNode(identifier) { let tutorialTableOfContents = try! context.entity(with: hierarchy.tutorialTableOfContents).semantic as! TutorialTableOfContents @@ -315,7 +315,7 @@ public struct RenderNodeTranslator: SemanticVisitor { // Visits a container and expects the elements to be block level elements public mutating func visitMarkupContainer(_ markupContainer: MarkupContainer) -> (any RenderTree)? { - var contentCompiler = RenderContentCompiler(context: context, bundle: bundle, identifier: identifier) + var contentCompiler = RenderContentCompiler(context: context, identifier: identifier) let content = markupContainer.elements.reduce(into: [], { result, item in result.append(contentsOf: contentCompiler.visit(item))}) as! [RenderBlockContent] collectedTopicReferences.append(contentsOf: contentCompiler.collectedTopicReferences) // Copy all the image references found in the markup container. @@ -327,7 +327,7 @@ public struct RenderNodeTranslator: SemanticVisitor { // Visits a collection of inline markup elements. public mutating func visitMarkup(_ markup: [any Markup]) -> (any RenderTree)? { - var contentCompiler = RenderContentCompiler(context: context, bundle: bundle, identifier: identifier) + var contentCompiler = RenderContentCompiler(context: context, identifier: identifier) let content = markup.reduce(into: [], { result, item in result.append(contentsOf: contentCompiler.visit(item))}) as! [RenderInlineContent] collectedTopicReferences.append(contentsOf: contentCompiler.collectedTopicReferences) // Copy all the image references. @@ -401,7 +401,7 @@ public struct RenderNodeTranslator: SemanticVisitor { node.sections.append(visitResources(resources) as! ResourcesRenderSection) } - var hierarchyTranslator = RenderHierarchyTranslator(context: context, bundle: bundle) + var hierarchyTranslator = RenderHierarchyTranslator(context: context) if let (hierarchyVariants, _) = hierarchyTranslator.visitTutorialTableOfContentsNode(identifier, omittingChapters: true) { node.hierarchyVariants = hierarchyVariants collectedTopicReferences.append(contentsOf: hierarchyTranslator.collectedTopicReferences) @@ -419,7 +419,7 @@ public struct RenderNodeTranslator: SemanticVisitor { private mutating func createTopicRenderReferences() -> [String: any RenderReference] { var renderReferences: [String: any RenderReference] = [:] - let renderer = DocumentationContentRenderer(documentationContext: context, bundle: bundle) + let renderer = DocumentationContentRenderer(documentationContext: context) for reference in collectedTopicReferences { var renderReference: TopicRenderReference @@ -530,7 +530,7 @@ public struct RenderNodeTranslator: SemanticVisitor { } public mutating func visitTutorialReference(_ tutorialReference: TutorialReference) -> (any RenderTree)? { - switch context.resolve(tutorialReference.topic, in: bundle.rootReference) { + switch context.resolve(tutorialReference.topic, in: context.inputs.rootReference) { case let .failure(reference, _): return RenderReferenceIdentifier(reference.topicURL.absoluteString) case let .success(resolved): @@ -600,7 +600,7 @@ public struct RenderNodeTranslator: SemanticVisitor { public mutating func visitArticle(_ article: Article) -> (any RenderTree)? { var node = RenderNode(identifier: identifier, kind: .article) // Contains symbol references declared in the Topics section. - var topicSectionContentCompiler = RenderContentCompiler(context: context, bundle: bundle, identifier: identifier) + var topicSectionContentCompiler = RenderContentCompiler(context: context, identifier: identifier) node.metadata.title = article.title!.plainText @@ -624,7 +624,7 @@ public struct RenderNodeTranslator: SemanticVisitor { let documentationNode = try! context.entity(with: identifier) - var hierarchyTranslator = RenderHierarchyTranslator(context: context, bundle: bundle) + var hierarchyTranslator = RenderHierarchyTranslator(context: context) let hierarchyVariants = hierarchyTranslator.visitArticle(identifier) collectedTopicReferences.append(contentsOf: hierarchyTranslator.collectedTopicReferences) node.hierarchyVariants = hierarchyVariants @@ -806,7 +806,6 @@ public struct RenderNodeTranslator: SemanticVisitor { for: documentationNode, withTraits: allowedTraits, context: context, - bundle: bundle, renderContext: renderContext, renderer: contentRenderer ) { @@ -878,7 +877,7 @@ public struct RenderNodeTranslator: SemanticVisitor { public mutating func visitTutorialArticle(_ article: TutorialArticle) -> (any RenderTree)? { var node = RenderNode(identifier: identifier, kind: .article) - var hierarchyTranslator = RenderHierarchyTranslator(context: context, bundle: bundle) + var hierarchyTranslator = RenderHierarchyTranslator(context: context) guard let hierarchy = hierarchyTranslator.visitTutorialTableOfContentsNode(identifier) else { // This tutorial article is not curated, so we don't generate a render node. // We've warned about this during semantic analysis. @@ -1029,7 +1028,7 @@ public struct RenderNodeTranslator: SemanticVisitor { ) -> [TaskGroupRenderSection] { return topics.taskGroups.compactMap { group in let supportedLanguages = group.directives[SupportedLanguage.directiveName]?.compactMap { - SupportedLanguage(from: $0, source: nil, for: bundle)?.language + SupportedLanguage(from: $0, source: nil, for: context.inputs)?.language } // If the task group has a set of supported languages, see if it should render for the allowed traits. @@ -1201,7 +1200,7 @@ public struct RenderNodeTranslator: SemanticVisitor { let identifier = identifier.addingSourceLanguages(documentationNode.availableSourceLanguages) var node = RenderNode(identifier: identifier, kind: .symbol) - var contentCompiler = RenderContentCompiler(context: context, bundle: bundle, identifier: identifier) + var contentCompiler = RenderContentCompiler(context: context, identifier: identifier) /* FIXME: We shouldn't be doing this kind of crawling here. @@ -1241,7 +1240,7 @@ public struct RenderNodeTranslator: SemanticVisitor { node.metadata.extendedModuleVariants = VariantCollection(from: symbol.extendedModuleVariants) - let defaultAvailability = defaultAvailability(for: bundle, moduleName: moduleName.symbolName, currentPlatforms: context.configuration.externalMetadata.currentPlatforms)? + let defaultAvailability = defaultAvailability(moduleName: moduleName.symbolName, currentPlatforms: context.configuration.externalMetadata.currentPlatforms)? .filter { $0.unconditionallyUnavailable != true } .sorted(by: AvailabilityRenderOrder.compare) @@ -1330,10 +1329,10 @@ public struct RenderNodeTranslator: SemanticVisitor { collectedTopicReferences.append(identifier) - let contentRenderer = DocumentationContentRenderer(documentationContext: context, bundle: bundle) + let contentRenderer = DocumentationContentRenderer(documentationContext: context) node.metadata.tags = contentRenderer.tags(for: identifier) - var hierarchyTranslator = RenderHierarchyTranslator(context: context, bundle: bundle) + var hierarchyTranslator = RenderHierarchyTranslator(context: context) let hierarchyVariants = hierarchyTranslator.visitSymbol(identifier) collectedTopicReferences.append(contentsOf: hierarchyTranslator.collectedTopicReferences) node.hierarchyVariants = hierarchyVariants @@ -1648,7 +1647,6 @@ public struct RenderNodeTranslator: SemanticVisitor { for: documentationNode, withTraits: allowedTraits, context: context, - bundle: bundle, renderContext: renderContext, renderer: contentRenderer ), !seeAlso.references.isEmpty { @@ -1774,7 +1772,6 @@ public struct RenderNodeTranslator: SemanticVisitor { } var context: DocumentationContext - var bundle: DocumentationBundle var identifier: ResolvedTopicReference var imageReferences: [String: ImageReference] = [:] var videoReferences: [String: VideoReference] = [:] @@ -1808,8 +1805,8 @@ public struct RenderNodeTranslator: SemanticVisitor { } /// The default availability for modules in a given bundle and module. - mutating func defaultAvailability(for bundle: DocumentationBundle, moduleName: String, currentPlatforms: [String: PlatformVersion]?) -> [AvailabilityRenderItem]? { - let identifier = BundleModuleIdentifier(bundle: bundle, moduleName: moduleName) + mutating func defaultAvailability(moduleName: String, currentPlatforms: [String: PlatformVersion]?) -> [AvailabilityRenderItem]? { + let identifier = BundleModuleIdentifier(inputs: context.inputs, moduleName: moduleName) // Cached availability if let availability = bundleAvailability[identifier] { @@ -1817,7 +1814,7 @@ public struct RenderNodeTranslator: SemanticVisitor { } // Find default module availability if existing - guard let bundleDefaultAvailability = bundle.info.defaultAvailability, + guard let bundleDefaultAvailability = context.inputs.info.defaultAvailability, let moduleAvailability = bundleDefaultAvailability.modules[moduleName] else { return nil } @@ -1851,7 +1848,7 @@ public struct RenderNodeTranslator: SemanticVisitor { } private func variants(for documentationNode: DocumentationNode) -> [RenderNode.Variant] { - let generator = PresentationURLGenerator(context: context, baseURL: bundle.baseURL) + let generator = PresentationURLGenerator(context: context, baseURL: context.inputs.baseURL) var allVariants: [SourceLanguage: ResolvedTopicReference] = documentationNode.availableSourceLanguages.reduce(into: [:]) { partialResult, language in partialResult[language] = identifier @@ -2002,7 +1999,6 @@ public struct RenderNodeTranslator: SemanticVisitor { init( context: DocumentationContext, - bundle: DocumentationBundle, identifier: ResolvedTopicReference, renderContext: RenderContext? = nil, emitSymbolSourceFileURIs: Bool = false, @@ -2011,10 +2007,9 @@ public struct RenderNodeTranslator: SemanticVisitor { symbolIdentifiersWithExpandedDocumentation: [String]? = nil ) { self.context = context - self.bundle = bundle self.identifier = identifier self.renderContext = renderContext - self.contentRenderer = DocumentationContentRenderer(documentationContext: context, bundle: bundle) + self.contentRenderer = DocumentationContentRenderer(documentationContext: context) self.shouldEmitSymbolSourceFileURIs = emitSymbolSourceFileURIs self.shouldEmitSymbolAccessLevels = emitSymbolAccessLevels self.sourceRepository = sourceRepository @@ -2025,8 +2020,8 @@ public struct RenderNodeTranslator: SemanticVisitor { fileprivate typealias BundleModuleIdentifier = String extension BundleModuleIdentifier { - fileprivate init(bundle: DocumentationBundle, moduleName: String) { - self = "\(bundle.id):\(moduleName)" + fileprivate init(inputs: DocumentationContext.Inputs, moduleName: String) { + self = "\(inputs.id):\(moduleName)" } } diff --git a/Sources/SwiftDocC/Model/Rendering/RenderReferenceStore.swift b/Sources/SwiftDocC/Model/Rendering/RenderReferenceStore.swift index d095303fc5..2b1a8eea25 100644 --- a/Sources/SwiftDocC/Model/Rendering/RenderReferenceStore.swift +++ b/Sources/SwiftDocC/Model/Rendering/RenderReferenceStore.swift @@ -38,7 +38,7 @@ public struct RenderReferenceStore: Codable { } /// Returns asset information for the given asset name. - public func content(forAssetNamed assetName: String, bundleID: DocumentationBundle.Identifier) -> DataAsset? { + public func content(forAssetNamed assetName: String, bundleID: DocumentationContext.Inputs.Identifier) -> DataAsset? { assets[AssetReference(assetName: assetName, bundleID: bundleID)] } } diff --git a/Sources/SwiftDocC/Semantics/Article/Article.swift b/Sources/SwiftDocC/Semantics/Article/Article.swift index aec17835f9..31cece3e1c 100644 --- a/Sources/SwiftDocC/Semantics/Article/Article.swift +++ b/Sources/SwiftDocC/Semantics/Article/Article.swift @@ -89,14 +89,14 @@ public final class Article: Semantic, MarkupConvertible, Abstracted, Redirected, /// Any automatically created task groups. var automaticTaskGroups: [AutomaticTaskGroupSection] - /// Initializes a new article with a given markup and source for a given documentation bundle and documentation context. + /// Initializes a new article with a given markup and source for a given documentation catalog. /// /// - Parameters: /// - markup: The markup that makes up this article's content. /// - source: The location of the file that this article's content comes from. - /// - bundle: The documentation bundle that the source file belongs to. + /// - inputs: The documentation catalog that the source file belongs to. /// - problems: A mutable collection of problems to update with any problem encountered while initializing the article. - public convenience init?(from markup: any Markup, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) { + public convenience init?(from markup: any Markup, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) { guard let title = markup.child(at: 0) as? Heading, title.level == 1 else { let range = markup.child(at: 0)?.range ?? SourceLocation(line: 1, column: 1, source: nil)..(severityIfFound: .warning, allowedArguments: [Semantics.Title.argumentName, Semantics.Layout.argumentName, Semantics.Eyebrow.argumentName]).analyze(directive, children: directive.children, source: source, problems: &problems) Semantic.Analyses.HasOnlyKnownDirectives(severityIfFound: .warning, allowedDirectives: [ImageMedia.directiveName, VideoMedia.directiveName]).analyze(directive, children: directive.children, source: source, problems: &problems) @@ -85,7 +85,7 @@ public final class ContentAndMedia: Semantic, DirectiveConvertible { let layout = Semantic.Analyses.DeprecatedArgument.unused(severityIfFound: .warning).analyze(directive, arguments: arguments, problems: &problems) - let (media, remainder) = Semantic.Analyses.HasExactlyOneMedia(severityIfNotFound: nil).analyze(directive, children: directive.children, source: source, for: bundle, problems: &problems) + let (media, remainder) = Semantic.Analyses.HasExactlyOneMedia(severityIfNotFound: nil).analyze(directive, children: directive.children, source: source, for: inputs, problems: &problems) let mediaPosition: MediaPosition if let firstChildDirective = directive.child(at: 0) as? BlockDirective, diff --git a/Sources/SwiftDocC/Semantics/DirectiveConvertable.swift b/Sources/SwiftDocC/Semantics/DirectiveConvertable.swift index fb2d4d6f9d..fb98e907af 100644 --- a/Sources/SwiftDocC/Semantics/DirectiveConvertable.swift +++ b/Sources/SwiftDocC/Semantics/DirectiveConvertable.swift @@ -34,9 +34,9 @@ public protocol DirectiveConvertible { /// - Parameters: /// - directive: The parsed block directive to create a semantic object from. /// - source: The location of the source file that contains the markup for the parsed block directive. - /// - bundle: The documentation bundle that the source file belongs to. + /// - inputs: The documentation bundle that the source file belongs to. /// - problems: An inout array of ``Problem`` to be collected for later diagnostic reporting. - init?(from directive: BlockDirective, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) + init?(from directive: BlockDirective, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) /// Returns a Boolean value indicating whether the `DirectiveConvertible` recognizes the given directive. /// diff --git a/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/AutomaticDirectiveConvertible.swift b/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/AutomaticDirectiveConvertible.swift index bfd1ab53de..99922cc826 100644 --- a/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/AutomaticDirectiveConvertible.swift +++ b/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/AutomaticDirectiveConvertible.swift @@ -92,21 +92,20 @@ extension AutomaticDirectiveConvertible { /// the same function but supports collecting an array of problems for diagnostics. /// /// - Parameters: - /// - directive: The block directive that will be parsed - /// - source: An optional URL for the source location where this directive is written. - /// - bundle: The documentation bundle that owns the directive. - /// - context: The documentation context in which the bundle resides. + /// - directive: The block directive that will be parsed + /// - source: An optional URL for the source location where this directive is written. + /// - inputs: The collection of inputs files that the directive originates from. public init?( from directive: BlockDirective, source: URL? = nil, - for bundle: DocumentationBundle + for inputs: DocumentationContext.Inputs ) { var problems = [Problem]() self.init( from: directive, source: source, - for: bundle, + for: inputs, problems: &problems ) } @@ -114,7 +113,7 @@ extension AutomaticDirectiveConvertible { public init?( from directive: BlockDirective, source: URL?, - for bundle: DocumentationBundle, + for inputs: DocumentationContext.Inputs, problems: inout [Problem] ) { precondition(directive.name == Self.directiveName) @@ -144,7 +143,7 @@ extension AutomaticDirectiveConvertible { allowedValues: reflectedArgument.allowedValues, expectedFormat: reflectedArgument.expectedFormat, convert: { argumentValue in - return reflectedArgument.parseArgument(bundle, argumentValue) + return reflectedArgument.parseArgument(inputs, argumentValue) }, valueTypeDiagnosticName: reflectedArgument.typeDisplayName ) @@ -177,7 +176,7 @@ extension AutomaticDirectiveConvertible { childType: Comment.self, children: remainder, source: source, - for: bundle, + for: inputs, problems: &problems ) @@ -190,7 +189,7 @@ extension AutomaticDirectiveConvertible { parentDirective: directive, children: remainder, source: source, - for: bundle, + for: inputs, problems: &problems ) @@ -214,7 +213,7 @@ extension AutomaticDirectiveConvertible { parentDirective: directive, children: remainder, source: source, - for: bundle, + for: inputs, problems: &problems ) @@ -237,7 +236,7 @@ extension AutomaticDirectiveConvertible { childType: childDirective.type, children: remainder, source: source, - for: bundle, + for: inputs, problems: &problems ) @@ -251,7 +250,7 @@ extension AutomaticDirectiveConvertible { parentDirective: directive, children: remainder, source: source, - for: bundle, + for: inputs, problems: &problems ) diff --git a/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/DirectiveArgumentWrapper.swift b/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/DirectiveArgumentWrapper.swift index 83639012ac..e55a1087fe 100644 --- a/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/DirectiveArgumentWrapper.swift +++ b/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/DirectiveArgumentWrapper.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2022-2023 Apple Inc. and the Swift project authors + Copyright (c) 2022-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -19,7 +19,7 @@ protocol _DirectiveArgumentProtocol { var expectedFormat: String? { get } var hiddenFromDocumentation: Bool { get } - var parseArgument: (_ bundle: DocumentationBundle, _ argumentValue: String) -> (Any?) { get } + var parseArgument: (_ inputs: DocumentationContext.Inputs, _ argumentValue: String) -> (Any?) { get } func setProperty( on containingDirective: some AutomaticDirectiveConvertible, @@ -68,7 +68,7 @@ public struct DirectiveArgumentWrapped: _DirectiveArgumentProtocol { let expectedFormat: String? let hiddenFromDocumentation: Bool - let parseArgument: (_ bundle: DocumentationBundle, _ argumentValue: String) -> (Any?) + let parseArgument: (_ bundle: DocumentationContext.Inputs, _ argumentValue: String) -> (Any?) let defaultValue: Value? var storedAsOptional: Bool { @@ -99,7 +99,7 @@ public struct DirectiveArgumentWrapped: _DirectiveArgumentProtocol { init( wrappedValue: Value, name: _DirectiveArgumentName = .inferredFromPropertyName, - parseArgument: @escaping (_ bundle: DocumentationBundle, _ argumentValue: String) -> (Value?), + parseArgument: @escaping (_ bundle: DocumentationContext.Inputs, _ argumentValue: String) -> (Value?), allowedValues: [String]? = nil, expectedFormat: String? = nil, hiddenFromDocumentation: Bool = false @@ -118,7 +118,7 @@ public struct DirectiveArgumentWrapped: _DirectiveArgumentProtocol { @_disfavoredOverload init( name: _DirectiveArgumentName = .inferredFromPropertyName, - parseArgument: @escaping (_ bundle: DocumentationBundle, _ argumentValue: String) -> (Value?), + parseArgument: @escaping (_ bundle: DocumentationContext.Inputs, _ argumentValue: String) -> (Value?), allowedValues: [String]? = nil, expectedFormat: String? = nil, hiddenFromDocumentation: Bool = false @@ -137,7 +137,7 @@ public struct DirectiveArgumentWrapped: _DirectiveArgumentProtocol { private init( value: Value?, name: _DirectiveArgumentName, - transform: @escaping (_ bundle: DocumentationBundle, _ argumentValue: String) -> (Value?), + transform: @escaping (_ bundle: DocumentationContext.Inputs, _ argumentValue: String) -> (Value?), allowedValues: [String]?, expectedFormat: String?, required: Bool?, @@ -325,7 +325,7 @@ extension DirectiveArgumentWrapped where Value: _OptionalDirectiveArgument { @_disfavoredOverload init( name: _DirectiveArgumentName = .inferredFromPropertyName, - parseArgument: @escaping (_ bundle: DocumentationBundle, _ argumentValue: String) -> (Value?), + parseArgument: @escaping (_ bundle: DocumentationContext.Inputs, _ argumentValue: String) -> (Value?), allowedValues: [String]? = nil, hiddenFromDocumentation: Bool = false ) { @@ -336,7 +336,7 @@ extension DirectiveArgumentWrapped where Value: _OptionalDirectiveArgument { init( wrappedValue: Value, name: _DirectiveArgumentName = .inferredFromPropertyName, - parseArgument: @escaping (_ bundle: DocumentationBundle, _ argumentValue: String) -> (Value?), + parseArgument: @escaping (_ bundle: DocumentationContext.Inputs, _ argumentValue: String) -> (Value?), allowedValues: [String]? = nil, hiddenFromDocumentation: Bool = false ) { @@ -346,7 +346,7 @@ extension DirectiveArgumentWrapped where Value: _OptionalDirectiveArgument { private init( value: Value?, name: _DirectiveArgumentName, - parseArgument: @escaping (_ bundle: DocumentationBundle, _ argumentValue: String) -> (Value?), + parseArgument: @escaping (_ bundle: DocumentationContext.Inputs, _ argumentValue: String) -> (Value?), allowedValues: [String]? = nil, expectedFormat: String? = nil, hiddenFromDocumentation: Bool = false diff --git a/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/DirectiveMirror.swift b/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/DirectiveMirror.swift index fcc8856aa5..269ac213be 100644 --- a/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/DirectiveMirror.swift +++ b/Sources/SwiftDocC/Semantics/DirectiveInfrastructure/DirectiveMirror.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2022-2023 Apple Inc. and the Swift project authors + Copyright (c) 2022-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -172,7 +172,7 @@ extension DirectiveMirror { let propertyLabel: String let argument: any _DirectiveArgumentProtocol - let parseArgument: (_ bundle: DocumentationBundle, _ argumentValue: String) -> (Any?) + let parseArgument: (_ inputs: DocumentationContext.Inputs, _ argumentValue: String) -> (Any?) func setValue( on containingDirective: some AutomaticDirectiveConvertible, diff --git a/Sources/SwiftDocC/Semantics/DirectiveParser.swift b/Sources/SwiftDocC/Semantics/DirectiveParser.swift index 95d38624ca..dfe4bcee54 100644 --- a/Sources/SwiftDocC/Semantics/DirectiveParser.swift +++ b/Sources/SwiftDocC/Semantics/DirectiveParser.swift @@ -23,7 +23,7 @@ struct DirectiveParser { from markupElements: inout [any Markup], parentType: Semantic.Type, source: URL?, - bundle: DocumentationBundle, + inputs: DocumentationContext.Inputs, problems: inout [Problem] ) -> Directive? { let (directiveElements, remainder) = markupElements.categorize { markup -> Directive? in @@ -35,7 +35,7 @@ struct DirectiveParser { return Directive( from: childDirective, source: source, - for: bundle, + for: inputs, problems: &problems ) } diff --git a/Sources/SwiftDocC/Semantics/ExternalLinks/ExternalMarkupReferenceWalker.swift b/Sources/SwiftDocC/Semantics/ExternalLinks/ExternalMarkupReferenceWalker.swift index 69502f34f8..3ba0acede4 100644 --- a/Sources/SwiftDocC/Semantics/ExternalLinks/ExternalMarkupReferenceWalker.swift +++ b/Sources/SwiftDocC/Semantics/ExternalLinks/ExternalMarkupReferenceWalker.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -14,10 +14,10 @@ import Markdown /// Walks a markup tree and collects any links external to a given bundle. struct ExternalMarkupReferenceWalker: MarkupVisitor { /// The local bundle ID, used to identify and skip absolute fully qualified local links. - var localBundleID: DocumentationBundle.Identifier + var localBundleID: DocumentationContext.Inputs.Identifier /// After walking a markup tree, all encountered external links are collected grouped by the bundle ID. - var collectedExternalLinks = [DocumentationBundle.Identifier: Set]() + var collectedExternalLinks = [DocumentationContext.Inputs.Identifier: Set]() /// Descends down the given elements' children. mutating func defaultVisit(_ markup: any Markup) { @@ -31,7 +31,7 @@ struct ExternalMarkupReferenceWalker: MarkupVisitor { // Only process documentation links to external bundles guard let destination = link.destination, let url = ValidatedURL(parsingAuthoredLink: destination)?.requiring(scheme: ResolvedTopicReference.urlScheme), - let bundleID = url.components.host.map({ DocumentationBundle.Identifier(rawValue: $0) }), + let bundleID = url.components.host.map({ DocumentationContext.Inputs.Identifier(rawValue: $0) }), bundleID != localBundleID else { return diff --git a/Sources/SwiftDocC/Semantics/ExternalLinks/ExternalReferenceWalker.swift b/Sources/SwiftDocC/Semantics/ExternalLinks/ExternalReferenceWalker.swift index b1f2021f4a..2cfa68e837 100644 --- a/Sources/SwiftDocC/Semantics/ExternalLinks/ExternalReferenceWalker.swift +++ b/Sources/SwiftDocC/Semantics/ExternalLinks/ExternalReferenceWalker.swift @@ -41,7 +41,7 @@ struct ExternalReferenceWalker: SemanticVisitor { private var markupResolver: ExternalMarkupReferenceWalker /// Collected unresolved external references, grouped by the bundle ID. - var collectedExternalReferences: [DocumentationBundle.Identifier: [UnresolvedTopicReference]] { + var collectedExternalReferences: [DocumentationContext.Inputs.Identifier: [UnresolvedTopicReference]] { return markupResolver.collectedExternalLinks.mapValues { links in links.map(UnresolvedTopicReference.init(topicURL:)) } @@ -49,7 +49,7 @@ struct ExternalReferenceWalker: SemanticVisitor { /// Creates a new semantic walker that collects links to other documentation sources. /// - Parameter localBundleID: The local bundle ID, used to identify and skip absolute fully qualified local links. - init(localBundleID: DocumentationBundle.Identifier) { + init(localBundleID: DocumentationContext.Inputs.Identifier) { self.markupResolver = ExternalMarkupReferenceWalker(localBundleID: localBundleID) } diff --git a/Sources/SwiftDocC/Semantics/General Purpose Analyses/Extract.swift b/Sources/SwiftDocC/Semantics/General Purpose Analyses/Extract.swift index 38b3611ea0..0e521e4a20 100644 --- a/Sources/SwiftDocC/Semantics/General Purpose Analyses/Extract.swift +++ b/Sources/SwiftDocC/Semantics/General Purpose Analyses/Extract.swift @@ -18,12 +18,12 @@ extension Semantic.Analyses { public struct ExtractAll { public init() {} - public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) -> ([Child], remainder: MarkupContainer) { + public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) -> ([Child], remainder: MarkupContainer) { return Semantic.Analyses.extractAll( childType: Child.self, children: children, source: source, - for: bundle, + for: inputs, problems: &problems ) as! ([Child], MarkupContainer) } @@ -33,7 +33,7 @@ extension Semantic.Analyses { childType: any DirectiveConvertible.Type, children: some Sequence, source: URL?, - for bundle: DocumentationBundle, + for inputs: DocumentationContext.Inputs, problems: inout [Problem] ) -> ([any DirectiveConvertible], remainder: MarkupContainer) { let (candidates, remainder) = children.categorize { child -> BlockDirective? in @@ -44,7 +44,7 @@ extension Semantic.Analyses { return childDirective } let converted = candidates.compactMap { - childType.init(from: $0, source: source, for: bundle, problems: &problems) + childType.init(from: $0, source: source, for: inputs, problems: &problems) } return (converted, remainder: MarkupContainer(remainder)) } diff --git a/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasAtLeastOne.swift b/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasAtLeastOne.swift index 7c8172f0d1..57fa7e3fc6 100644 --- a/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasAtLeastOne.swift +++ b/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasAtLeastOne.swift @@ -25,7 +25,7 @@ extension Semantic.Analyses { _ directive: BlockDirective, children: some Sequence, source: URL?, - for bundle: DocumentationBundle, + for inputs: DocumentationContext.Inputs, problems: inout [Problem] ) -> ([Child], remainder: MarkupContainer) { Semantic.Analyses.extractAtLeastOne( @@ -33,7 +33,7 @@ extension Semantic.Analyses { parentDirective: directive, children: children, source: source, - for: bundle, + for: inputs, severityIfNotFound: severityIfNotFound, problems: &problems ) as! ([Child], MarkupContainer) @@ -45,7 +45,7 @@ extension Semantic.Analyses { parentDirective: BlockDirective, children: some Sequence, source: URL?, - for bundle: DocumentationBundle, + for inputs: DocumentationContext.Inputs, severityIfNotFound: DiagnosticSeverity? = .warning, problems: inout [Problem] ) -> ([any DirectiveConvertible], remainder: MarkupContainer) { @@ -79,7 +79,7 @@ extension Semantic.Analyses { return childType.init( from: childDirective, source: source, - for: bundle, + for: inputs, problems: &problems ) } diff --git a/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasAtMostOne.swift b/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasAtMostOne.swift index 93765fd5d3..bc9a4beb8d 100644 --- a/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasAtMostOne.swift +++ b/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasAtMostOne.swift @@ -16,13 +16,13 @@ extension Semantic.Analyses { Checks to see if a parent directive has at most one child directive of a specified type. If so, return that child and the remainder. */ public struct HasAtMostOne { - public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) -> (Child?, remainder: MarkupContainer) { + public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) -> (Child?, remainder: MarkupContainer) { return Semantic.Analyses.extractAtMostOne( childType: Child.self, parentDirective: directive, children: children, source: source, - for: bundle, + for: inputs, problems: &problems ) as! (Child?, MarkupContainer) } @@ -33,7 +33,7 @@ extension Semantic.Analyses { parentDirective: BlockDirective, children: some Sequence, source: URL?, - for bundle: DocumentationBundle, + for inputs: DocumentationContext.Inputs, severityIfNotFound: DiagnosticSeverity = .warning, problems: inout [Problem] ) -> ((any DirectiveConvertible)?, remainder: MarkupContainer) { @@ -67,7 +67,7 @@ extension Semantic.Analyses { problems.append(Problem(diagnostic: diagnostic, possibleSolutions: [])) } - return (childType.init(from: match, source: source, for: bundle, problems: &problems), MarkupContainer(remainder)) + return (childType.init(from: match, source: source, for: inputs, problems: &problems), MarkupContainer(remainder)) } } diff --git a/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasExactlyOne.swift b/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasExactlyOne.swift index aa05a6dd63..9f90e0172c 100644 --- a/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasExactlyOne.swift +++ b/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasExactlyOne.swift @@ -21,13 +21,13 @@ extension Semantic.Analyses { self.severityIfNotFound = severityIfNotFound } - public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) -> (Child?, remainder: MarkupContainer) { + public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) -> (Child?, remainder: MarkupContainer) { return Semantic.Analyses.extractExactlyOne( childType: Child.self, parentDirective: directive, children: children, source: source, - for: bundle, + for: inputs, severityIfNotFound: severityIfNotFound, problems: &problems ) as! (Child?, MarkupContainer) @@ -39,7 +39,7 @@ extension Semantic.Analyses { parentDirective: BlockDirective, children: some Sequence, source: URL?, - for bundle: DocumentationBundle, + for inputs: DocumentationContext.Inputs, severityIfNotFound: DiagnosticSeverity? = .warning, problems: inout [Problem] ) -> ((any DirectiveConvertible)?, remainder: MarkupContainer) { @@ -89,7 +89,7 @@ extension Semantic.Analyses { } } - return (childType.init(from: candidate, source: source, for: bundle, problems: &problems), MarkupContainer(remainder)) + return (childType.init(from: candidate, source: source, for: inputs, problems: &problems), MarkupContainer(remainder)) } /// Checks a parent directive for the presence of exactly one of two child directives---but not both---to be converted to a type ``SemanticAnalysis/Result``. If so, return that child and the remainder. @@ -99,7 +99,7 @@ extension Semantic.Analyses { self.severityIfNotFound = severityIfNotFound } - public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) -> (Child1?, Child2?, remainder: MarkupContainer) { + public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for bundle: DocumentationContext.Inputs, problems: inout [Problem]) -> (Child1?, Child2?, remainder: MarkupContainer) { let (candidates, remainder) = children.categorize { child -> BlockDirective? in guard let childDirective = child as? BlockDirective else { return nil @@ -149,7 +149,7 @@ extension Semantic.Analyses { self.severityIfNotFound = severityIfNotFound } - public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) -> ((any Media)?, remainder: MarkupContainer) { + public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for bundle: DocumentationContext.Inputs, problems: inout [Problem]) -> ((any Media)?, remainder: MarkupContainer) { let (foundImage, foundVideo, remainder) = HasExactlyOneOf(severityIfNotFound: severityIfNotFound).analyze(directive, children: children, source: source, for: bundle, problems: &problems) return (foundImage ?? foundVideo, remainder) } @@ -162,7 +162,7 @@ extension Semantic.Analyses { self.severityIfNotFound = severityIfNotFound } - public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) -> ((any Media)?, remainder: MarkupContainer) { + public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for bundle: DocumentationContext.Inputs, problems: inout [Problem]) -> ((any Media)?, remainder: MarkupContainer) { let (mediaDirectives, remainder) = children.categorize { child -> BlockDirective? in guard let childDirective = child as? BlockDirective else { return nil diff --git a/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasOnlySequentialHeadings.swift b/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasOnlySequentialHeadings.swift index b7515b4efa..d48c41e609 100644 --- a/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasOnlySequentialHeadings.swift +++ b/Sources/SwiftDocC/Semantics/General Purpose Analyses/HasOnlySequentialHeadings.swift @@ -36,7 +36,7 @@ extension Semantic.Analyses { } /// Returns all valid headings. - @discardableResult public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for _: DocumentationBundle, problems: inout [Problem]) -> [Heading] { + @discardableResult public func analyze(_ directive: BlockDirective, children: some Sequence, source: URL?, for _: DocumentationContext.Inputs, problems: inout [Problem]) -> [Heading] { var currentHeadingLevel = startingFromLevel var headings: [Heading] = [] for case let child as Heading in children { diff --git a/Sources/SwiftDocC/Semantics/MarkupReferenceResolver.swift b/Sources/SwiftDocC/Semantics/MarkupReferenceResolver.swift index 8f34a30d46..2a273db1c9 100644 --- a/Sources/SwiftDocC/Semantics/MarkupReferenceResolver.swift +++ b/Sources/SwiftDocC/Semantics/MarkupReferenceResolver.swift @@ -44,13 +44,11 @@ private func removedLinkDestinationProblem(reference: ResolvedTopicReference, ra */ struct MarkupReferenceResolver: MarkupRewriter { var context: DocumentationContext - var bundle: DocumentationBundle var problems = [Problem]() var rootReference: ResolvedTopicReference - init(context: DocumentationContext, bundle: DocumentationBundle, rootReference: ResolvedTopicReference) { + init(context: DocumentationContext, rootReference: ResolvedTopicReference) { self.context = context - self.bundle = bundle self.rootReference = rootReference } @@ -84,14 +82,14 @@ struct MarkupReferenceResolver: MarkupRewriter { return nil } - let uncuratedArticleMatch = context.uncuratedArticles[bundle.articlesDocumentationRootReference.appendingPathOfReference(unresolved)]?.source + let uncuratedArticleMatch = context.uncuratedArticles[context.inputs.articlesDocumentationRootReference.appendingPathOfReference(unresolved)]?.source problems.append(unresolvedReferenceProblem(source: range?.source, range: range, severity: severity, uncuratedArticleMatch: uncuratedArticleMatch, errorInfo: error, fromSymbolLink: fromSymbolLink)) return nil } } mutating func visitImage(_ image: Image) -> (any Markup)? { - if let reference = image.reference(in: bundle), !context.resourceExists(with: reference) { + if let reference = image.reference(in: context.inputs), !context.resourceExists(with: reference) { problems.append(unresolvedResourceProblem(resource: reference, source: image.range?.source, range: image.range, severity: .warning)) } @@ -172,7 +170,7 @@ struct MarkupReferenceResolver: MarkupRewriter { switch blockDirective.name { case Snippet.directiveName: var problems = [Problem]() - guard let snippet = Snippet(from: blockDirective, source: source, for: bundle, problems: &problems) else { + guard let snippet = Snippet(from: blockDirective, source: source, for: context.inputs, problems: &problems) else { return blockDirective } @@ -192,7 +190,7 @@ struct MarkupReferenceResolver: MarkupRewriter { return blockDirective } case ImageMedia.directiveName: - guard let imageMedia = ImageMedia(from: blockDirective, source: source, for: bundle) else { + guard let imageMedia = ImageMedia(from: blockDirective, source: source, for: context.inputs) else { return blockDirective } @@ -210,7 +208,7 @@ struct MarkupReferenceResolver: MarkupRewriter { return blockDirective case VideoMedia.directiveName: - guard let videoMedia = VideoMedia(from: blockDirective, source: source, for: bundle) else { + guard let videoMedia = VideoMedia(from: blockDirective, source: source, for: context.inputs) else { return blockDirective } diff --git a/Sources/SwiftDocC/Semantics/Metadata/CallToAction.swift b/Sources/SwiftDocC/Semantics/Metadata/CallToAction.swift index 569bf8c81e..b550f95cf7 100644 --- a/Sources/SwiftDocC/Semantics/Metadata/CallToAction.swift +++ b/Sources/SwiftDocC/Semantics/Metadata/CallToAction.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2022-2023 Apple Inc. and the Swift project authors + Copyright (c) 2022-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -57,10 +57,10 @@ public final class CallToAction: Semantic, AutomaticDirectiveConvertible { @DirectiveArgumentWrapped public var url: URL? = nil - /// The location of the associated link, as a reference to a file in this documentation bundle. + /// The location of the associated link, as a reference to a file in this documentation catalog. @DirectiveArgumentWrapped( - parseArgument: { bundle, argumentValue in - ResourceReference(bundleID: bundle.id, path: argumentValue) + parseArgument: { inputs, argumentValue in + ResourceReference(bundleID: inputs.id, path: argumentValue) } ) public var file: ResourceReference? = nil @@ -149,13 +149,9 @@ public final class CallToAction: Semantic, AutomaticDirectiveConvertible { } extension CallToAction { - func resolveFile( - for bundle: DocumentationBundle, - in context: DocumentationContext, - problems: inout [Problem]) -> ResourceReference? - { + func resolveFile(in context: DocumentationContext, problems: inout [Problem]) -> ResourceReference? { if let file = self.file { - if context.resolveAsset(named: file.url.lastPathComponent, in: bundle.rootReference) == nil { + if context.resolveAsset(named: file.url.lastPathComponent, in: context.inputs.rootReference) == nil { problems.append(.init( diagnostic: Diagnostic( source: url, diff --git a/Sources/SwiftDocC/Semantics/ReferenceResolver.swift b/Sources/SwiftDocC/Semantics/ReferenceResolver.swift index 2bb44a90ec..ce06808210 100644 --- a/Sources/SwiftDocC/Semantics/ReferenceResolver.swift +++ b/Sources/SwiftDocC/Semantics/ReferenceResolver.swift @@ -95,9 +95,6 @@ struct ReferenceResolver: SemanticVisitor { /// The context to use to resolve references. var context: DocumentationContext - /// The bundle in which visited documents reside. - var bundle: DocumentationBundle - /// Problems found while trying to resolve references. var problems = [Problem]() @@ -106,10 +103,9 @@ struct ReferenceResolver: SemanticVisitor { /// If the documentation is inherited, the reference of the parent symbol. var inheritanceParentReference: ResolvedTopicReference? - init(context: DocumentationContext, bundle: DocumentationBundle, rootReference: ResolvedTopicReference? = nil, inheritanceParentReference: ResolvedTopicReference? = nil) { + init(context: DocumentationContext, rootReference: ResolvedTopicReference? = nil, inheritanceParentReference: ResolvedTopicReference? = nil) { self.context = context - self.bundle = bundle - self.rootReference = rootReference ?? bundle.rootReference + self.rootReference = rootReference ?? context.inputs.rootReference self.inheritanceParentReference = inheritanceParentReference } @@ -119,7 +115,7 @@ struct ReferenceResolver: SemanticVisitor { return .success(resolved) case let .failure(unresolved, error): - let uncuratedArticleMatch = context.uncuratedArticles[bundle.documentationRootReference.appendingPathOfReference(unresolved)]?.source + let uncuratedArticleMatch = context.uncuratedArticles[context.inputs.documentationRootReference.appendingPathOfReference(unresolved)]?.source problems.append(unresolvedReferenceProblem(source: range?.source, range: range, severity: severity, uncuratedArticleMatch: uncuratedArticleMatch, errorInfo: error, fromSymbolLink: false)) return .failure(unresolved, error) } @@ -172,9 +168,9 @@ struct ReferenceResolver: SemanticVisitor { // Change the context of the project file to `download` if let projectFiles = tutorial.projectFiles, - var resolvedDownload = context.resolveAsset(named: projectFiles.path, in: bundle.rootReference) { + var resolvedDownload = context.resolveAsset(named: projectFiles.path, in: rootReference) { resolvedDownload.context = .download - context.updateAsset(named: projectFiles.path, asset: resolvedDownload, in: bundle.rootReference) + context.updateAsset(named: projectFiles.path, asset: resolvedDownload, in: rootReference) } return Tutorial(originalMarkup: tutorial.originalMarkup, durationMinutes: tutorial.durationMinutes, projectFiles: tutorial.projectFiles, requirements: newRequirements, intro: newIntro, sections: newSections, assessments: newAssessments, callToActionImage: newCallToActionImage, redirects: tutorial.redirects) @@ -215,7 +211,7 @@ struct ReferenceResolver: SemanticVisitor { } mutating func visitMarkupContainer(_ markupContainer: MarkupContainer) -> Semantic { - var markupResolver = MarkupReferenceResolver(context: context, bundle: bundle, rootReference: rootReference) + var markupResolver = MarkupReferenceResolver(context: context, rootReference: rootReference) let parent = inheritanceParentReference let context = self.context @@ -315,7 +311,7 @@ struct ReferenceResolver: SemanticVisitor { // i.e. doc:/${SOME_TECHNOLOGY}/${PROJECT} or doc://${BUNDLE_ID}/${SOME_TECHNOLOGY}/${PROJECT} switch tutorialReference.topic { case .unresolved: - let maybeResolved = resolve(tutorialReference.topic, in: bundle.tutorialsContainerReference, + let maybeResolved = resolve(tutorialReference.topic, in: context.inputs.tutorialsContainerReference, range: tutorialReference.originalMarkup.range, severity: .warning) return TutorialReference(originalMarkup: tutorialReference.originalMarkup, tutorial: .resolved(maybeResolved)) @@ -369,10 +365,10 @@ struct ReferenceResolver: SemanticVisitor { visitMarkupContainer($0) as? MarkupContainer } // If there's a call to action with a local-file reference, change its context to `download` - if let downloadFile = article.metadata?.callToAction?.resolveFile(for: bundle, in: context, problems: &problems), - var resolvedDownload = context.resolveAsset(named: downloadFile.path, in: bundle.rootReference) { + if let downloadFile = article.metadata?.callToAction?.resolveFile(in: context, problems: &problems), + var resolvedDownload = context.resolveAsset(named: downloadFile.path, in: rootReference) { resolvedDownload.context = .download - context.updateAsset(named: downloadFile.path, asset: resolvedDownload, in: bundle.rootReference) + context.updateAsset(named: downloadFile.path, asset: resolvedDownload, in: rootReference) } return Article( @@ -543,15 +539,15 @@ fileprivate extension URL { } extension Image { - func reference(in bundle: DocumentationBundle) -> ResourceReference? { + func reference(in inputs: DocumentationContext.Inputs) -> ResourceReference? { guard let source else { - return ResourceReference(bundleID: bundle.id, path: "") + return ResourceReference(bundleID: inputs.id, path: "") } if let url = URL(string: source), url.isLikelyWebURL { return nil } else { - return ResourceReference(bundleID: bundle.id, path: source) + return ResourceReference(bundleID: inputs.id, path: source) } } } diff --git a/Sources/SwiftDocC/Semantics/SemanticAnalyzer.swift b/Sources/SwiftDocC/Semantics/SemanticAnalyzer.swift index 7af7e5999a..27cb006478 100644 --- a/Sources/SwiftDocC/Semantics/SemanticAnalyzer.swift +++ b/Sources/SwiftDocC/Semantics/SemanticAnalyzer.swift @@ -14,11 +14,11 @@ import Markdown struct SemanticAnalyzer: MarkupVisitor { var problems = [Problem]() let source: URL? - let bundle: DocumentationBundle + let inputs: DocumentationContext.Inputs - init(source: URL?, bundle: DocumentationBundle) { + init(source: URL?, inputs: DocumentationContext.Inputs) { self.source = source - self.bundle = bundle + self.inputs = inputs } private mutating func analyzeChildren(of markup: any Markup) -> [Semantic] { @@ -51,13 +51,13 @@ struct SemanticAnalyzer: MarkupVisitor { .list(finalConjunction: .or) if let source { - if !topLevelChildren.isEmpty, !DocumentationBundleFileTypes.isTutorialFile(source) { + if !topLevelChildren.isEmpty, !DocumentationInputFileTypes.isTutorialFile(source) { // Only tutorials support top level directives. This document has top level directives but is not a tutorial file. let directiveName = type(of: topLevelChildren.first! as! (any DirectiveConvertible)).directiveName let diagnostic = Diagnostic(source: source, severity: .warning, range: document.range, identifier: "org.swift.docc.unsupportedTopLevelChild", summary: "Found unsupported \(directiveName.singleQuoted) directive in '.\(source.pathExtension)' file", explanation: "Only '.tutorial' files support top-level directives") problems.append(Problem(diagnostic: diagnostic, possibleSolutions: [])) return nil - } else if topLevelChildren.isEmpty, !DocumentationBundleFileTypes.isReferenceDocumentationFile(source) { + } else if topLevelChildren.isEmpty, !DocumentationInputFileTypes.isReferenceDocumentationFile(source) { // Only reference documentation support all markdown content. This document has no top level directives but is not a reference documentation file. let diagnostic = Diagnostic( source: source, @@ -77,7 +77,7 @@ struct SemanticAnalyzer: MarkupVisitor { } if topLevelChildren.isEmpty { - guard let article = Article(from: document, source: source, for: bundle, problems: &problems) else { + guard let article = Article(from: document, source: source, for: inputs, problems: &problems) else { // We've already diagnosed the invalid article. return nil } @@ -100,58 +100,58 @@ struct SemanticAnalyzer: MarkupVisitor { mutating func visitBlockDirective(_ blockDirective: BlockDirective) -> Semantic? { switch blockDirective.name { case TutorialTableOfContents.directiveName: - return TutorialTableOfContents(from: blockDirective, source: source, for: bundle, problems: &problems) + return TutorialTableOfContents(from: blockDirective, source: source, for: inputs, problems: &problems) case Volume.directiveName: - return Volume(from: blockDirective, source: source, for: bundle, problems: &problems) + return Volume(from: blockDirective, source: source, for: inputs, problems: &problems) case Chapter.directiveName: - return Chapter(from: blockDirective, source: source, for: bundle, problems: &problems) + return Chapter(from: blockDirective, source: source, for: inputs, problems: &problems) case TutorialReference.directiveName: - return TutorialReference(from: blockDirective, source: source, for: bundle, problems: &problems) + return TutorialReference(from: blockDirective, source: source, for: inputs, problems: &problems) case ContentAndMedia.directiveName: - return ContentAndMedia(from: blockDirective, source: source, for: bundle, problems: &problems) + return ContentAndMedia(from: blockDirective, source: source, for: inputs, problems: &problems) case Intro.directiveName: - return Intro(from: blockDirective, source: source, for: bundle, problems: &problems) + return Intro(from: blockDirective, source: source, for: inputs, problems: &problems) case ImageMedia.directiveName: - return ImageMedia(from: blockDirective, source: source, for: bundle, problems: &problems) + return ImageMedia(from: blockDirective, source: source, for: inputs, problems: &problems) case VideoMedia.directiveName: - return VideoMedia(from: blockDirective, source: source, for: bundle, problems: &problems) + return VideoMedia(from: blockDirective, source: source, for: inputs, problems: &problems) case Tutorial.directiveName: - return Tutorial(from: blockDirective, source: source, for: bundle, problems: &problems) + return Tutorial(from: blockDirective, source: source, for: inputs, problems: &problems) case TutorialArticle.directiveName: - return TutorialArticle(from: blockDirective, source: source, for: bundle, problems: &problems) + return TutorialArticle(from: blockDirective, source: source, for: inputs, problems: &problems) case XcodeRequirement.directiveName: - return XcodeRequirement(from: blockDirective, source: source, for: bundle, problems: &problems) + return XcodeRequirement(from: blockDirective, source: source, for: inputs, problems: &problems) case Assessments.directiveName: - return Assessments(from: blockDirective, source: source, for: bundle, problems: &problems) + return Assessments(from: blockDirective, source: source, for: inputs, problems: &problems) case MultipleChoice.directiveName: - return MultipleChoice(from: blockDirective, source: source, for: bundle, problems: &problems) + return MultipleChoice(from: blockDirective, source: source, for: inputs, problems: &problems) case Choice.directiveName: - return Choice(from: blockDirective, source: source, for: bundle, problems: &problems) + return Choice(from: blockDirective, source: source, for: inputs, problems: &problems) case Justification.directiveName: - return Justification(from: blockDirective, source: source, for: bundle, problems: &problems) + return Justification(from: blockDirective, source: source, for: inputs, problems: &problems) case TutorialSection.directiveName: - return TutorialSection(from: blockDirective, source: source, for: bundle, problems: &problems) + return TutorialSection(from: blockDirective, source: source, for: inputs, problems: &problems) case Step.directiveName: - return Step(from: blockDirective, source: source, for: bundle, problems: &problems) + return Step(from: blockDirective, source: source, for: inputs, problems: &problems) case Resources.directiveName: - return Resources(from: blockDirective, source: source, for: bundle, problems: &problems) + return Resources(from: blockDirective, source: source, for: inputs, problems: &problems) case Comment.directiveName: - return Comment(from: blockDirective, source: source, for: bundle, problems: &problems) + return Comment(from: blockDirective, source: source, for: inputs, problems: &problems) case DeprecationSummary.directiveName: - return DeprecationSummary(from: blockDirective, source: source, for: bundle, problems: &problems) + return DeprecationSummary(from: blockDirective, source: source, for: inputs, problems: &problems) case Metadata.directiveName: - return Metadata(from: blockDirective, source: source, for: bundle, problems: &problems) + return Metadata(from: blockDirective, source: source, for: inputs, problems: &problems) case Redirect.directiveName: - return Redirect(from: blockDirective, source: source, for: bundle, problems: &problems) + return Redirect(from: blockDirective, source: source, for: inputs, problems: &problems) case DocumentationExtension.directiveName: - return DocumentationExtension(from: blockDirective, source: source, for: bundle, problems: &problems) + return DocumentationExtension(from: blockDirective, source: source, for: inputs, problems: &problems) case Snippet.directiveName: // A snippet directive does not need to stay around as a Semantic object. // we only need to check the path argument and that it doesn't // have any inner content as a convenience to the author. // The path will resolve as a symbol link later in the // MarkupReferenceResolver. - _ = Snippet(from: blockDirective, source: source, for: bundle, problems: &problems) + _ = Snippet(from: blockDirective, source: source, for: inputs, problems: &problems) return nil case Options.directiveName: return nil @@ -166,7 +166,7 @@ struct SemanticAnalyzer: MarkupVisitor { guard let directive = directiveType.init( from: blockDirective, source: source, - for: bundle, + for: inputs, problems: &problems ) else { return nil diff --git a/Sources/SwiftDocC/Semantics/Snippets/Snippet.swift b/Sources/SwiftDocC/Semantics/Snippets/Snippet.swift index 417f4c5dc3..12e0001476 100644 --- a/Sources/SwiftDocC/Semantics/Snippets/Snippet.swift +++ b/Sources/SwiftDocC/Semantics/Snippets/Snippet.swift @@ -65,7 +65,7 @@ public final class Snippet: Semantic, AutomaticDirectiveConvertible { extension Snippet: RenderableDirectiveConvertible { func render(with contentCompiler: inout RenderContentCompiler) -> [any RenderContent] { - guard let snippet = Snippet(from: originalMarkup, for: contentCompiler.bundle) else { + guard let snippet = Snippet(from: originalMarkup, for: contentCompiler.context.inputs) else { return [] } diff --git a/Sources/SwiftDocC/Semantics/Symbol/Symbol.swift b/Sources/SwiftDocC/Semantics/Symbol/Symbol.swift index a62aac5ba7..deb0413567 100644 --- a/Sources/SwiftDocC/Semantics/Symbol/Symbol.swift +++ b/Sources/SwiftDocC/Semantics/Symbol/Symbol.swift @@ -48,13 +48,6 @@ public import SymbolKit /// - ``seeAlsoVariants`` /// - ``returnsSectionVariants`` /// - ``parametersSectionVariants`` -/// - ``dictionaryKeysSectionVariants`` -/// - ``possibleValuesSectionVariants`` -/// - ``httpEndpointSectionVariants`` -/// - ``httpParametersSectionVariants`` -/// - ``httpResponsesSectionVariants`` -/// - ``httpBodySectionVariants`` -/// - ``redirectsVariants`` /// - ``abstractVariants`` /// - ``isDeprecatedVariants`` /// - ``isSPIVariants`` diff --git a/Sources/SwiftDocC/Semantics/Technology/Resources/Resources.swift b/Sources/SwiftDocC/Semantics/Technology/Resources/Resources.swift index ba00a1b633..cefa682ce3 100644 --- a/Sources/SwiftDocC/Semantics/Technology/Resources/Resources.swift +++ b/Sources/SwiftDocC/Semantics/Technology/Resources/Resources.swift @@ -54,7 +54,7 @@ public final class Resources: Semantic, DirectiveConvertible, Abstracted, Redire self.redirects = redirects } - public convenience init?(from directive: BlockDirective, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) { + public convenience init?(from directive: BlockDirective, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) { precondition(directive.name == Resources.directiveName) var remainder: [any Markup] @@ -76,7 +76,7 @@ public final class Resources: Semantic, DirectiveConvertible, Abstracted, Redire guard let childDirective = child as? BlockDirective, childDirective.name == Redirect.directiveName else { return nil } - return Redirect(from: childDirective, source: source, for: bundle, problems: &problems) + return Redirect(from: childDirective, source: source, for: inputs, problems: &problems) } let tiles: [Tile] @@ -84,7 +84,7 @@ public final class Resources: Semantic, DirectiveConvertible, Abstracted, Redire guard let childDirective = child as? BlockDirective, Tile.DirectiveNames(rawValue: childDirective.name) != nil else { return nil } - return Tile(from: childDirective, source: source, for: bundle, problems: &problems) + return Tile(from: childDirective, source: source, for: inputs, problems: &problems) } var seenTileDirectiveNames = Set() diff --git a/Sources/SwiftDocC/Semantics/Technology/Resources/Tile.swift b/Sources/SwiftDocC/Semantics/Technology/Resources/Tile.swift index a8975c57d6..2e1463d153 100644 --- a/Sources/SwiftDocC/Semantics/Technology/Resources/Tile.swift +++ b/Sources/SwiftDocC/Semantics/Technology/Resources/Tile.swift @@ -166,7 +166,7 @@ public final class Tile: Semantic, DirectiveConvertible { self.init(originalMarkup: directive, identifier: tileIdentifier, title: title, destination: destination, content: MarkupContainer(directive.children)) } - public convenience init?(from directive: BlockDirective, source: URL?, for _: DocumentationBundle, problems: inout [Problem]) { + public convenience init?(from directive: BlockDirective, source: URL?, for _: DocumentationContext.Inputs, problems: inout [Problem]) { switch directive.name { case Tile.DirectiveNames.documentation.rawValue: self.init(genericTile: directive, diff --git a/Sources/SwiftDocC/Semantics/Technology/TutorialTableOfContents.swift b/Sources/SwiftDocC/Semantics/Technology/TutorialTableOfContents.swift index 7e7098c0fb..00f6822112 100644 --- a/Sources/SwiftDocC/Semantics/Technology/TutorialTableOfContents.swift +++ b/Sources/SwiftDocC/Semantics/Technology/TutorialTableOfContents.swift @@ -59,7 +59,7 @@ public final class TutorialTableOfContents: Semantic, DirectiveConvertible, Abst } } - public convenience init?(from directive: BlockDirective, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) { + public convenience init?(from directive: BlockDirective, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) { precondition(directive.name == TutorialTableOfContents.directiveName) let arguments = Semantic.Analyses.HasOnlyKnownArguments(severityIfFound: .warning, allowedArguments: [Semantics.Name.argumentName]).analyze(directive, children: directive.children, source: source, problems: &problems) @@ -67,15 +67,15 @@ public final class TutorialTableOfContents: Semantic, DirectiveConvertible, Abst Semantic.Analyses.HasOnlyKnownDirectives(severityIfFound: .warning, allowedDirectives: [Intro.directiveName, Volume.directiveName, Chapter.directiveName, Resources.directiveName, Redirect.directiveName]).analyze(directive, children: directive.children, source: source, problems: &problems) let requiredName = Semantic.Analyses.HasArgument(severityIfNotFound: .warning).analyze(directive, arguments: arguments, problems: &problems) - let requiredIntro = Semantic.Analyses.HasExactlyOne(severityIfNotFound: .warning).analyze(directive, children: directive.children, source: source, for: bundle, problems: &problems).0 + let requiredIntro = Semantic.Analyses.HasExactlyOne(severityIfNotFound: .warning).analyze(directive, children: directive.children, source: source, for: inputs, problems: &problems).0 var volumes: [Volume] var remainder: MarkupContainer - (volumes, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: directive.children, source: source, for: bundle, problems: &problems) + (volumes, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: directive.children, source: source, for: inputs, problems: &problems) // Retrieve chapters outside volumes. let chapters: [Chapter] - (chapters, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: directive.children, source: source, for: bundle, problems: &problems) + (chapters, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: directive.children, source: source, for: inputs, problems: &problems) if !chapters.isEmpty { if !volumes.isEmpty { @@ -94,10 +94,10 @@ public final class TutorialTableOfContents: Semantic, DirectiveConvertible, Abst } let resources: Resources? - (resources, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + (resources, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) let redirects: [Redirect] - (redirects, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + (redirects, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) guard let name = requiredName, let intro = requiredIntro else { diff --git a/Sources/SwiftDocC/Semantics/Technology/Volume/Volume.swift b/Sources/SwiftDocC/Semantics/Technology/Volume/Volume.swift index 40e606ca6a..900357def3 100644 --- a/Sources/SwiftDocC/Semantics/Technology/Volume/Volume.swift +++ b/Sources/SwiftDocC/Semantics/Technology/Volume/Volume.swift @@ -63,7 +63,7 @@ public final class Volume: Semantic, DirectiveConvertible, Abstracted, Redirecte } } - public convenience init?(from directive: BlockDirective, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) { + public convenience init?(from directive: BlockDirective, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) { precondition(directive.name == Volume.directiveName) let arguments = Semantic.Analyses.HasOnlyKnownArguments(severityIfFound: .warning, allowedArguments: [Semantics.Name.argumentName]).analyze(directive, children: directive.children, source: source, problems: &problems) @@ -74,14 +74,14 @@ public final class Volume: Semantic, DirectiveConvertible, Abstracted, Redirecte let image: ImageMedia? var remainder: MarkupContainer - (image, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: .warning).analyze(directive, children: directive.children, source: source, for: bundle, problems: &problems) + (image, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: .warning).analyze(directive, children: directive.children, source: source, for: inputs, problems: &problems) let chapters: [Chapter] - (chapters, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: .warning).analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + (chapters, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: .warning).analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) _ = Semantic.Analyses.HasContent(additionalContext: "A \(Volume.directiveName.singleQuoted) directive should at least have a sentence summarizing what the reader will learn").analyze(directive, children: remainder, source: source, problems: &problems) let redirects: [Redirect] - (redirects, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + (redirects, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) guard let name = requiredName else { return nil diff --git a/Sources/SwiftDocC/Semantics/Tutorial/Assessments/Multiple Choice/MultipleChoice.swift b/Sources/SwiftDocC/Semantics/Tutorial/Assessments/Multiple Choice/MultipleChoice.swift index 3b8eecfa2f..8550187bc6 100644 --- a/Sources/SwiftDocC/Semantics/Tutorial/Assessments/Multiple Choice/MultipleChoice.swift +++ b/Sources/SwiftDocC/Semantics/Tutorial/Assessments/Multiple Choice/MultipleChoice.swift @@ -51,7 +51,7 @@ public final class MultipleChoice: Semantic, DirectiveConvertible { self.choices = choices } - public convenience init?(from directive: BlockDirective, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) { + public convenience init?(from directive: BlockDirective, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) { precondition(directive.name == MultipleChoice.directiveName) _ = Semantic.Analyses.HasOnlyKnownArguments(severityIfFound: .warning, allowedArguments: []).analyze(directive, children: directive.children, source: source, problems: &problems) @@ -70,7 +70,7 @@ public final class MultipleChoice: Semantic, DirectiveConvertible { } let choices: [Choice] - (choices, remainder) = Semantic.Analyses.ExtractAll().analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + (choices, remainder) = Semantic.Analyses.ExtractAll().analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) if choices.count < 2 || choices.count > 4 { let diagnostic = Diagnostic(source: source, severity: .warning, range: directive.range, identifier: "org.swift.docc.\(MultipleChoice.self).CorrectNumberOfChoices", summary: "`\(MultipleChoice.directiveName)` should contain 2-4 `\(Choice.directiveName)` child directives") @@ -115,7 +115,7 @@ public final class MultipleChoice: Semantic, DirectiveConvertible { } let images: [ImageMedia] - (images, remainder) = Semantic.Analyses.ExtractAll().analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + (images, remainder) = Semantic.Analyses.ExtractAll().analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) if images.count > 1 { for extraneousImage in images.suffix(from: 1) { diff --git a/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Code.swift b/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Code.swift index ceca8cb7f0..f91c530b3a 100644 --- a/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Code.swift +++ b/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Code.swift @@ -59,7 +59,7 @@ public final class Code: Semantic, DirectiveConvertible { self.preview = preview } - public convenience init?(from directive: BlockDirective, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) { + public convenience init?(from directive: BlockDirective, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) { precondition(directive.name == Code.directiveName) let arguments = Semantic.Analyses.HasOnlyKnownArguments(severityIfFound: .warning, allowedArguments: [Semantics.File.argumentName, Semantics.PreviousFile.argumentName, Semantics.Name.argumentName, Semantics.ResetDiff.argumentName]).analyze(directive, children: directive.children, source: source, problems: &problems) @@ -67,7 +67,7 @@ public final class Code: Semantic, DirectiveConvertible { Semantic.Analyses.HasOnlyKnownDirectives(severityIfFound: .warning, allowedDirectives: [ImageMedia.directiveName, VideoMedia.directiveName]).analyze(directive, children: directive.children, source: source, problems: &problems) guard let requiredFileReference = Semantic.Analyses.HasArgument(severityIfNotFound: .warning).analyze(directive, arguments: arguments, problems: &problems) else { return nil } - let fileReference = ResourceReference(bundleID: bundle.id, path: requiredFileReference) + let fileReference = ResourceReference(bundleID: inputs.id, path: requiredFileReference) guard let requiredFileName = Semantic.Analyses.HasArgument(severityIfNotFound: .warning).analyze(directive, arguments: arguments, problems: &problems) else { return nil } @@ -80,10 +80,10 @@ public final class Code: Semantic, DirectiveConvertible { shouldResetDiff = false } - let (optionalPreview, _) = Semantic.Analyses.HasExactlyOneImageOrVideoMedia(severityIfNotFound: nil).analyze(directive, children: directive.children, source: source, for: bundle, problems: &problems) + let (optionalPreview, _) = Semantic.Analyses.HasExactlyOneImageOrVideoMedia(severityIfNotFound: nil).analyze(directive, children: directive.children, source: source, for: inputs, problems: &problems) let optionalPreviousFileReference = Semantic.Analyses.HasArgument(severityIfNotFound: nil).analyze(directive, arguments: arguments, problems: &problems).map { argument in - ResourceReference(bundleID: bundle.id, path: argument) + ResourceReference(bundleID: inputs.id, path: argument) } self.init(originalMarkup: directive, fileReference: fileReference, fileName: requiredFileName, previousFileReference: optionalPreviousFileReference, shouldResetDiff: shouldResetDiff, preview: optionalPreview) diff --git a/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Step.swift b/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Step.swift index 625e16572f..78cf270b80 100644 --- a/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Step.swift +++ b/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Step.swift @@ -46,7 +46,7 @@ public final class Step: Semantic, DirectiveConvertible { self.caption = caption } - public convenience init?(from directive: BlockDirective, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) { + public convenience init?(from directive: BlockDirective, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) { precondition(directive.name == Step.directiveName) _ = Semantic.Analyses.HasOnlyKnownArguments(severityIfFound: .warning, allowedArguments: []).analyze(directive, children: directive.children, source: source, problems: &problems) @@ -55,10 +55,10 @@ public final class Step: Semantic, DirectiveConvertible { var remainder: MarkupContainer let optionalMedia: (any Media)? - (optionalMedia, remainder) = Semantic.Analyses.HasExactlyOneMedia(severityIfNotFound: nil).analyze(directive, children: directive.children, source: source, for: bundle, problems: &problems) + (optionalMedia, remainder) = Semantic.Analyses.HasExactlyOneMedia(severityIfNotFound: nil).analyze(directive, children: directive.children, source: source, for: inputs, problems: &problems) let optionalCode: Code? - (optionalCode, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + (optionalCode, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) let paragraphs: [Paragraph] (paragraphs, remainder) = Semantic.Analyses.ExtractAllMarkup().analyze(directive, children: remainder, source: source, problems: &problems) diff --git a/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Steps.swift b/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Steps.swift index 9edba4a4cb..96da81f3c9 100644 --- a/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Steps.swift +++ b/Sources/SwiftDocC/Semantics/Tutorial/Tasks/Steps/Steps.swift @@ -34,7 +34,7 @@ public final class Steps: Semantic, DirectiveConvertible { self.content = content } - public convenience init?(from directive: BlockDirective, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) { + public convenience init?(from directive: BlockDirective, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) { precondition(directive.name == Steps.directiveName) _ = Semantic.Analyses.HasOnlyKnownArguments(severityIfFound: .warning, allowedArguments: []) @@ -46,7 +46,7 @@ public final class Steps: Semantic, DirectiveConvertible { let stepsContent: [Semantic] = directive.children.compactMap { child -> Semantic? in if let directive = child as? BlockDirective, directive.name == Step.directiveName { - return Step(from: directive, source: source, for: bundle, problems: &problems) + return Step(from: directive, source: source, for: inputs, problems: &problems) } else { return MarkupContainer(child) } diff --git a/Sources/SwiftDocC/Semantics/Tutorial/Tasks/TutorialSection.swift b/Sources/SwiftDocC/Semantics/Tutorial/Tasks/TutorialSection.swift index 17ded53583..d95a3bcecb 100644 --- a/Sources/SwiftDocC/Semantics/Tutorial/Tasks/TutorialSection.swift +++ b/Sources/SwiftDocC/Semantics/Tutorial/Tasks/TutorialSection.swift @@ -77,7 +77,7 @@ public final class TutorialSection: Semantic, DirectiveConvertible, Abstracted, } } - public convenience init?(from directive: BlockDirective, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) { + public convenience init?(from directive: BlockDirective, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) { precondition(directive.name == TutorialSection.directiveName) let arguments = Semantic.Analyses.HasOnlyKnownArguments(severityIfFound: .warning, allowedArguments: [Semantics.Title.argumentName]).analyze(directive, children: directive.children, source: source, problems: &problems) @@ -88,14 +88,14 @@ public final class TutorialSection: Semantic, DirectiveConvertible, Abstracted, var remainder: MarkupContainer let optionalSteps: Steps? - (optionalSteps, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: .warning).analyze(directive, children: directive.children, source: source, for: bundle, problems: &problems) + (optionalSteps, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: .warning).analyze(directive, children: directive.children, source: source, for: inputs, problems: &problems) - Semantic.Analyses.HasOnlySequentialHeadings(severityIfFound: .warning, startingFromLevel: 2).analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + Semantic.Analyses.HasOnlySequentialHeadings(severityIfFound: .warning, startingFromLevel: 2).analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) let redirects: [Redirect] - (redirects, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + (redirects, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) - let content = StackedContentParser.topLevelContent(from: remainder, source: source, for: bundle, problems: &problems) + let content = StackedContentParser.topLevelContent(from: remainder, source: source, for: inputs, problems: &problems) guard let title = requiredTitle else { return nil diff --git a/Sources/SwiftDocC/Semantics/TutorialArticle/TutorialArticle.swift b/Sources/SwiftDocC/Semantics/TutorialArticle/TutorialArticle.swift index 56961cba84..15fb2a8905 100644 --- a/Sources/SwiftDocC/Semantics/TutorialArticle/TutorialArticle.swift +++ b/Sources/SwiftDocC/Semantics/TutorialArticle/TutorialArticle.swift @@ -102,7 +102,7 @@ public final class TutorialArticle: Semantic, DirectiveConvertible, Abstracted, self.redirects = redirects } - public convenience init?(from directive: BlockDirective, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) { + public convenience init?(from directive: BlockDirective, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) { precondition(directive.name == TutorialArticle.directiveName) let arguments = Semantic.Analyses.HasOnlyKnownArguments(severityIfFound: .warning, allowedArguments: [Semantics.Time.argumentName]) @@ -116,20 +116,20 @@ public final class TutorialArticle: Semantic, DirectiveConvertible, Abstracted, var remainder: MarkupContainer let optionalIntro: Intro? - (optionalIntro, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: .warning).analyze(directive, children: directive.children, source: source, for: bundle, problems: &problems) + (optionalIntro, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: .warning).analyze(directive, children: directive.children, source: source, for: inputs, problems: &problems) - let headings = Semantic.Analyses.HasOnlySequentialHeadings(severityIfFound: .warning, startingFromLevel: 2).analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + let headings = Semantic.Analyses.HasOnlySequentialHeadings(severityIfFound: .warning, startingFromLevel: 2).analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) - let content = StackedContentParser.topLevelContent(from: remainder, source: source, for: bundle, problems: &problems) + let content = StackedContentParser.topLevelContent(from: remainder, source: source, for: inputs, problems: &problems) let optionalAssessments: Assessments? - (optionalAssessments, remainder) = Semantic.Analyses.HasAtMostOne().analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + (optionalAssessments, remainder) = Semantic.Analyses.HasAtMostOne().analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) let optionalCallToActionImage: ImageMedia? - (optionalCallToActionImage, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + (optionalCallToActionImage, remainder) = Semantic.Analyses.HasExactlyOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) let redirects: [Redirect] - (redirects, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: bundle, problems: &problems) + (redirects, remainder) = Semantic.Analyses.HasAtLeastOne(severityIfNotFound: nil).analyze(directive, children: remainder, source: source, for: inputs, problems: &problems) self.init(originalMarkup: directive, durationMinutes: optionalTime, intro: optionalIntro, content: content, assessments: optionalAssessments, callToActionImage: optionalCallToActionImage, landmarks: headings, redirects: redirects.isEmpty ? nil : redirects) } @@ -152,14 +152,14 @@ public enum MarkupLayout { } struct StackedContentParser { - static func topLevelContent(from markup: some Sequence, source: URL?, for bundle: DocumentationBundle, problems: inout [Problem]) -> [MarkupLayout] { + static func topLevelContent(from markup: some Sequence, source: URL?, for inputs: DocumentationContext.Inputs, problems: inout [Problem]) -> [MarkupLayout] { return markup.reduce(into: []) { (accumulation, nextBlock) in if let directive = nextBlock as? BlockDirective { if directive.name == Stack.directiveName, - let stack = Stack(from: directive, source: source, for: bundle, problems: &problems) { + let stack = Stack(from: directive, source: source, for: inputs, problems: &problems) { accumulation.append(.stack(stack)) } else if directive.name == ContentAndMedia.directiveName, - let contentAndMedia = ContentAndMedia(from: directive, source: source, for: bundle, problems: &problems) { + let contentAndMedia = ContentAndMedia(from: directive, source: source, for: inputs, problems: &problems) { accumulation.append(.contentAndMedia(contentAndMedia)) } } else { diff --git a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/AddingFeatureFlags.md b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/AddingFeatureFlags.md index 3712ca2aa0..9517c5c782 100644 --- a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/AddingFeatureFlags.md +++ b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/AddingFeatureFlags.md @@ -27,14 +27,11 @@ instance, which can then be used during the compilation process. ### Feature flags in Info.plist -A subset of feature flags can affect how a documentation bundle is authored. For example, the -experimental overloaded symbol presentation can affect how a bundle curates its symbols due to the -creation of overload group pages. These flags should also be added to the -``DocumentationBundle/Info/BundleFeatureFlags`` type, so that they can be parsed out of a bundle's -Info.plist. +A subset of feature flags can affect how you write documentation. +For example, the experimental overloaded symbol presentation can affect how you curate symbols due to the creation of overload group pages. +Feature flags like this can be defined in the ``DocumentationContext/Inputs/Info/BundleFeatureFlags`` the, so that they can be parsed out of a documentation catalog's Info.plist file. -Feature flags that are loaded from an Info.plist file are saved into the global feature flags while -the bundle is being registered. To ensure that your new feature flag is properly loaded, update the -``FeatureFlags/loadFlagsFromBundle(_:)`` method to load your new field into the global flags. +Feature flags that are loaded from an Info.plist file are saved into the global ``FeatureFlags/current`` feature flags during the context registration. +To ensure that your new feature flag is properly loaded, update the ``FeatureFlags/loadFlagsFromBundle(_:)`` method to load your new field into the global ``FeatureFlags/current`` flags. - + diff --git a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Benchmarking.md b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Benchmarking.md index 7f97baff97..b66d0d9130 100644 --- a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Benchmarking.md +++ b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Benchmarking.md @@ -36,17 +36,17 @@ This will only gather new metrics for the local changes, as you iterate, but wil When you work on a particular feature and you want to track a given custom metric you can temporarily add it to the log. -For example, to add a metric that counts the registered bundles, create a `BundlesCount` class that adopts the ``BenchmarkMetric`` protocol: +For example, to add a metric that counts the the number of markdown files in the collection of inputs, create a `MarkdownFileCount` class that adopts the ``BenchmarkMetric`` protocol: ```swift -class BundlesCount: BenchmarkMetric { - static let identifier = "bundles-count" - static let displayName = "Bundles Count" +class MarkdownFileCount: BenchmarkMetric { + static let identifier = "markdown-file-count" + static let displayName = "Markdown File Count" var result: MetricValue? init(context: DocumentationContext) { - result = .number(Double(context.registeredBundles.count)) + result = .number(Double(context.inputs.markupURLs.count)) } } ``` @@ -80,4 +80,4 @@ benchmark(add: BundlesCount(context: context)) - ``benchmark(end:benchmarkLog:)`` - ``benchmark(wrap:benchmarkLog:body:)`` - + diff --git a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Communication.md b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Communication.md index 9b7e3d80bf..7d2fc01456 100644 --- a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Communication.md +++ b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Communication.md @@ -19,7 +19,6 @@ Offer native integration of DocC in your IDE. - ``FileServerProvider`` - ``FileServer`` -- ``FileSystemRenderNodeProvider`` - ``FileSystemServerProvider`` - ``MemoryFileServerProvider`` diff --git a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/DocumentationContextGroup.md b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/DocumentationContextGroup.md index 32904e973c..9378d7c1ad 100644 --- a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/DocumentationContextGroup.md +++ b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/DocumentationContextGroup.md @@ -7,7 +7,7 @@ Build and query the in-memory documentation model. A documentation context is the the in-memory representation of a "unit" of documentation (for example a module, package, or technology). The context is generally responsible for: - - Analyzing bundle file contents and converting to semantic models. + - Analyzing input file contents and converting to semantic models. - Managing a graph of documentation nodes (a single node representing one documentation topic). - Processing assets like media files or download archives. - Resolving links to external documentation sources via ``ExternalDocumentationSource`` and resolving external symbols via ``GlobalExternalSymbolResolver``. @@ -15,16 +15,16 @@ The context is generally responsible for: ### Creating a Context -Use ``DocumentationContext/init(bundle:dataProvider:diagnosticEngine:configuration:)`` to create a context for a given bundle: +Use ``DocumentationContext/init(inputs:dataProvider:diagnosticEngine:configuration:)`` to create a context for a given collection of inputs files: ```swift let inputsProvider = DocumentationContext.InputsProvider() -let (bundle, dataProvider) = try inputsProvider.inputsAndDataProvider( +let (inputs, dataProvider) = try inputsProvider.inputsAndDataProvider( startingPoint: catalogURL, options: bundleDiscoveryOptions ) -let context = try DocumentationContext(bundle: bundle, dataProvider: dataProvider) +let context = try DocumentationContext(inputs: inputs, dataProvider: dataProvider) ``` ### Accessing Documentation @@ -33,7 +33,7 @@ Use ``DocumentationContext/entity(with:)`` to access a documentation node by its ```swift let reference = ResolvedTopicReference( - bundleID: "com.mybundle", + bundleID: "com.example", path: "/documentation/ValidationKit/EmailValidator", fragment: nil, sourceLanguage: .swift) @@ -74,9 +74,7 @@ let sourceFileURL = try context.documentURL(for: reference) ### Code Listings -- ``AttributedCodeListing`` -- ``UnresolvedCodeListingReference`` - ``CodeColorsPreferenceKey`` - ``SRGBColor`` - + diff --git a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/DocumentationIndexing.md b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/DocumentationIndexing.md index 80316b7ddd..5daca6ccb6 100644 --- a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/DocumentationIndexing.md +++ b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/DocumentationIndexing.md @@ -28,7 +28,6 @@ Each rendering model element adopts the ``TextIndexing`` protocol in order to pr - ``AvailabilityIndex`` - ``RenderNodeDataExtractor`` -- ``RenderNodeProvider`` - ``Serializable`` - ``AnyCodable`` - ``AnyMetadata`` diff --git a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/InputDiscovery.md b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/InputDiscovery.md index 80d38636c0..e83ceb3de9 100644 --- a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/InputDiscovery.md +++ b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/InputDiscovery.md @@ -4,7 +4,7 @@ Learn how to discover documentation inputs on the file system. ## Discussion -A ``DocumentationContext/InputsProvider`` discovers documentation catalogs on the file system and creates a ``DocumentationBundle`` from the discovered catalog content. +A ``DocumentationContext/InputsProvider`` discovers documentation catalogs on the file system and creates a ``DocumentationContext/Inputs`` from the discovered catalog content. ```swift let inputProvider = DocumentationContext.InputsProvider(fileManager: fileSystem) @@ -12,9 +12,9 @@ let inputProvider = DocumentationContext.InputsProvider(fileManager: fileSystem) guard let catalogURL = try inputProvider.findCatalog(startingPoint: startingPoint) else { return } -let bundle = try inputProvider.makeInputs(contentOf: catalogURL, options: BundleDiscoveryOptions()) +let inputs = try inputProvider.makeInputs(contentOf: catalogURL, options: CatalogDiscoveryOptions()) -print("A bundle with ID: \(bundle.identifier)") +print("Documentation inputs with ID: \(inputs.identifier)") ``` You can also create documentation inputs, without a documentation catalog, from a list of symbol graph files: @@ -22,41 +22,41 @@ You can also create documentation inputs, without a documentation catalog, from ```swift let inputProvider = DocumentationContext.InputsProvider(fileManager: fileSystem) -guard let (bundle, dataProvider) = try inputProvider.makeInputsFromSymbolGraphs( - options: BundleDiscoveryOptions( +guard let (inputs, dataProvider) = try inputProvider.makeInputsFromSymbolGraphs( + options: CatalogDiscoveryOptions( additionalSymbolGraphFiles: listOfSymbolGraphLocations ) ) else { return } -print("A bundle with ID: \(bundle.identifier)") +print("Documentation inputs with ID: \(inputs.identifier)") ``` -> Note: use the returned `dataProvider` to create a ``DocumentationContext`` from this ``DocumentationBundle``. +> Note: use the returned `dataProvider` to create a ``DocumentationContext`` from this ``DocumentationContext/Inputs``. -It's common to want combine these two strategies and require that they discover a ``DocumentationBundle``. +It's common to want combine these two strategies and require that they discover a ``DocumentationContext/Inputs``. For this use-case, use the ``DocumentationContext/InputsProvider/inputsAndDataProvider(startingPoint:allowArbitraryCatalogDirectories:options:)`` method: ```swift let inputProvider = DocumentationContext.InputsProvider(fileManager: fileSystem) -let (bundle, dataProvider) = try inputProvider.inputsAndDataProvider( +let (inputs, dataProvider) = try inputProvider.inputsAndDataProvider( startingPoint: maybeStartingPoint, - options: BundleDiscoveryOptions( + options: CatalogDiscoveryOptions( additionalSymbolGraphFiles: listOfSymbolGraphLocations ) ) -print("A bundle with ID: \(bundle.identifier)") +print("Documentation inputs with ID: \(inputs.identifier)") ``` -### Bundle Contents +### Input files -A ``DocumentationBundle`` represents the list of "discovered" input files--categorized by their kind--to use as documentation inputs. +A ``DocumentationContext/Inputs`` represents the list of "discovered" input files--categorized by their kind--to use as documentation inputs. -Use a ``DataProvider`` that the ``DocumentationContext/InputsProvider`` returned alongside the bundle to read the files in the bundle. +Use a ``DataProvider`` that the ``DocumentationContext/InputsProvider`` returned alongside the inputs to its files. ## Topics @@ -65,22 +65,22 @@ Use a ``DataProvider`` that the ``DocumentationContext/InputsProvider`` returned - ``DocumentationContext/InputsProvider`` - ``DocumentationContext/InputsProvider/inputsAndDataProvider(startingPoint:allowArbitraryCatalogDirectories:options:)`` -### Documentation Bundle +### Inputs -- ``DocumentationBundle`` -- ``BundleIdentifier`` -- ``DocumentationBundleFileTypes`` +- ``DocumentationContext/Inputs`` +- ``DocumentationContext/Inputs/Identifier`` +- ``DocumentationInputFileTypes`` -### Bundle Assets +### Assets - ``DataTraitCollection`` - ``DataAsset`` - ``BundleData`` -### Bundle Metadata +### Inputs Metadata - ``ExternalMetadata`` - ``DefaultAvailability`` - ``PlatformVersion`` - + diff --git a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/PersistingDocumentation.md b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/PersistingDocumentation.md index e08c6a54d6..603115b690 100644 --- a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/PersistingDocumentation.md +++ b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/PersistingDocumentation.md @@ -9,7 +9,7 @@ Once the in-memory documentation model is finalized each of its graph nodes can The ``DocumentationNodeConverter`` type converts documentation nodes to rendering nodes: ```swift -let converter = DocumentationNodeConverter(bundle: myBundle, context: myContext) +let converter = DocumentationNodeConverter(context: myContext) let renderNode = converter.convert(documentationNode) ``` @@ -38,4 +38,4 @@ The precise path inside the output folder where resulting JSON file is saved is - ``RenderNodeTransformationContext`` - ``RenderNodeTransformer`` - + diff --git a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/RenderingModel/RenderingModel.md b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/RenderingModel/RenderingModel.md index d9284d75e0..a899f82eb0 100644 --- a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/RenderingModel/RenderingModel.md +++ b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/RenderingModel/RenderingModel.md @@ -8,7 +8,7 @@ A representation of the in-memory model's documentation nodes when compiled into A documentation node represents a single documentation topic and it might reference a variety of resources within the documentation context. Unlike a documentation node, a rendering node is a self-contained entity that includes any and all data necessary to display a single page of documentation. -Hereto a rendering node contains data not only about a single specific topic (a tutorial, an article, or a framework symbol) but also data about its hierarchy in the documentation bundle, the titles and abstracts of any linked symbols, and any other metadata needed to display a single documentation page. +Hereto a rendering node contains data not only about a single specific topic (a tutorial, an article, or a framework symbol) but also data about its hierarchy in the documentation, the titles and abstracts of any linked symbols, and any other metadata needed to display a single documentation page. ``RenderNodeTranslator`` is the type that converts a ``DocumentationNode`` into a ``RenderNode`` and ``PresentationURLGenerator`` is the one that automatically determines the location of the resulting rendering node within the compiled documentation. @@ -74,4 +74,4 @@ Hereto a rendering node contains data not only about a single specific topic (a - ``SemanticVersion`` - + diff --git a/Sources/SwiftDocC/Utility/FeatureFlags.swift b/Sources/SwiftDocC/Utility/FeatureFlags.swift index def7e642d1..b3a90bb331 100644 --- a/Sources/SwiftDocC/Utility/FeatureFlags.swift +++ b/Sources/SwiftDocC/Utility/FeatureFlags.swift @@ -32,9 +32,9 @@ public struct FeatureFlags: Codable { /// Creates a set of feature flags with all default values. public init() {} - /// Set feature flags that were loaded from a bundle's Info.plist. - internal mutating func loadFlagsFromBundle(_ bundleFlags: DocumentationBundle.Info.BundleFeatureFlags) { - if let overloadsPresentation = bundleFlags.experimentalOverloadedSymbolPresentation { + /// Set feature flags that were loaded from an input files Info.plist. + internal mutating func loadFlagsFromInputs(_ inputFilesFlags: DocumentationContext.Inputs.Info.BundleFeatureFlags) { + if let overloadsPresentation = inputFilesFlags.experimentalOverloadedSymbolPresentation { self.isExperimentalOverloadedSymbolPresentationEnabled = overloadsPresentation } } diff --git a/Sources/SwiftDocC/Utility/FoundationExtensions/Dictionary+TypedValues.swift b/Sources/SwiftDocC/Utility/FoundationExtensions/Dictionary+TypedValues.swift index 6ca1858aca..34ff43d05c 100644 --- a/Sources/SwiftDocC/Utility/FoundationExtensions/Dictionary+TypedValues.swift +++ b/Sources/SwiftDocC/Utility/FoundationExtensions/Dictionary+TypedValues.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -53,7 +53,7 @@ enum TypedValueError: DescribedError { /// The requested value is of the wrong type. case wrongType(key: String, expected: Any.Type, actual: Any.Type) /// One or more required ``DocumentationBundle.Info.Key``s are missing. - case missingRequiredKeys([DocumentationBundle.Info.CodingKeys]) + case missingRequiredKeys([DocumentationContext.Inputs.Info.CodingKeys]) var errorDescription: String { switch self { diff --git a/Sources/SwiftDocCTestUtilities/FilesAndFolders.swift b/Sources/SwiftDocCTestUtilities/FilesAndFolders.swift index 248dcdc9db..406366c281 100644 --- a/Sources/SwiftDocCTestUtilities/FilesAndFolders.swift +++ b/Sources/SwiftDocCTestUtilities/FilesAndFolders.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2024 Apple Inc. and the Swift project authors + Copyright (c) 2021-2025 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See https://swift.org/LICENSE.txt for license information @@ -94,11 +94,17 @@ public struct InfoPlist: File, DataRepresentable { /// The information that the Into.plist file contains. public let content: Content - public init(displayName: String? = nil, identifier: String? = nil, defaultAvailability: [String: [DefaultAvailability.ModuleAvailability]]? = nil) { + public init( + displayName: String? = nil, + identifier: String? = nil, + defaultAvailability: [String: [DefaultAvailability.ModuleAvailability]]? = nil, + defaultCodeListingLanguage: String? = nil + ) { self.content = Content( displayName: displayName, identifier: identifier, - defaultAvailability: defaultAvailability + defaultAvailability: defaultAvailability, + defaultCodeListingLanguage: defaultCodeListingLanguage ) } @@ -106,25 +112,29 @@ public struct InfoPlist: File, DataRepresentable { public let displayName: String? public let identifier: String? public let defaultAvailability: [String: [DefaultAvailability.ModuleAvailability]]? - - fileprivate init(displayName: String?, identifier: String?, defaultAvailability: [String: [DefaultAvailability.ModuleAvailability]]?) { + public let defaultCodeListingLanguage: String? + + fileprivate init(displayName: String?, identifier: String?, defaultAvailability: [String: [DefaultAvailability.ModuleAvailability]]?, defaultCodeListingLanguage: String?) { self.displayName = displayName self.identifier = identifier self.defaultAvailability = defaultAvailability + self.defaultCodeListingLanguage = defaultCodeListingLanguage } public init(from decoder: any Decoder) throws { - let container = try decoder.container(keyedBy: DocumentationBundle.Info.CodingKeys.self) + let container = try decoder.container(keyedBy: DocumentationContext.Inputs.Info.CodingKeys.self) displayName = try container.decodeIfPresent(String.self, forKey: .displayName) identifier = try container.decodeIfPresent(String.self, forKey: .id) defaultAvailability = try container.decodeIfPresent([String : [DefaultAvailability.ModuleAvailability]].self, forKey: .defaultAvailability) + defaultCodeListingLanguage = try container.decodeIfPresent(String.self, forKey: .defaultCodeListingLanguage) } public func encode(to encoder: any Encoder) throws { - var container = encoder.container(keyedBy: DocumentationBundle.Info.CodingKeys.self) + var container = encoder.container(keyedBy: DocumentationContext.Inputs.Info.CodingKeys.self) try container.encodeIfPresent(displayName, forKey: .displayName) try container.encodeIfPresent(identifier, forKey: .id) try container.encodeIfPresent(defaultAvailability, forKey: .defaultAvailability) + try container.encodeIfPresent(defaultCodeListingLanguage, forKey: .defaultCodeListingLanguage) } } diff --git a/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift b/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift index 6f0af6647c..f64f01196e 100644 --- a/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift +++ b/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift @@ -81,7 +81,7 @@ public struct ConvertAction: AsyncAction { fileManager: any FileManagerProtocol = FileManager.default, temporaryDirectory: URL, documentationCoverageOptions: DocumentationCoverageOptions = .noCoverage, - bundleDiscoveryOptions: BundleDiscoveryOptions = .init(), + bundleDiscoveryOptions: CatalogDiscoveryOptions = .init(), diagnosticLevel: String? = nil, diagnosticEngine: DiagnosticEngine? = nil, diagnosticFilePath: URL? = nil, @@ -167,7 +167,7 @@ public struct ConvertAction: AsyncAction { } configuration.externalDocumentationConfiguration.dependencyArchives = dependencies - let (bundle, dataProvider) = try signposter.withIntervalSignpost("Discover inputs", id: signposter.makeSignpostID()) { + let (inputs, dataProvider) = try signposter.withIntervalSignpost("Discover inputs", id: signposter.makeSignpostID()) { try DocumentationContext.InputsProvider(fileManager: fileManager) .inputsAndDataProvider( startingPoint: documentationBundleURL, @@ -178,12 +178,12 @@ public struct ConvertAction: AsyncAction { self.configuration = configuration - self.bundle = bundle + self.inputs = inputs self.dataProvider = dataProvider } let configuration: DocumentationContext.Configuration - private let bundle: DocumentationBundle + private let inputs: DocumentationContext.Inputs private let dataProvider: any DataProvider /// A block of extra work that tests perform to affect the time it takes to convert documentation @@ -286,10 +286,10 @@ public struct ConvertAction: AsyncAction { workingDirectory: temporaryFolder, fileManager: fileManager) - let indexer = try Indexer(outputURL: temporaryFolder, bundleID: bundle.id) + let indexer = try Indexer(outputURL: temporaryFolder, bundleID: inputs.id) let registerInterval = signposter.beginInterval("Register", id: signposter.makeSignpostID()) - let context = try await DocumentationContext(bundle: bundle, dataProvider: dataProvider, diagnosticEngine: diagnosticEngine, configuration: configuration) + let context = try await DocumentationContext(inputs: inputs, dataProvider: dataProvider, diagnosticEngine: diagnosticEngine, configuration: configuration) signposter.endInterval("Register", registerInterval) let outputConsumer = ConvertFileWritingConsumer( @@ -300,7 +300,7 @@ public struct ConvertAction: AsyncAction { indexer: indexer, enableCustomTemplates: experimentalEnableCustomTemplates, transformForStaticHostingIndexHTML: transformForStaticHosting ? indexHTML : nil, - bundleID: bundle.id + bundleID: inputs.id ) if experimentalModifyCatalogWithGeneratedCuration, let catalogURL = rootURL { @@ -318,7 +318,6 @@ public struct ConvertAction: AsyncAction { do { conversionProblems = try signposter.withIntervalSignpost("Process") { try ConvertActionConverter.convert( - bundle: bundle, context: context, outputConsumer: outputConsumer, sourceRepository: sourceRepository, @@ -347,7 +346,7 @@ public struct ConvertAction: AsyncAction { let tableOfContentsFilename = CatalogTemplateKind.tutorialTopLevelFilename let source = rootURL?.appendingPathComponent(tableOfContentsFilename) var replacements = [Replacement]() - if let tableOfContentsTemplate = CatalogTemplateKind.tutorialTemplateFiles(bundle.displayName)[tableOfContentsFilename] { + if let tableOfContentsTemplate = CatalogTemplateKind.tutorialTemplateFiles(inputs.displayName)[tableOfContentsFilename] { replacements.append( Replacement( range: .init(line: 1, column: 1, source: source) ..< .init(line: 1, column: 1, source: source), @@ -438,7 +437,7 @@ public struct ConvertAction: AsyncAction { context: context, indexer: nil, transformForStaticHostingIndexHTML: nil, - bundleID: bundle.id + bundleID: inputs.id ) try outputConsumer.consume(benchmarks: Benchmark.main) diff --git a/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertFileWritingConsumer.swift b/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertFileWritingConsumer.swift index 56e4925851..9133d48424 100644 --- a/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertFileWritingConsumer.swift +++ b/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertFileWritingConsumer.swift @@ -34,7 +34,7 @@ struct ConvertFileWritingConsumer: ConvertOutputConsumer, ExternalNodeConsumer { indexer: ConvertAction.Indexer?, enableCustomTemplates: Bool = false, transformForStaticHostingIndexHTML: URL?, - bundleID: DocumentationBundle.Identifier? + bundleID: DocumentationContext.Inputs.Identifier? ) { self.targetFolder = targetFolder self.bundleRootFolder = bundleRootFolder @@ -73,7 +73,7 @@ struct ConvertFileWritingConsumer: ConvertOutputConsumer, ExternalNodeConsumer { indexer?.index(externalRenderNode) } - func consume(assetsInBundle bundle: DocumentationBundle) throws { + func consume(assetsInInputs inputs: DocumentationContext.Inputs) throws { func copyAsset(_ asset: DataAsset, to destinationFolder: URL) throws { for sourceURL in asset.variants.values where !sourceURL.isAbsoluteWebURL { let assetName = sourceURL.lastPathComponent @@ -84,7 +84,7 @@ struct ConvertFileWritingConsumer: ConvertOutputConsumer, ExternalNodeConsumer { } } - let bundleID = bundle.id + let bundleID = inputs.id assert(bundleID.rawValue == self.assetPrefixComponent, "Unexpectedly encoding assets for a bundle other than the one this output consumer was created for.") // Create images directory if needed. @@ -129,21 +129,21 @@ struct ConvertFileWritingConsumer: ConvertOutputConsumer, ExternalNodeConsumer { // If the bundle contains a `header.html` file, inject a