Skip to content

Commit 82a5a41

Browse files
committed
Add --include-extended-types flag
The --include-extended-types flag is transformed to the --emit-extension-block-symbols flag of the swift package dump-symbol-graph command. It is available starting from Swift 5.8.
1 parent 3e3305b commit 82a5a41

File tree

11 files changed

+221
-12
lines changed

11 files changed

+221
-12
lines changed

Plugins/SharedPackagePluginExtensions/PackageManager+getSymbolGraphsForDocC.swift

+4-2
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,14 @@ extension PackageManager {
3838
for target: SwiftSourceModuleTarget,
3939
context: PluginContext,
4040
verbose: Bool,
41-
snippetBuilder: SnippetBuilder?
41+
snippetBuilder: SnippetBuilder?,
42+
arguments: Arguments
4243
) throws -> DocCSymbolGraphResult {
4344
// First generate the primary symbol graphs containing information about the
4445
// symbols defined in the target itself.
4546

46-
let symbolGraphOptions = target.defaultSymbolGraphOptions(in: context.package)
47+
var symbolGraphOptions = target.defaultSymbolGraphOptions(in: context.package)
48+
symbolGraphOptions.override(with: arguments)
4749

4850
if verbose {
4951
print("symbol graph options: '\(symbolGraphOptions)'")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// This source file is part of the Swift.org open source project
2+
//
3+
// Copyright (c) 2022 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 PackagePlugin
10+
11+
extension PackageManager.SymbolGraphOptions {
12+
/// Overrides individual values in the `SymbolGraphOptions`
13+
/// according to the given `arguments`.
14+
mutating func override(with arguments: Arguments) {
15+
for argument in arguments {
16+
switch argument {
17+
case "--emit-extension-block-symbols":
18+
#if swift(>=5.8)
19+
self.emitExtensionBlocks = true
20+
#else
21+
print("warning: detected '--emit-extension-block-symbols' option, which is incompatible with your swift version (required: 5.8)")
22+
#endif
23+
default:
24+
print("warning: detected unknown dump-symbol-graph option '\(argument)'")
25+
}
26+
}
27+
}
28+
}

Plugins/SharedPackagePluginExtensions/Target+defaultSymbolGraphOptions.swift

+15-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,21 @@ extension SwiftSourceModuleTarget {
2727
return PackageManager.SymbolGraphOptions(
2828
minimumAccessLevel: targetMinimumAccessLevel,
2929
includeSynthesized: true,
30-
includeSPI: false
30+
includeSPI: false,
31+
emitExtensionBlocks: false
3132
)
3233
}
3334
}
35+
36+
37+
#if swift(<5.8)
38+
private extension PackageManager.SymbolGraphOptions {
39+
/// A copatibility layer for lower Swift versions which discards unknown parameters.
40+
init(minimumAccessLevel: PackagePlugin.PackageManager.SymbolGraphOptions.AccessLevel = .public,
41+
includeSynthesized: Bool = false,
42+
includeSPI: Bool = false,
43+
emitExtensionBlocks: Bool) {
44+
self.init(minimumAccessLevel: minimumAccessLevel, includeSynthesized: includeSynthesized, includeSPI: includeSPI)
45+
}
46+
}
47+
#endif

Plugins/Swift-DocC Convert/SwiftDocCConvert.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ import PackagePlugin
7070
for: target,
7171
context: context,
7272
verbose: verbose,
73-
snippetBuilder: snippetBuilder
73+
snippetBuilder: snippetBuilder,
74+
arguments: parsedArguments.dumpSymbolGraphArguments()
7475
)
7576

7677
if try FileManager.default.contentsOfDirectory(atPath: symbolGraphs.targetSymbolGraphsDirectory.path).isEmpty {

Plugins/Swift-DocC Preview/SwiftDocCPreview.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ import PackagePlugin
8383
for: target,
8484
context: context,
8585
verbose: verbose,
86-
snippetBuilder: snippetBuilder
86+
snippetBuilder: snippetBuilder,
87+
arguments: parsedArguments.dumpSymbolGraphArguments()
8788
)
8889

