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
Expand Up @@ -68,7 +68,7 @@ extension RenderBlockContent.Paragraph {

extension RenderBlockContent.Aside {
func capitalizingFirstWord() -> RenderBlockContent.Aside {
return .init(style: self.style, content: self.content.capitalizingFirstWord())
return .init(style: self.style, name: self.name, content: self.content.capitalizingFirstWord())
}
}

Expand Down
148 changes: 104 additions & 44 deletions Sources/SwiftDocC/Model/Rendering/Content/RenderBlockContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,86 @@ public enum RenderBlockContent: Equatable {
}

/// An aside block.
public struct Aside: Equatable {
public struct Aside: Codable, Equatable {

/// The style of this aside block.
public var style: AsideStyle

/// The name of this aside block.
public var name: String

/// The content inside this aside block.
public var content: [RenderBlockContent]

/// Create an aside from an aside style. Use the capitalized style
/// as the name.
/// - Parameters:
/// - style: The style of this aside
/// - content: The block content to display in the aside
public init(style: AsideStyle, content: [RenderBlockContent]) {
self.style = style
self.name = style.displayName
self.content = content
}

/// Create an aside from a name.
/// - Parameters:
/// - name: The name of the aside.
/// - content: The block content to display in the aside
/// > Note:
/// > If the name doesn't match a style supported by DocC Render, set the style to "note".
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding these comments!

public init(name: String, content: [RenderBlockContent]) {
self.style = .init(rawValue: name)
self.name = name
self.content = content
}

/// Create an aside from both an aside style and a name.
/// - Parameters:
/// - style: The style of the aside
/// - name: The name of the aside
/// - content: The block content to display in the aside
public init(style: AsideStyle, name: String, content: [RenderBlockContent]) {
self.style = style
self.name = name
self.content = content
}

/// Create an aside from a markdown aside kind.
/// - Parameters:
/// - asideKind: The Swift Markdown aside kind
/// - content: The block content to display in the aside
///
/// For known values, use the Swift Markdown aside kind's display
/// name for this aside's name. For other values, use the capitalized kind
/// as the name.
public init(asideKind: Markdown.Aside.Kind, content: [RenderBlockContent]) {

// Determine which name to use for this aside:
// 1. If the provided kind case-insensitive matches one of the known Swift Markdown
// aside kinds, then use the matching kind's display name.
// 2. If any character is upper-cased, assume the content has specific casing and
// return the raw value.
// 3. Otherwise use the capitalized kind that was provided.
let name: String
if let knownDisplayName = Self.knownDisplayNames[asideKind.rawValue.lowercased()] {
name = knownDisplayName
} else if asideKind.rawValue.contains(where: \.isUppercase) {
name = asideKind.rawValue
} else {
name = asideKind.rawValue.capitalized
}

self.init(
style: .init(asideKind: asideKind),
name: name,
content: content
)
}

private static let knownDisplayNames: [String: String] = Dictionary(
uniqueKeysWithValues: Markdown.Aside.Kind.allCases.map { ($0.rawValue.lowercased(), $0.displayName) }
)
}

/// A block of sample code.
Expand Down Expand Up @@ -515,10 +584,7 @@ public enum RenderBlockContent: Equatable {

/// A type the describes an aside style.
public struct AsideStyle: Codable, Equatable {
private static let knownDisplayNames: [String: String] = Dictionary(
uniqueKeysWithValues: Markdown.Aside.Kind.allCases.map { ($0.rawValue.lowercased(), $0.displayName) }
)


/// Returns a Boolean value indicating whether two aside styles are equal.
///
/// The comparison uses ``rawValue`` and is case-insensitive.
Expand All @@ -529,29 +595,23 @@ public enum RenderBlockContent: Equatable {
public static func ==(lhs: AsideStyle, rhs: AsideStyle) -> Bool {
lhs.rawValue.caseInsensitiveCompare(rhs.rawValue) == .orderedSame
}

/// The underlying raw string value.
public var rawValue: String

/// The heading text to use when rendering this style of aside.
public var displayName: String {
if let value = Self.knownDisplayNames[rawValue.lowercased()] {
return value
} else if rawValue.contains(where: \.isUppercase) {
// If any character is upper-cased, assume the content has
// specific casing and return the raw value.
return rawValue
} else {
return rawValue.capitalized
}
return rawValue.capitalized
}

/// The style of aside to use when rendering.
///
/// DocC Render currently has five styles of asides: Note, Tip, Experiment, Important, and Warning. Asides
/// of these styles can emit their own style into the output, but other styles need to be rendered as one of
/// these five styles. This property maps aside styles to the render style used in the output.
var renderKind: String {
/// Create an aside style.
/// - Parameters:
/// - rawValue: The name of the style to use.
/// > Note:
/// > If the style isn't supported by DocC Render (one of
/// > note, tip, experiment, important, or warning) coerce the
/// > new style to be "note".
public init(rawValue: String) {
switch rawValue.lowercased() {
case let lowercasedRawValue
where [
Expand All @@ -560,40 +620,38 @@ public enum RenderBlockContent: Equatable {
"experiment",
"tip"
].contains(lowercasedRawValue):
return lowercasedRawValue
self.rawValue = lowercasedRawValue
default:
return "note"
self.rawValue = "note"
}
}

/// Creates an aside type for the specified aside kind.
/// - Parameter asideKind: The aside kind that provides the display name.
/// Create an aside style from a Swift Markdown aside kind.
/// - Parameters:
/// - asideKind: The Swift Markdown aside kind
/// > Note:
/// > If the style isn't supported by DocC Render (one of
/// > note, tip, experiment, important, and warning) coerce the
/// > new style to be "note".
public init(asideKind: Markdown.Aside.Kind) {
self.rawValue = asideKind.rawValue
}

/// Creates an aside style for the specified raw value.
/// - Parameter rawValue: The heading text to use when rendering this style of aside.
public init(rawValue: String) {
self.rawValue = rawValue
self.init(rawValue: asideKind.rawValue)
}

/// Creates an aside style with the specified display name.
/// - Parameter displayName: The heading text to use when rendering this style of aside.
@available(*, deprecated, message: "Use Aside.init(style:, name:, content:) instead. This deprecated API will be removed after 6.4 is released.")
public init(displayName: String) {
self.rawValue = Self.knownDisplayNames.first(where: { $0.value == displayName })?.key ?? displayName
self.init(rawValue: displayName)
}

/// Encodes the aside style into the specified encoder.
/// - Parameter encoder: The encoder to write data to.
public func encode(to encoder: any Encoder) throws {
// For backwards compatibility, encode only the display name and
// not a key-value pair.
var container = encoder.singleValueContainer()
try container.encode(rawValue)
}

/// Creates an aside style by decoding the specified decoder.
/// Creates an aside style by decoding with the specified decoder.
/// - Parameter decoder: The decoder to read data from.
public init(from decoder: any Decoder) throws {
let container = try decoder.singleValueContainer()
Expand Down Expand Up @@ -930,11 +988,13 @@ extension RenderBlockContent: Codable {
case .paragraph:
self = try .paragraph(.init(inlineContent: container.decode([RenderInlineContent].self, forKey: .inlineContent)))
case .aside:
var style = try container.decode(AsideStyle.self, forKey: .style)
if let displayName = try container.decodeIfPresent(String.self, forKey: .name) {
style = AsideStyle(displayName: displayName)
}
self = try .aside(.init(style: style, content: container.decode([RenderBlockContent].self, forKey: .content)))
self = try .aside(
.init(
style: try container.decode(AsideStyle.self, forKey: .style),
name: try container.decode(String.self, forKey: .name),
content: container.decode([RenderBlockContent].self, forKey: .content)
)
)
case .codeListing:
let copy = FeatureFlags.current.isExperimentalCodeBlockAnnotationsEnabled
let options: CodeBlockOptions?
Expand Down Expand Up @@ -1049,8 +1109,8 @@ extension RenderBlockContent: Codable {
case .paragraph(let p):
try container.encode(p.inlineContent, forKey: .inlineContent)
case .aside(let a):
try container.encode(a.style.renderKind, forKey: .style)
try container.encode(a.style.displayName, forKey: .name)
try container.encode(a.style, forKey: .style)
try container.encode(a.name, forKey: .name)
try container.encode(a.content, forKey: .content)
case .codeListing(let l):
try container.encode(l.syntax, forKey: .syntax)
Expand Down
15 changes: 9 additions & 6 deletions Sources/SwiftDocC/Model/Rendering/RenderContentCompiler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ struct RenderContentCompiler: MarkupVisitor {
let aside = Aside(blockQuote)

let newAside = RenderBlockContent.Aside(
style: RenderBlockContent.AsideStyle(asideKind: aside.kind),
asideKind: aside.kind,
content: aside.content.reduce(into: [], { result, child in result.append(contentsOf: visit(child))}) as! [RenderBlockContent]
)

return [RenderBlockContent.aside(newAside.capitalizingFirstWord())]
}

Expand Down Expand Up @@ -389,10 +389,13 @@ struct RenderContentCompiler: MarkupVisitor {
fatalError("Unexpected content type in note: \(type(of: $0))")
}
}
return [RenderBlockContent.aside(.init(
style: .init(asideKind: .note),
content: content
))]
let aside = RenderBlockContent.aside(
.init(
asideKind: .note,
content: content
)
)
return [aside]
}

mutating func visitThematicBreak(_ thematicBreak: ThematicBreak) -> [any RenderContent] {
Expand Down
Loading