Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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]()
Expand Down
31 changes: 22 additions & 9 deletions Sources/SwiftDocC/Converter/DocumentationContextConverter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand All @@ -61,15 +57,13 @@ 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,
emitSymbolAccessLevels: Bool = false,
sourceRepository: SourceRepository? = nil,
symbolIdentifiersWithExpandedDocumentation: [String]? = nil
) {
self.bundle = bundle
self.context = context
self.renderContext = renderContext
self.shouldEmitSymbolSourceFileURIs = emitSymbolSourceFileURIs
Expand All @@ -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.
Expand All @@ -91,7 +105,6 @@ public class DocumentationContextConverter {

var translator = RenderNodeTranslator(
context: context,
bundle: bundle,
identifier: node.reference,
renderContext: renderContext,
emitSymbolSourceFileURIs: shouldEmitSymbolSourceFileURIs,
Expand Down
18 changes: 9 additions & 9 deletions Sources/SwiftDocC/Converter/DocumentationNodeConverter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,29 @@ 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.
/// - Parameters:
/// - 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
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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)

Expand All @@ -37,8 +37,8 @@ extension ConvertService {
}

return (
DocumentationBundle(
info: request.bundleInfo,
DocumentationContext.Inputs(
info: request.info,
symbolGraphURLs: symbolGraphURLs,
markupURLs: markupFileURL,
miscResourceURLs: request.miscResourceURLs
Expand Down
29 changes: 14 additions & 15 deletions Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand All @@ -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 {
Expand All @@ -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,
Expand Down Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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

Expand Down
Loading