Skip to content

Commit b623ee6

Browse files
committed
Decode the supported features for a given DocC executable
1 parent 0f7d4be commit b623ee6

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// This source file is part of the Swift.org open source project
2+
//
3+
// Copyright (c) 2024 Apple Inc. and the Swift project authors
4+
// Licensed under Apache License v2.0 with Runtime Library Exception
5+
//
6+
// See https://swift.org/LICENSE.txt for license information
7+
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
8+
9+
import Foundation
10+
11+
/// The features that a `docc` executable lists in its corresponding "features.json" file.
12+
///
13+
/// In a Swift toolchain, the `docc` executable is located at `usr/bin/docc` and the
14+
/// corresponding features file is located at `usr/share/docc/features.json`.
15+
///
16+
/// The "features.json" file is a list of named features. For example:
17+
///
18+
/// ```json
19+
/// {
20+
/// "features": [
21+
/// {
22+
/// "name": "diagnostics-file"
23+
/// },
24+
/// {
25+
/// "name": "dependency"
26+
/// },
27+
/// {
28+
/// "name": "overloads"
29+
/// }
30+
/// ]
31+
/// }
32+
/// ```
33+
struct DocCFeatures: Decodable {
34+
/// A single named feature that's supported for a given `docc` executable.
35+
struct Feature: Decodable, Hashable {
36+
var name: String
37+
}
38+
private var features: Set<Feature>
39+
40+
/// Decodes the DocC features that correspond to a given `docc` executable in a Swift toolchain.
41+
init(doccExecutable: URL) throws {
42+
let data = try Data(contentsOf: Self._featuresURL(forDoccExecutable: doccExecutable))
43+
self = try JSONDecoder().decode(DocCFeatures.self, from: data)
44+
}
45+
46+
/// Creates an empty list of supported DocC features.
47+
init() {
48+
features = []
49+
}
50+
51+
/// Returns the "features.json" file for a given `docc` executable in a Swift toolchain.
52+
static func _featuresURL(forDoccExecutable doccExecutable: URL) -> URL {
53+
doccExecutable
54+
.deletingLastPathComponent() // docc
55+
.deletingLastPathComponent() // bin
56+
.appendingPathComponent("share/docc/features.json")
57+
}
58+
}
59+
60+
extension DocCFeatures: Collection {
61+
typealias Index = Set<Feature>.Index
62+
typealias Element = Set<Feature>.Element
63+
64+
var startIndex: Index { features.startIndex }
65+
var endIndex: Index { features.endIndex }
66+
67+
subscript(index: Index) -> Iterator.Element {
68+
get { features[index] }
69+
}
70+
71+
func index(after i: Index) -> Index {
72+
return features.index(after: i)
73+
}
74+
}
75+
76+
// MARK: Known features
77+
78+
extension DocCFeatures.Feature {
79+
/// DocC supports writing diagnostic information to a JSON file, specified by `--diagnostics-output-path`.
80+
static let diagnosticsFileOutput = DocCFeatures.Feature(name: "diagnostics-file")
81+
82+
/// DocC supports linking between documentation builds and merging archives into a combined archive.
83+
static let linkDependencies = DocCFeatures.Feature(name: "dependency")
84+
85+
/// DocC supports grouping overloaded symbols.
86+
static let overloads = DocCFeatures.Feature(name: "overloads")
87+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// This source file is part of the Swift.org open source project
2+
//
3+
// Copyright (c) 2024 Apple Inc. and the Swift project authors
4+
// Licensed under Apache License v2.0 with Runtime Library Exception
5+
//
6+
// See https://swift.org/LICENSE.txt for license information
7+
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
8+
9+
import Foundation
10+
@testable import SwiftDocCPluginUtilities
11+
import XCTest
12+
13+
final class DocCFeaturesTests: XCTestCase {
14+
func testKnownFeatures() throws {
15+
let json = Data("""
16+
{
17+
"features": [
18+
{
19+
"name": "diagnostics-file"
20+
},
21+
{
22+
"name": "dependency"
23+
},
24+
{
25+
"name": "overloads"
26+
}
27+
]
28+
}
29+
""".utf8)
30+
let features = try JSONDecoder().decode(DocCFeatures.self, from: json)
31+
32+
XCTAssertEqual(features.count, 3)
33+
34+
XCTAssert(features.contains(.diagnosticsFileOutput))
35+
XCTAssert(features.contains(.overloads))
36+
XCTAssert(features.contains(.linkDependencies))
37+
38+
XCTAssertFalse(features.contains(.init(name: "some-unknown-feature")))
39+
}
40+
41+
func testUnknownFeatures() throws {
42+
let json = Data("""
43+
{
44+
"features": [
45+
{
46+
"name": "some-unknown-feature"
47+
}
48+
]
49+
}
50+
""".utf8)
51+
let features = try JSONDecoder().decode(DocCFeatures.self, from: json)
52+
53+
XCTAssertEqual(features.count, 1)
54+
55+
XCTAssert(features.contains(.init(name: "some-unknown-feature")))
56+
57+
XCTAssertFalse(features.contains(.diagnosticsFileOutput))
58+
XCTAssertFalse(features.contains(.overloads))
59+
XCTAssertFalse(features.contains(.linkDependencies))
60+
}
61+
62+
func testFeaturesURL() {
63+
XCTAssertEqual(
64+
DocCFeatures._featuresURL(forDoccExecutable: URL(fileURLWithPath: "/path/to/toolchain/usr/bin/docc")),
65+
URL(fileURLWithPath: "/path/to/toolchain/usr/share/docc/features.json")
66+
)
67+
}
68+
}

0 commit comments

Comments
 (0)