8990
if try FileManager.default.contentsOfDirectory(atPath: symbolGraphs.targetSymbolGraphsDirectory.path).isEmpty {

Sources/SwiftDocCPluginUtilities/HelpInformation.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,14 @@ public enum HelpInformation {
4343
helpText = previewPluginHelpOverview
4444
}
4545

46-
let supportedPluginFlags = [
46+
var supportedPluginFlags = [
4747
PluginFlag.disableIndex,
4848
]
4949

50+
#if swift(>=5.8)
51+
supportedPluginFlags += [PluginFlag.extendedTypes]
52+
#endif
53+
5054
for flag in supportedPluginFlags {
5155
helpText += """
5256
\(flag.parsedValues.sorted().joined(separator: ", "))

Sources/SwiftDocCPluginUtilities/ParsedArguments.swift

+64-4
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,25 @@ public struct ParsedArguments {
1919
return arguments.contains("--help") || arguments.contains("-h")
2020
}
2121

22+
/// Returns the arguments that could be passed to `swift package dump-symbol-graph`.
23+
///
24+
/// In practice, however we won't invoke the `dump-symbol-graph` command via the command line,
25+
/// but via the `PackagePlugin` API. Thus, these arguments have to be parsed later on and converted to
26+
/// `PackageManager.SymbolGraphOptions`.
27+
public func dumpSymbolGraphArguments() -> Arguments {
28+
var dumpSymbolGraphArguments = arguments.filter(for: .dumpSymbolGraph)
29+
30+
for argumentsTransformer in Self.argumentsTransformers {
31+
dumpSymbolGraphArguments = argumentsTransformer.transform(dumpSymbolGraphArguments)
32+
}
33+
34+
return dumpSymbolGraphArguments
35+
}
36+
2237
/// Returns the arguments that should be passed to `docc` to invoke the given plugin action.
2338
///
24-
/// Merges the arguments provided upon initialization of the parsed arguments
25-
/// with default fallback values for required options that were not provided.
39+
/// Merges the arguments provided upon initialization of the parsed arguments that are relevant
40+
/// to `docc` with default fallback values for required options that were not provided.
2641
///
2742
/// For example, if ParsedArguments is initialized like so:
2843
///
@@ -90,7 +105,7 @@ public struct ParsedArguments {
90105
symbolGraphDirectoryPath: String,
91106
outputPath: String
92107
) -> Arguments {
93-
var doccArguments = arguments
108+
var doccArguments = arguments.filter(for: .docc)
94109

95110
// Iterate through the flags required for the `docc` invocation
96111
// and append any that are not already present.
@@ -170,6 +185,51 @@ public struct ParsedArguments {
170185
]
171186

172187
private static let argumentsTransformers: [ArgumentsTransforming] = [
173-
PluginFlag.disableIndex
188+
PluginFlag.disableIndex,
189+
PluginFlag.extendedTypes
174190
]
175191
}
192+
193+
private extension ParsedArguments {
194+
enum ArgumentConsumer: CaseIterable {
195+
/// The `docc` command
196+
case docc
197+
/// The `swift package dump-symbol-graph` command
198+
case dumpSymbolGraph
199+
200+
/// Returns the flags applicable to an `ArgumentConsumer`.
201+
///
202+
/// If `flags` is `nil`, this `ArgumentConsumer` is assumed to
203+
/// consume all flags not consumed by any of the other `ArgumentConsumer`s.
204+
var flags: [PluginFlag]? {
205+
switch self {
206+
case .dumpSymbolGraph:
207+
return [
208+
PluginFlag.extendedTypes
209+
]
210+
case .docc:
211+
return nil
212+
}
213+
}
214+
}
215+
}
216+
217+
private extension Arguments {
218+
/// Returns the subset of arguments which are applicable to the given `consumer`.
219+
func filter(for consumer: ParsedArguments.ArgumentConsumer) -> Arguments {
220+
if let flagsToInclude = consumer.flags {
221+
return self.filter { argument in
222+
flagsToInclude.contains(where: { flag in
223+
flag.parsedValues.contains(argument)
224+
})
225+
}
226+
} else {
227+
let flagsToExclude = ParsedArguments.ArgumentConsumer.allCases.compactMap(\.flags).flatMap { $0 }
228+
return self.filter { argument in
229+
!flagsToExclude.contains(where: { flag in
230+
flag.parsedValues.contains(argument)
231+
})
232+
}
233+
}
234+
}
235+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// This source file is part of the Swift.org open source project
2+
//
3+
// Copyright (c) 2022 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+
extension PluginFlag {
10+
/// Include extended types in documentation archives.
11+
///
12+
/// Enables the extension block symbol format when calling the
13+
/// dump symbol graph API.
14+
///
15+
/// - Note: This flag is only available starting from Swift 5.8. It should
16+
/// be hidden from the `--help` command for lower toolchain versions.
17+
/// However, we do not hide the flag entirely, because this enables us to give
18+
/// a more precise warning when accidentally used with Swift 5.7 or lower.
19+
static let extendedTypes = PluginFlag(
20+
parsedValues: [
21+
"--include-extended-types",
22+
],
23+
abstract: "Include extended types from other modules in the produced DocC archive.",
24+
description: """
25+
Allows documenting symbols that a target adds to its dependencies.
26+
""",
27+
argumentTransformation: { $0 + ["--emit-extension-block-symbols"] }
28+
)
29+
}

Tests/SwiftDocCPluginUtilitiesTests/HelpInformationTests.swift

+12-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ final class HelpInformationTests: XCTestCase {
3939
--product <product> Generate documentation for the specified product.
4040
--disable-indexing, --no-indexing
4141
Disable indexing for the produced DocC archive.
42-
Produces a DocC archive that is best-suited for hosting online but incompatible with Xcode.
42+
Produces a DocC archive that is best-suited for hosting online but incompatible with Xcode.\(includeExtendedTypesSection)
4343
4444
DOCC OPTIONS:
4545
--platform <platform> Set the current release version of a platform.
@@ -128,7 +128,7 @@ final class HelpInformationTests: XCTestCase {
128128
--product <product> Preview documentation for the specified product.
129129
--disable-indexing, --no-indexing
130130
Disable indexing for the produced DocC archive.
131-
Produces a DocC archive that is best-suited for hosting online but incompatible with Xcode.
131+
Produces a DocC archive that is best-suited for hosting online but incompatible with Xcode.\(includeExtendedTypesSection)
132132
133133
DOCC OPTIONS:
134134
--platform <platform> Set the current release version of a platform.
@@ -184,3 +184,13 @@ final class HelpInformationTests: XCTestCase {
184184
}
185185
}
186186

187+
#if swift(>=5.8)
188+
private let includeExtendedTypesSection = """
189+
190+
--include-extended-types
191+
Include extended types from other modules in the produced DocC archive.
192+
Allows documenting symbols that a target adds to its dependencies.
193+
"""
194+
#else
195+
private let includeExtendedTypesSection = ""
196+
#endif

Tests/SwiftDocCPluginUtilitiesTests/ParsedArgumentsTests.swift

+29
Original file line numberDiff line numberDiff line change
@@ -442,4 +442,33 @@ final class ParsedArgumentsTests: XCTestCase {
442442
]
443443
)
444444
}
445+
446+
func testDocCArgumentsWithDumpSymbolGraphArguments() {
447+
let dumpSymbolGraphArguments = ParsedArguments(["--include-extended-types"])
448+
449+
let doccArguments = dumpSymbolGraphArguments.doccArguments(
450+
action: .convert,
451+
targetKind: .executable,
452+
doccCatalogPath: "/my/catalog.docc",
453+
targetName: "MyTarget",
454+
symbolGraphDirectoryPath: "/my/symbol-graph",
455+
outputPath: "/my/output-path"
456+
)
457+
458+
XCTAssertFalse(doccArguments.contains("--include-extended-types"))
459+
XCTAssertFalse(doccArguments.contains("--emit-extension-block-symbols"))
460+
}
461+
462+
func testDumpSymbolGraphArguments() {
463+
let dumpSymbolGraphArguments = ParsedArguments(["--include-extended-types"])
464+
465+
XCTAssertEqual(dumpSymbolGraphArguments.dumpSymbolGraphArguments(), ["--emit-extension-block-symbols"])
466+
}
467+
468+
func testDumpSymbolGraphArgumentsWithDocCArguments() {
469+
let dumpSymbolGraphArguments = ParsedArguments(["--fallback-default-module-kind", "Executable"])
470+
471+
472+
XCTAssertTrue(dumpSymbolGraphArguments.dumpSymbolGraphArguments().isEmpty)
473+
}
445474
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// This source file is part of the Swift.org open source project
2+
//
3+
// Copyright (c) 2022 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 ExtendedTypesFlagTests: XCTestCase {
14+
func testReplacesIncludeExtendedTypesFlagWhenPresent() {
15+
XCTAssertEqual(
16+
PluginFlag.extendedTypes.transform(
17+
["--include-extended-types", "--other-flag"]
18+
),
19+
["--other-flag", "--emit-extension-block-symbols"]
20+
)
21+
}
22+
23+
func testDoesNotAddEmitExtensionBlockSymbolsFlagWhenAbsent() {
24+
XCTAssertEqual(
25+
PluginFlag.extendedTypes.transform(
26+
["--other-flag"]
27+
),
28+
["--other-flag"]
29+
)
30+
}
31+
}

0 commit comments

Comments
 (0)