Skip to content

Commit 5d68ace

Browse files
Add a helper function for rendering a returns sections as HTML (#1381)
* Add a helper function for rendering a returns sections as HTML rdar://163326857 * Minor phrasing updates to the parameter section helper's documentation * Add new source file to Windows CMake file list * Correct grammar in documentation comments Co-authored-by: Pat Shaughnessy <pat_shaughnessy@apple.com> --------- Co-authored-by: Pat Shaughnessy <pat_shaughnessy@apple.com>
1 parent f561a86 commit 5d68ace

File tree

4 files changed

+115
-2
lines changed

4 files changed

+115
-2
lines changed

Sources/DocCHTML/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ add_library(DocCHTML STATIC
1212
MarkdownRenderer+Availability.swift
1313
MarkdownRenderer+Breadcrumbs.swift
1414
MarkdownRenderer+Parameters.swift
15+
MarkdownRenderer+Returns.swift
1516
MarkdownRenderer.swift
1617
WordBreak.swift
1718
XMLNode+element.swift)

Sources/DocCHTML/MarkdownRenderer+Parameters.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ package extension MarkdownRenderer {
3434

3535
/// Creates a "parameters" section that describes all the parameters for a symbol.
3636
///
37-
/// If each language representation of the API has their own language-specific parameters, pass each language representation's parameter information.
37+
/// If each language representation of the symbol has its own language-specific parameters, pass the parameter information for all language representations.
3838
///
39-
/// If the API has the _same_ parameters in all language representations, only pass the parameters for one language.
39+
/// If all language representations of the symbol have the _same_ parameters, only pass the parameter information for one language.
4040
/// This produces a "parameters" section that doesn't hide any parameters for any of the languages (same as if the symbol only had one language representation)
4141
func parameters(_ info: [SourceLanguage: [ParameterInfo]]) -> [XMLNode] {
4242
let info = RenderHelpers.sortedLanguageSpecificValues(info)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2025 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See https://swift.org/LICENSE.txt for license information
8+
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
#if canImport(FoundationXML)
12+
// TODO: Consider other HTML rendering options as a future improvement (rdar://165755530)
13+
package import FoundationXML
14+
#else
15+
package import Foundation
16+
#endif
17+
18+
package import Markdown
19+
package import DocCCommon
20+
21+
package extension MarkdownRenderer {
22+
/// Creates a "returns" section that describes all return values of a symbol.
23+
///
24+
/// If each language representation of the symbol has its own language-specific return values, pass the return value content for all language representations.
25+
///
26+
/// If all language representations of the symbol have the _same_ return value, only pass the return value content for one language.
27+
/// This produces a "returns" section that doesn't hide the return value content for any of the languages (same as if the symbol only had one language representation)
28+
func returns(_ languageSpecificSections: [SourceLanguage: [any Markup]]) -> [XMLNode] {
29+
let info = RenderHelpers.sortedLanguageSpecificValues(languageSpecificSections)
30+
let items: [XMLNode] = if info.count == 1 {
31+
info.first!.value.map { visit($0) }
32+
} else {
33+
info.flatMap { language, content in
34+
let attributes = ["class": "\(language.id)-only"]
35+
// Most return sections only have 1 paragraph of content with 2 and 3 paragraphs being increasingly uncommon.
36+
// Avoid wrapping that content in a `<div>` or other container element and instead add the language specific class attribute to each paragraph.
37+
return content.map { markup in
38+
let node = visit(markup)
39+
if let element = node as? XMLElement {
40+
element.addAttributes(attributes)
41+
return element
42+
} else {
43+
// Any text _should_ already be contained in a markdown paragraph, but if the input is unexpected, wrap the raw text in a paragraph here.
44+
return .element(named: "p", children: [node], attributes: attributes)
45+
}
46+
}
47+
}
48+
}
49+
50+
return selfReferencingSection(named: "Return Value", content: items)
51+
}
52+
}

Tests/DocCHTMLTests/MarkdownRenderer+PageElementsTests.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,66 @@ struct MarkdownRenderer_PageElementsTests {
269269
""")
270270
}
271271

272+
@Test(arguments: RenderGoal.allCases)
273+
func testRenderSingleLanguageReturnSections(goal: RenderGoal) {
274+
let returns = makeRenderer(goal: goal).returns([
275+
.swift: parseMarkup(string: "First paragraph\n\nSecond paragraph")
276+
])
277+
278+
let commonHTML = """
279+
<p>First paragraph</p>
280+
<p>Second paragraph</p>
281+
"""
282+
283+
switch goal {
284+
case .richness:
285+
returns.assertMatches(prettyFormatted: true, expectedXMLString: """
286+
<section id="Return-Value">
287+
<h2>
288+
<a href="#Return-Value">Return Value</a>
289+
</h2>
290+
\(commonHTML)
291+
</section>
292+
""")
293+
case .conciseness:
294+
returns.assertMatches(prettyFormatted: true, expectedXMLString: """
295+
<h2>Return Value</h2>
296+
\(commonHTML)
297+
""")
298+
}
299+
}
300+
301+
@Test(arguments: RenderGoal.allCases)
302+
func testRenderLanguageSpecificReturnSections(goal: RenderGoal) {
303+
let returns = makeRenderer(goal: goal).returns([
304+
.swift: parseMarkup(string: "First paragraph\n\nSecond paragraph"),
305+
.objectiveC: parseMarkup(string: "Other language's paragraph"),
306+
])
307+
308+
let commonHTML = """
309+
<p class="swift-only">First paragraph</p>
310+
<p class="swift-only">Second paragraph</p>
311+
<p class="occ-only">Other language’s paragraph</p>
312+
"""
313+
314+
switch goal {
315+
case .richness:
316+
returns.assertMatches(prettyFormatted: true, expectedXMLString: """
317+
<section id="Return-Value">
318+
<h2>
319+
<a href="#Return-Value">Return Value</a>
320+
</h2>
321+
\(commonHTML)
322+
</section>
323+
""")
324+
case .conciseness:
325+
returns.assertMatches(prettyFormatted: true, expectedXMLString: """
326+
<h2>Return Value</h2>
327+
\(commonHTML)
328+
""")
329+
}
330+
}
331+
272332
// MARK: -
273333

274334
private func makeRenderer(

0 commit comments

Comments
 (0)