1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
|
/*
This source file is part of the Swift.org open source project
Copyright (c) 2021-2024 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
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
import Foundation
/// A rendering-friendly representation of a documentation node.
///
/// A render node contains all the data required for a renderer to display a topic's documentation. This includes the topic's
/// authored markup documentation, hierarchy information (the topic's curation), API availability, and more.
///
/// The fields of a render node are populated depending on the documentation page's type. For example, reference
/// documentation pages (i.e., symbols and articles) have their child topics listed in ``topicSections``, but for Tutorial pages,
/// that field is empty.
///
/// Information about external resources such as other documentation pages or media is stored in the ``references`` dictionary.
///
/// An OpenAPI specification for render node is available in the repo at `Sources/SwiftDocC/SwiftDocC.docc/Resources/RenderNode.spec.json`.
///
/// ### Versioning
///
/// The render node schema constantly evolves to support new documentation features. To help clients maintain compatibility,
/// we associate each schema with a version. See ``schemaVersion`` for more details.
///
/// ### Variants
///
/// Different variants of a documentation page can be represented by a single render node using the ``variantOverrides`` property.
/// This property holds overrides that clients should apply to the render JSON when processing documentation for specific programming languages. The overrides
/// are organized by traits (e.g., language) and it's up to the client to determine which trait is most appropriate for them. For example, a client that wants to
/// process the Objective-C version of documentation should apply the overrides associated with the `interfaceLanguage: objc` trait.
///
/// Use the ``RenderJSONEncoder/makeEncoder(prettyPrint:emitVariantOverrides:assetPrefixComponent:)`` API to instantiate a JSON encoder that's configured
/// to accumulate variant overrides and emit them to the ``variantOverrides`` property.
///
/// The overrides are emitted in the [JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902) format.
///
/// To apply variants onto a render node using `SwiftDocC`, use the ``RenderNodeVariantOverridesApplier`` API.
///
/// ## Topics
///
/// ### General
///
/// - ``schemaVersion``
/// - ``kind``
/// - ``sections``
/// - ``references``
/// - ``hierarchy``
/// - ``metadata``
///
/// ### Reference Documentation Data
///
/// Data specific for reference documentation nodes.
///
/// - ``abstract``
/// - ``primaryContentSections``
/// - ``topicSections``
/// - ``relationshipSections``
/// - ``defaultImplementationsSections``
/// - ``seeAlsoSections``
/// - ``deprecationSummary``
/// - ``variants``
/// - ``diffAvailability``
///
/// ### Multi-Language Reference Documentation Data
///
/// Data specific for reference documentation nodes that are available in multiple programming languages.
///
/// - ``abstractVariants``
/// - ``primaryContentSectionsVariants``
/// - ``topicSectionsVariants``
/// - ``relationshipSectionsVariants``
/// - ``defaultImplementationsSectionsVariants``
/// - ``seeAlsoSectionsVariants``
/// - ``deprecationSummaryVariants``
///
/// ### Sample Code Data
///
/// Data specific for sample code nodes.
///
/// - ``sampleDownload``
///
/// ### Models
///
/// - ``Variant``
public struct RenderNode: VariantContainer {
/// The current version of the render node schema.
///
/// The schema version describes the compatibility of a client with a render node value. Clients should be able to decode
/// render node values of the same major version, but are not guaranteed to be able to decode values of other major versions.
/// For example, a client that supports render node `2.5.0` should be able to process any render node of version greater than
/// or equal to `2.0.0` and less than `3.0.0` _with no regressions_, ignoring new fields in render nodes of version greater
/// than `2.5.0`.
///
/// The components should be incremented as follows:
/// - The _major_ component should be incremented when introducing a change that prevents clients from processing
/// older render node values, for example when creating a new required property.
/// - The _minor_ component should be incremented when introducing a change that's compatible with older values, for example
/// when creating a new optional property.
/// - The _pre-release_ component can be used during development to indicate a new version without incrementing the major or
/// minor components. When creating a DocC release, the render node version should not have a pre-release
/// component.
///
/// > Note: The patch value is currently unused and always set to `0`.
public var schemaVersion = SemanticVersion(
major: 0,
minor: 3,
patch: 0
)
/// The identifier of the render node.
///
/// The identifier of a render node is typically the same as the documentation node it's representing.
public var identifier: ResolvedTopicReference
/// The kind of this documentation node.
public var kind: Kind
/// The references used in the render node. These can be references to other nodes, media, and more.
///
/// The key for each reference is the ``RenderReferenceIdentifier/identifier`` of the reference's ``RenderReference/identifier``.
public var references: [String: RenderReference] = [:]
/// Hierarchy information about the context in which this documentation node is placed.
public var hierarchy: RenderHierarchy?
/// Arbitrary metadata information about the render node.
public var metadata = RenderMetadata()
// MARK: Reference documentation nodes
/// The default value for the abstract of the node, which provides a short overview of its contents.
public var abstract: [RenderInlineContent]? {
get { getVariantDefaultValue(keyPath: \.abstractVariants) }
set { setVariantDefaultValue(newValue, keyPath: \.abstractVariants) }
}
/// The variants of the abstract of the node, which provide a short overview of its contents.
public var abstractVariants: VariantCollection<[RenderInlineContent]?> = .init(defaultValue: nil)
/// The default value of the main sections of a reference documentation node.
public var primaryContentSections: [RenderSection] {
get { primaryContentSectionsVariants.compactMap(\.defaultValue?.section) }
set {
primaryContentSectionsVariants = newValue.enumerated().map { index, section in
let section = CodableContentSection(section)
if primaryContentSectionsVariants.indices.contains(index) {
var variantCollection = primaryContentSectionsVariants[index]
variantCollection.defaultValue = section
return variantCollection
} else {
return VariantCollection<CodableContentSection?>(defaultValue: section)
}
}
}
}
/// The variants of the primary content sections of the node, which are the main sections of a reference documentation node.
public var primaryContentSectionsVariants: [VariantCollection<CodableContentSection?>] = []
/// The visual style that should be used when rendering this page's Topics section.
public var topicSectionsStyle: TopicsSectionStyle
/// The default Topics sections of this documentation node, which contain links to useful related documentation nodes.
public var topicSections: [TaskGroupRenderSection] {
get { getVariantDefaultValue(keyPath: \.topicSectionsVariants) }
set { setVariantDefaultValue(newValue, keyPath: \.topicSectionsVariants) }
}
/// The variants for the Topics sections of this documentation node, which contain links to useful related documentation nodes.
public var topicSectionsVariants: VariantCollection<[TaskGroupRenderSection]> = .init(defaultValue: [])
/// The default Relationships sections of a reference documentation node, which describes how this symbol is related to others.
public var relationshipSections: [RelationshipsRenderSection] {
get { getVariantDefaultValue(keyPath: \.relationshipSectionsVariants) }
set { setVariantDefaultValue(newValue, keyPath: \.relationshipSectionsVariants) }
}
/// The variants of the Relationships sections of a reference documentation node, which describe how this symbol is related to others.
public var relationshipSectionsVariants: VariantCollection<[RelationshipsRenderSection]> = .init(defaultValue: [])
/// The default Default Implementations sections of symbol node, which list APIs that provide a default implementation of the symbol.
public var defaultImplementationsSections: [TaskGroupRenderSection] {
get { getVariantDefaultValue(keyPath: \.defaultImplementationsSectionsVariants) }
set { setVariantDefaultValue(newValue, keyPath: \.defaultImplementationsSectionsVariants) }
}
/// The variants of the Default Implementations sections of symbol node, which list APIs that provide a default implementation of the symbol.
public var defaultImplementationsSectionsVariants: VariantCollection<[TaskGroupRenderSection]> = .init(defaultValue: [])
/// The See Also sections of a node, which list documentation resources related to this documentation node.
public var seeAlsoSections: [TaskGroupRenderSection] {
get { getVariantDefaultValue(keyPath: \.seeAlsoSectionsVariants) }
set { setVariantDefaultValue(newValue, keyPath: \.seeAlsoSectionsVariants) }
}
/// The variants of the See Also sections of a node, which list documentation resources related to this documentation node.
public var seeAlsoSectionsVariants: VariantCollection<[TaskGroupRenderSection]> = .init(defaultValue: [])
/// A description of why this symbol is deprecated.
public var deprecationSummary: [RenderBlockContent]? {
get { getVariantDefaultValue(keyPath: \.deprecationSummaryVariants) }
set { setVariantDefaultValue(newValue, keyPath: \.deprecationSummaryVariants) }
}
/// The variants of the description of why this symbol is deprecated.
public var deprecationSummaryVariants: VariantCollection<[RenderBlockContent]?> = .init(defaultValue: nil)
/// List of variants of the same documentation node for various languages.
public var variants: [RenderNode.Variant]?
/// Language-specific overrides for documentation.
///
/// This property holds overrides that clients should apply to the render JSON when processing documentation for specific languages. The overrides are
/// organized by traits (e.g., language) and it's up to the client to determine which trait is most appropriate for them. For example, a client that wants to
/// process the Objective-C version of documentation should apply the overrides associated with the `interfaceLanguage: objc` trait.
///
/// The overrides are emitted in the [JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902) format.
public var variantOverrides: VariantOverrides?
/// Information about what API diffs are available for this symbol.
public var diffAvailability: DiffAvailability?
// MARK: Sample code nodes
/// Download information for sample code nodes.
public var sampleDownload: SampleDownloadSection?
/// Download not available information.
public var downloadNotAvailableSummary: [RenderBlockContent]?
/// Creates an instance given an identifier and a kind.
public init(identifier: ResolvedTopicReference, kind: Kind) {
self.identifier = identifier
self.kind = kind
self.topicSectionsStyle = .list
}
// MARK: Tutorials nodes
/// The sections of this node.
///
/// For tutorial pages, this property is the top-level grouping for the page's contents.
public var sections: [RenderSection] = []
/// The kind of content represented by this node.
public enum Kind: String, Codable {
case symbol
case article
case tutorial = "project"
case section
case overview
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
switch try container.decode(String.self) {
case "symbol":
self = .symbol
case "article":
self = .article
case "tutorial", "project":
self = .tutorial
case "section":
self = .section
case "overview":
self = .overview
case let unknown:
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Unknown RenderNode.Kind: '\(unknown)'.")
}
}
}
}
|