Skip to content

Commit 8cba153

Browse files
RenderNodeTranslator.visitSymbol filters out availability items with a missing domain (#1256)
RenderNodeTranslator.visitSymbol filters out availability items which have a missing or invalid domain (platform name). Swift developers can add global availability messages with no specific platform information, for example like this: @available(*, deprecated, message: """ Don't use this function; call some other function instead. """ ) In this scenario, the Swift compiler adds an availability item with the message but no domain (platform name) to the symbol graph file, like this: { "domain": null, "isUnconditionallyDeprecated": true, "message": "Don't use this function; call some other function instead." } To avoid displaying an empty/null platform in the DocC Render user interface, the RenderNodeTranslator needs to filter out these records. Additionally, AvailabilityRenderOrder.compare always returns false for availability items that have no name, leading to an unpredictable sort order when any of the items is missing a platform name, even for availability items that had a valid platform name.
1 parent 1b4a185 commit 8cba153

File tree

3 files changed

+50
-7
lines changed

3 files changed

+50
-7
lines changed

Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,13 +1257,14 @@ public struct RenderNodeTranslator: SemanticVisitor {
12571257
if availability.obsoletedVersion != nil {
12581258
return nil
12591259
}
1260-
guard let name = availability.domain.map({ PlatformName(operatingSystemName: $0.rawValue) }),
1261-
let currentPlatform = context.configuration.externalMetadata.currentPlatforms?[name.displayName]
1262-
else {
1260+
// Filter out this availability item if it has a missing or invalid domain.
1261+
guard let name = availability.domain.map({ PlatformName(operatingSystemName: $0.rawValue) }) else {
1262+
return nil
1263+
}
1264+
guard let currentPlatform = context.configuration.externalMetadata.currentPlatforms?[name.displayName] else {
12631265
// No current platform provided by the context
12641266
return AvailabilityRenderItem(availability, current: nil)
12651267
}
1266-
12671268
return AvailabilityRenderItem(availability, current: currentPlatform)
12681269
}
12691270
.filter { $0.unconditionallyUnavailable != true }

Tests/SwiftDocCTests/Rendering/AvailabilityRenderOrderTests.swift

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
import Foundation
12+
import SymbolKit
1213
import XCTest
1314
@testable import SwiftDocC
1415

@@ -18,7 +19,47 @@ class AvailabilityRenderOrderTests: XCTestCase {
1819

1920
func testSortingAtRenderTime() throws {
2021
let (bundleURL, bundle, context) = try testBundleAndContext(copying: "LegacyBundle_DoNotUseInNewTests", excludingPaths: []) { url in
21-
try? FileManager.default.copyItem(at: self.availabilitySGFURL, to: url.appendingPathComponent("Availability.symbols.json"))
22+
let availabilitySymbolGraphURL = url.appendingPathComponent("Availability.symbols.json")
23+
try? FileManager.default.copyItem(at: self.availabilitySGFURL, to: availabilitySymbolGraphURL)
24+
25+
// Load the symbol graph fixture
26+
var availabilitySymbolGraph = try JSONDecoder().decode(SymbolGraph.self, from: try Data(contentsOf: availabilitySymbolGraphURL))
27+
28+
// There should be at least one symbol in this graph
29+
XCTAssertEqual(1, availabilitySymbolGraph.symbols.count)
30+
if let tuple = availabilitySymbolGraph.symbols.first {
31+
32+
let key = tuple.key
33+
var symbol = tuple.value
34+
35+
// The symbol should have availability info specified
36+
XCTAssertNotNil(symbol.availability)
37+
if var alternateSymbols = symbol.mixins[Availability.mixinKey] as? Availability {
38+
39+
// Create a new availability item which is missing a domain (platform name).
40+
let missingDomain = SymbolGraph.Symbol.Availability.AvailabilityItem(
41+
domain: nil,
42+
introducedVersion: nil,
43+
deprecatedVersion: nil,
44+
obsoletedVersion: nil,
45+
message: "Don't use this function; call some other function instead.",
46+
renamed: nil,
47+
isUnconditionallyDeprecated: true,
48+
isUnconditionallyUnavailable: false,
49+
willEventuallyBeDeprecated: false
50+
)
51+
52+
// Append the invalid item and update the symbol
53+
alternateSymbols.availability.insert(missingDomain, at: 4)
54+
symbol.mixins[Availability.mixinKey] = alternateSymbols
55+
}
56+
availabilitySymbolGraph.symbols[key] = symbol
57+
}
58+
59+
// Update the temporary copy of the fixture
60+
let jsonEncoder = JSONEncoder()
61+
let data = try jsonEncoder.encode(availabilitySymbolGraph)
62+
try data.write(to: availabilitySymbolGraphURL)
2263
}
2364
defer {
2465
try? FileManager.default.removeItem(at: bundleURL)
@@ -32,6 +73,7 @@ class AvailabilityRenderOrderTests: XCTestCase {
3273
// Verify that all the symbol's availabilities were sorted into the order
3374
// they need to appear for rendering (they are not in the symbol graph fixture).
3475
// Additionally verify all the platforms have their correctly spelled name including spaces.
76+
// Finally, the invalid item added above should be filtered out.
3577
XCTAssertEqual(renderNode.metadata.platforms?.map({ "\($0.name ?? "") \($0.introduced ?? "")" }), [
3678
"iOS 12.0", "iOS App Extension 12.0",
3779
"iPadOS 12.0",

Tests/SwiftDocCTests/Rendering/RenderNodeTranslatorSymbolVariantsTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ class RenderNodeTranslatorSymbolVariantsTests: XCTestCase {
147147
configureSymbol: { symbol in
148148
symbol.availabilityVariants[.swift] = SymbolGraph.Symbol.Availability(availability: [
149149
SymbolGraph.Symbol.Availability.AvailabilityItem(
150-
domain: nil,
150+
domain: .init(rawValue: "iOS"),
151151
introducedVersion: SymbolGraph.SemanticVersion(string: "1.0"),
152152
deprecatedVersion: nil,
153153
obsoletedVersion: nil,
@@ -161,7 +161,7 @@ class RenderNodeTranslatorSymbolVariantsTests: XCTestCase {
161161

162162
symbol.availabilityVariants[.objectiveC] = SymbolGraph.Symbol.Availability(availability: [
163163
SymbolGraph.Symbol.Availability.AvailabilityItem(
164-
domain: nil,
164+
domain: .init(rawValue: "iOS"),
165165
introducedVersion: SymbolGraph.SemanticVersion(string: "2.0"),
166166
deprecatedVersion: nil,
167167
obsoletedVersion: nil,

0 commit comments

Comments
 (0)