From 013ebb983b7cdd996c16d20e8690d4baa444b21a Mon Sep 17 00:00:00 2001 From: Maic Lopez Saenz Date: Wed, 24 Jun 2026 21:22:16 -0700 Subject: [PATCH 1/3] =?UTF-8?q?add=20=E2=80=94json-prettyprint=20argument?= =?UTF-8?q?=20to=20plugins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the jsonPrettyPrint argument flat to both plugins, used in the command line through `--json-prettyprint`. This flag adds an the `DOCC_JSON_PRETTYPRINT` variable to the docc process environment, enabling prettyprinting of json files. This environment value is mentioned in https://github.com/swiftlang/swift-docc/blob/main/CONTRIBUTING.md --- .../Swift-DocC Convert/SwiftDocCConvert.swift | 34 +++++++++++++++---- .../Swift-DocC Preview/SwiftDocCPreview.swift | 12 ++++--- .../ParsedPluginArguments.swift | 2 ++ .../DocumentedArgument.swift | 10 ++++++ .../HelpInformation.swift | 1 + .../ParsedArguments.swift | 14 ++++++++ 6 files changed, 62 insertions(+), 11 deletions(-) diff --git a/Plugins/Swift-DocC Convert/SwiftDocCConvert.swift b/Plugins/Swift-DocC Convert/SwiftDocCConvert.swift index db5ba3a..d7664da 100644 --- a/Plugins/Swift-DocC Convert/SwiftDocCConvert.swift +++ b/Plugins/Swift-DocC Convert/SwiftDocCConvert.swift @@ -64,7 +64,18 @@ import PackagePlugin let intermediateArchivesDirectory = URL(fileURLWithPath: context.pluginWorkDirectory.appending("intermediates").string) try? FileManager.default.createDirectory(at: intermediateArchivesDirectory, withIntermediateDirectories: true) - + + // An inner function that configures the process running docc executable with the given + // process and environment values. + func configureDoccProcess(arguments: [String], environment: [String: String]) -> Process { + let process = Process() + process.executableURL = doccExecutableURL + process.arguments = arguments + process.environment = ProcessInfo.processInfo.environment + .merging(environment) { _, new in new } + return process + } + // An inner function that defines the work to build documentation for a given target. func performBuildTask(_ task: DocumentationBuildGraph.Task) throws -> URL? { let target = task.target @@ -128,16 +139,20 @@ import PackagePlugin dependencyArchivePaths: dependencyArchivePaths ) + let doccEnvironment = parsedArguments.doccEnvironment() + if verbose { let arguments = doccArguments.joined(separator: " ") print("docc invocation: '\(doccExecutableURL.path) \(arguments)'") + print("add'l environment: '\(doccEnvironment)'") } - + print("Building documentation for '\(target.name)'...") let conversionStartTime = DispatchTime.now() // Run `docc convert` with the generated arguments and wait until the process completes - let process = try Process.run(doccExecutableURL, arguments: doccArguments) + let process = configureDoccProcess(arguments: doccArguments, environment: doccEnvironment) + try process.run() process.waitUntilExit() // Check whether the `docc convert` invocation was successful. @@ -221,14 +236,19 @@ import PackagePlugin // Remove the combined archive if it already exists try? FileManager.default.removeItem(at: combinedArchiveOutput) - + + let remainingArguments = mergeCommandArguments.remainingArguments + let doccEnvironment = parsedArguments.doccEnvironment() + if verbose { - let arguments = mergeCommandArguments.remainingArguments.joined(separator: " ") + let arguments = remainingArguments.joined(separator: " ") print("docc invocation: '\(doccExecutableURL.path) \(arguments)'") + print("add'l environment: '\(doccEnvironment)'") } - + // Create a new combined archive - let process = try Process.run(doccExecutableURL, arguments: mergeCommandArguments.remainingArguments) + let process = configureDoccProcess(arguments: remainingArguments, environment: doccEnvironment) + try process.run() process.waitUntilExit() print(""" diff --git a/Plugins/Swift-DocC Preview/SwiftDocCPreview.swift b/Plugins/Swift-DocC Preview/SwiftDocCPreview.swift index 3aa9c15..fd089b5 100644 --- a/Plugins/Swift-DocC Preview/SwiftDocCPreview.swift +++ b/Plugins/Swift-DocC Preview/SwiftDocCPreview.swift @@ -115,18 +115,22 @@ import PackagePlugin symbolGraphDirectoryPath: symbolGraphs.unifiedSymbolGraphsDirectory.path, outputPath: parsedArguments.outputDirectory?.path ?? target.doccArchiveOutputPath(in: context) ) - + + let doccEnvironment = parsedArguments.doccEnvironment() + if verbose { let arguments = doccArguments.joined(separator: " ") print("docc invocation: '\(doccExecutableURL.path) \(arguments)'") + print("add'l environment: '\(doccEnvironment)'") } - // Configure the `docc preview` process with the generated arguments + // Configure the `docc preview` process with the generated arguments and environment. let previewProcess = Process() previewProcess.executableURL = doccExecutableURL previewProcess.arguments = doccArguments - - + previewProcess.environment = ProcessInfo.processInfo.environment + .merging(doccEnvironment) { _, new in new } + func stopPreviewProcess() { #if canImport(Darwin) previewProcess.interrupt() diff --git a/Sources/SwiftDocCPluginUtilities/CommandLineArguments/ParsedPluginArguments.swift b/Sources/SwiftDocCPluginUtilities/CommandLineArguments/ParsedPluginArguments.swift index 962c397..a391bc4 100644 --- a/Sources/SwiftDocCPluginUtilities/CommandLineArguments/ParsedPluginArguments.swift +++ b/Sources/SwiftDocCPluginUtilities/CommandLineArguments/ParsedPluginArguments.swift @@ -12,6 +12,7 @@ import Foundation struct ParsedPluginArguments { var enableCombinedDocumentation: Bool var disableLMDBIndex: Bool + var jsonPrettyPrint: Bool var verbose: Bool var help: Bool @@ -19,6 +20,7 @@ struct ParsedPluginArguments { init(extractingFrom arguments: inout CommandLineArguments) { enableCombinedDocumentation = arguments.extractFlag(.enableCombinedDocumentation) ?? false disableLMDBIndex = arguments.extractFlag(.disableLMDBIndex) ?? false + jsonPrettyPrint = arguments.extractFlag(.jsonPrettyPrint) ?? false verbose = arguments.extractFlag(.verbose) ?? false help = arguments.extract(Self.help).last ?? false } diff --git a/Sources/SwiftDocCPluginUtilities/DocumentedPluginFlags/DocumentedArgument.swift b/Sources/SwiftDocCPluginUtilities/DocumentedPluginFlags/DocumentedArgument.swift index 0d1efcc..01e815b 100644 --- a/Sources/SwiftDocCPluginUtilities/DocumentedPluginFlags/DocumentedArgument.swift +++ b/Sources/SwiftDocCPluginUtilities/DocumentedPluginFlags/DocumentedArgument.swift @@ -72,6 +72,16 @@ extension DocumentedArgument { """ ) + /// A plugin feature flag to enable pretty-printed and sorted JSON output. + static let jsonPrettyPrint = Self( + flag: .init(preferred: "--json-prettyprint"), + abstract: "Pretty-print the JSON output of the documentation archive.", + discussion: """ + Formats the JSON files in the documentation archive with spacing, indentation, and sorted \ + keys for a deterministic output. + """ + ) + /// A plugin feature flag to enable verbose logging. static let verbose = Self( flag: .init(preferred: "--verbose"), diff --git a/Sources/SwiftDocCPluginUtilities/HelpInformation.swift b/Sources/SwiftDocCPluginUtilities/HelpInformation.swift index 83087c0..3a9f0a7 100644 --- a/Sources/SwiftDocCPluginUtilities/HelpInformation.swift +++ b/Sources/SwiftDocCPluginUtilities/HelpInformation.swift @@ -45,6 +45,7 @@ public enum HelpInformation { var supportedPluginFlags = [ DocumentedArgument.disableLMDBIndex, + DocumentedArgument.jsonPrettyPrint, DocumentedArgument.verbose, ] diff --git a/Sources/SwiftDocCPluginUtilities/ParsedArguments.swift b/Sources/SwiftDocCPluginUtilities/ParsedArguments.swift index a76e5f3..2ed07e5 100644 --- a/Sources/SwiftDocCPluginUtilities/ParsedArguments.swift +++ b/Sources/SwiftDocCPluginUtilities/ParsedArguments.swift @@ -134,6 +134,20 @@ struct ParsedArguments { return [action.rawValue] + arguments.remainingArguments } + + + /// Returns the enviroment values that should be set in the `docc` process. + /// + /// The returned dictionary contains settings for the `docc` executable that are configured + /// through the process environment, instead of command-line arguments. Merge the values in the + /// dictionary to the process environment running the `docc` executable. + func doccEnvironment() -> [String: String] { + var environment: [String: String] = [:] + if pluginArguments.jsonPrettyPrint { + environment["DOCC_JSON_PRETTYPRINT"] = "YES" + } + return environment + } } enum DocCArguments { From 680a4567edce190df6896d3111bbcdb736b4d862 Mon Sep 17 00:00:00 2001 From: Maic Lopez Saenz Date: Wed, 24 Jun 2026 22:30:04 -0700 Subject: [PATCH 2/3] update help information tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit with the help output for `—json-prettyprint` --- .../SwiftDocCPluginUtilitiesTests/HelpInformationTests.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Tests/SwiftDocCPluginUtilitiesTests/HelpInformationTests.swift b/Tests/SwiftDocCPluginUtilitiesTests/HelpInformationTests.swift index fab66a0..eda81c6 100644 --- a/Tests/SwiftDocCPluginUtilitiesTests/HelpInformationTests.swift +++ b/Tests/SwiftDocCPluginUtilitiesTests/HelpInformationTests.swift @@ -40,6 +40,8 @@ final class HelpInformationTests: XCTestCase { --disable-indexing, --no-indexing Disable indexing for the produced DocC archive. Produces a DocC archive that is best-suited for hosting online but incompatible with Xcode. + --json-prettyprint Pretty-print the JSON output of the documentation archive. + Formats the JSON files in the documentation archive with spacing, indentation, and sorted keys for a deterministic output. --verbose Increase verbosity to include informational output. SYMBOL GRAPH OPTIONS: @@ -187,6 +189,8 @@ final class HelpInformationTests: XCTestCase { --disable-indexing, --no-indexing Disable indexing for the produced DocC archive. Produces a DocC archive that is best-suited for hosting online but incompatible with Xcode. + --json-prettyprint Pretty-print the JSON output of the documentation archive. + Formats the JSON files in the documentation archive with spacing, indentation, and sorted keys for a deterministic output. --verbose Increase verbosity to include informational output. SYMBOL GRAPH OPTIONS: From a74e64b23ae1508b7dd4e347177fe18360e1855f Mon Sep 17 00:00:00 2001 From: Maic Lopez Saenz Date: Wed, 24 Jun 2026 22:31:45 -0700 Subject: [PATCH 3/3] add tests for parsed environment properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests for the expected properties in `doccEnvironment` when the `—json-prettyprint` flag is enabled --- .../ParsedArgumentsTests.swift | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/Tests/SwiftDocCPluginUtilitiesTests/ParsedArgumentsTests.swift b/Tests/SwiftDocCPluginUtilitiesTests/ParsedArgumentsTests.swift index b1c3367..a93ab43 100644 --- a/Tests/SwiftDocCPluginUtilitiesTests/ParsedArgumentsTests.swift +++ b/Tests/SwiftDocCPluginUtilitiesTests/ParsedArgumentsTests.swift @@ -89,6 +89,8 @@ final class ParsedArgumentsTests: XCTestCase { "--output-path", "/my/output-path" ] ) + + XCTAssertEqual(arguments.doccEnvironment(), [:]) } func testDocCArgumentsForOneArgument() { @@ -444,7 +446,46 @@ final class ParsedArgumentsTests: XCTestCase { XCTAssertFalse(doccArguments.contains("--include-extended-types")) XCTAssertFalse(doccArguments.contains("--experimental-skip-synthesized-symbols")) } - + + func testDoccEnvironmentWithJSONPrettyPrint() { + let prettyPrintArguments = ParsedArguments( + ["--json-prettyprint"] + ) + + XCTAssertTrue(prettyPrintArguments.pluginArguments.jsonPrettyPrint) + + XCTAssertEqual( + prettyPrintArguments.doccEnvironment(), + ["DOCC_JSON_PRETTYPRINT": "YES"] + ) + + XCTAssertEqual( + prettyPrintArguments.doccArguments( + action: .convert, + targetKind: .library, + doccCatalogPath: "/my/catalog.docc", + targetName: "MyTarget", + symbolGraphDirectoryPath: "/my/symbol-graph", + outputPath: "/my/output-path" + ), + [ + "convert", + "/my/catalog.docc", + "--emit-lmdb-index", + "--fallback-display-name", "MyTarget", + "--fallback-bundle-identifier", "MyTarget", + "--additional-symbol-graph-dir", "/my/symbol-graph", + "--output-path", "/my/output-path" + ] + ) + + + let defaultArguments = ParsedArguments([]) + + XCTAssertFalse(defaultArguments.pluginArguments.jsonPrettyPrint) + XCTAssertEqual(defaultArguments.doccEnvironment(), [:]) + } + func testSymbolGraphArguments() { do { let arguments = ParsedArguments(["--include-extended-types", "--experimental-skip-synthesized-symbols", "--symbol-graph-minimum-access-level", "internal"])