Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Formally deprecate the old diagnostics.json digest file #1163

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Sources/SwiftDocC/Infrastructure/ConvertActionConverter.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2024 Apple Inc. and the Swift project authors
Copyright (c) 2024-2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -54,7 +54,7 @@ package enum ConvertActionConverter {

guard !context.problems.containsErrors else {
if emitDigest {
try outputConsumer.consume(problems: context.problems)
try (_Deprecated(outputConsumer) as _DeprecatedConsumeProblemsAccess)._consume(problems: context.problems)
}
return []
}
Expand Down Expand Up @@ -198,7 +198,7 @@ package enum ConvertActionConverter {
if emitDigest {
signposter.withIntervalSignpost("Emit digest", id: signposter.makeSignpostID()) {
do {
try outputConsumer.consume(problems: context.problems + conversionProblems)
try (_Deprecated(outputConsumer) as _DeprecatedConsumeProblemsAccess)._consume(problems: context.problems + conversionProblems)
} catch {
recordProblem(from: error, in: &conversionProblems, withIdentifier: "problems")
}
Expand Down
40 changes: 39 additions & 1 deletion Sources/SwiftDocC/Infrastructure/ConvertOutputConsumer.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2021 Apple Inc. and the Swift project authors
Copyright (c) 2021-2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
Expand All @@ -16,6 +16,7 @@ import Foundation
/// or store them in memory.
public protocol ConvertOutputConsumer {
/// Consumes an array of problems that were generated during a conversion.
@available(*, deprecated, message: "This deprecated API will be removed after 6.2 is released")
func consume(problems: [Problem]) throws

/// Consumes a render node that was generated during a conversion.
Expand Down Expand Up @@ -58,3 +59,40 @@ public extension ConvertOutputConsumer {
func consume(buildMetadata: BuildMetadata) throws {}
func consume(linkResolutionInformation: SerializableLinkResolutionInformation) throws {}
}

// Default implementation so that conforming types don't need to implement deprecated API.
public extension ConvertOutputConsumer {
func consume(problems: [Problem]) throws {}
}

package protocol _DeprecatedConsumeProblemsAccess {
func _consume(problems: [Problem]) throws
}

package struct _Deprecated<Consumer: ConvertOutputConsumer>: _DeprecatedConsumeProblemsAccess {
Comment on lines +68 to +72
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because ConvertOutputConsumer is a public protocol I had to get a bit creative to be able to still call its deprecated API without introducing deprecation warnings in the DocC code.

private let consumer: Consumer
package init(_ consumer: Consumer) {
self.consumer = consumer
}

@available(*, deprecated, message: "This deprecated API will be removed after 6.2 is released")
package func _consume(problems: [Problem]) throws {
var problems = problems

if !problems.isEmpty {
problems.insert(
Problem(diagnostic: Diagnostic(
severity: .warning,
identifier: "org.swift.docc.DeprecatedDiagnosticsDigets",
summary: """
The 'diagnostics.json' digest file is deprecated and will be removed after 6.2 is released. \
Pass a `--diagnostics-file <diagnostics-file>` to specify a custom location where DocC will write a diagnostics JSON file with more information.
""")
),
at: 0
)
}

try consumer.consume(problems: problems)
}
}
8 changes: 4 additions & 4 deletions Sources/SwiftDocC/Infrastructure/DocumentationConverter.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2021-2024 Apple Inc. and the Swift project authors
Copyright (c) 2021-2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -212,7 +212,7 @@ public struct DocumentationConverter: DocumentationConverterProtocol {
if let rootURL {
throw Error.doesNotContainBundle(url: rootURL)
} else {
try outputConsumer.consume(problems: context.problems)
try (_Deprecated(outputConsumer) as _DeprecatedConsumeProblemsAccess)._consume(problems: context.problems)
throw GeneratedDataProvider.Error.notEnoughDataToGenerateBundle(options: bundleDiscoveryOptions, underlyingError: nil)
}
}
Expand All @@ -232,7 +232,7 @@ public struct DocumentationConverter: DocumentationConverterProtocol {

guard !context.problems.containsErrors else {
if emitDigest {
try outputConsumer.consume(problems: context.problems)
try (_Deprecated(outputConsumer) as _DeprecatedConsumeProblemsAccess)._consume(problems: context.problems)
}
return (analysisProblems: context.problems, conversionProblems: [])
}
Expand Down Expand Up @@ -367,7 +367,7 @@ public struct DocumentationConverter: DocumentationConverterProtocol {

if emitDigest {
do {
try outputConsumer.consume(problems: context.problems + conversionProblems)
try (_Deprecated(outputConsumer) as _DeprecatedConsumeProblemsAccess)._consume(problems: context.problems + conversionProblems)
} catch {
recordProblem(from: error, in: &conversionProblems, withIdentifier: "problems")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"openapi": "3.0.0",
"info": {
"description": "Specification of the DocC diagnostics.json digest file.",
"description": "Specification of the deprecated DocC diagnostics.json digest file. This deprecated file will be removed after 6.2 is released.",
"version": "0.1.0",
"title": "Diagnostics"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2021-2024 Apple Inc. and the Swift project authors
Copyright (c) 2021-2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -330,7 +330,7 @@ public struct ConvertAction: AsyncAction {
} catch {
if emitDigest {
let problem = Problem(description: (error as? DescribedError)?.errorDescription ?? error.localizedDescription, source: nil)
try outputConsumer.consume(problems: context.problems + [problem])
try (_Deprecated(outputConsumer) as _DeprecatedConsumeProblemsAccess)._consume(problems: context.problems + [problem])
try moveOutput(from: temporaryFolder, to: targetDirectory)
}
throw error
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2021-2024 Apple Inc. and the Swift project authors
Copyright (c) 2021-2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -50,6 +50,7 @@ struct ConvertFileWritingConsumer: ConvertOutputConsumer {
self.assetPrefixComponent = bundleID?.rawValue.split(separator: "/").joined(separator: "-")
}

@available(*, deprecated, message: "This deprecated API will be removed after 6.2 is released")
func consume(problems: [Problem]) throws {
let diagnostics = problems.map { problem in
Digest.Diagnostic(diagnostic: problem.diagnostic, rootURL: bundleRootFolder)
Expand Down Expand Up @@ -245,6 +246,7 @@ enum Digest {
let downloads: [DownloadReference]
}

@available(*, deprecated, message: "This deprecated API will be removed after 6.2 is released")
struct Diagnostic: Codable {
struct Location: Codable {
let line: Int
Expand All @@ -263,6 +265,7 @@ enum Digest {
}
}

@available(*, deprecated, message: "This deprecated API will be removed after 6.2 is released")
private extension Digest.Diagnostic {
init(diagnostic: Diagnostic, rootURL: URL?) {
self.start = (diagnostic.range?.lowerBound).map { Location(line: $0.line, column: $0.column) }
Expand Down
90 changes: 90 additions & 0 deletions Tests/SwiftDocCTests/DeprecatedDiagnosticsDigestWarningTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import Foundation
import SwiftDocC
import SwiftDocCTestUtilities
import XCTest

class DeprecatedDiagnosticsDigestWarningTests: XCTestCase {
func testNoDeprecationWarningWhenThereAreNoOtherWarnings() throws {
let catalog = Folder(name: "unit-test.docc", content: [
TextFile(name: "Root.md", utf8Content: """
# Root

An empty root page
""")
])
let (bundle, context) = try loadBundle(catalog: catalog)

let outputConsumer = TestOutputConsumer()

_ = try ConvertActionConverter.convert(
bundle: bundle,
context: context,
outputConsumer: outputConsumer,
sourceRepository: nil,
emitDigest: true,
documentationCoverageOptions: .noCoverage
)

XCTAssert(outputConsumer.problems.isEmpty, "Unexpected problems: \(outputConsumer.problems.map(\.diagnostic.summary).joined(separator: "\n"))")
}

func testDeprecationWarningWhenThereAreOtherWarnings() throws {
let catalog = Folder(name: "unit-test.docc", content: [
TextFile(name: "Root.md", utf8Content: """
# Root

An empty root page

This link will result in a warning: ``NotFound``.
""")
])
let (bundle, context) = try loadBundle(catalog: catalog)

let outputConsumer = TestOutputConsumer()

_ = try ConvertActionConverter.convert(
bundle: bundle,
context: context,
outputConsumer: outputConsumer,
sourceRepository: nil,
emitDigest: true,
documentationCoverageOptions: .noCoverage
)

XCTAssertEqual(outputConsumer.problems.count, 2, "Unexpected problems: \(outputConsumer.problems.map(\.diagnostic.summary).joined(separator: "\n"))")

let deprecationWarning = try XCTUnwrap(outputConsumer.problems.first?.diagnostic)

XCTAssertEqual(deprecationWarning.identifier, "org.swift.docc.DeprecatedDiagnosticsDigets")
XCTAssertEqual(deprecationWarning.summary, "The 'diagnostics.json' digest file is deprecated and will be removed after 6.2 is released. Pass a `--diagnostics-file <diagnostics-file>` to specify a custom location where DocC will write a diagnostics JSON file with more information.")
}
}

private class TestOutputConsumer: ConvertOutputConsumer {
var problems: [Problem] = []

func consume(problems: [Problem]) throws {
self.problems.append(contentsOf: problems)
}

func consume(renderNode: RenderNode) throws { }
func consume(assetsInBundle bundle: DocumentationBundle) throws { }
func consume(linkableElementSummaries: [LinkDestinationSummary]) throws { }
func consume(indexingRecords: [IndexingRecord]) throws { }
func consume(assets: [RenderReferenceType: [RenderReference]]) throws { }
func consume(benchmarks: Benchmark) throws { }
func consume(documentationCoverageInfo: [CoverageDataEntry]) throws { }
func consume(renderReferenceStore: RenderReferenceStore) throws { }
func consume(buildMetadata: BuildMetadata) throws { }
func consume(linkResolutionInformation: SerializableLinkResolutionInformation) throws { }
}
3 changes: 1 addition & 2 deletions Tests/SwiftDocCTests/TestRenderNodeOutputConsumer.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2022-2024 Apple Inc. and the Swift project authors
Copyright (c) 2022-2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
Expand All @@ -21,7 +21,6 @@ class TestRenderNodeOutputConsumer: ConvertOutputConsumer {
}
}

func consume(problems: [Problem]) throws { }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tests that conforming types can omit implementing the deprecated method.

func consume(assetsInBundle bundle: DocumentationBundle) throws { }
func consume(linkableElementSummaries: [LinkDestinationSummary]) throws { }
func consume(indexingRecords: [IndexingRecord]) throws { }
Expand Down
Loading