Skip to content

Commit 8fc6667

Browse files
authored
Formally deprecate the old diagnostics.json digest file (#1163)
* Formally deprecate the old diagnostics.json digest file rdar://145729962 * Add code comments to explain the temporary deprecation workaround * Add missing `any` when referring to new deprecation silencing protocol * Resolve unrelated warning about unnecessary public import
1 parent cfbf9ce commit 8fc6667

File tree

10 files changed

+200
-16
lines changed

10 files changed

+200
-16
lines changed

Sources/SwiftDocC/Infrastructure/ConvertActionConverter.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

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

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

5555
guard !context.problems.containsErrors else {
5656
if emitDigest {
57-
try outputConsumer.consume(problems: context.problems)
57+
try (_Deprecated(outputConsumer) as (any _DeprecatedConsumeProblemsAccess))._consume(problems: context.problems)
5858
}
5959
return []
6060
}
@@ -198,7 +198,7 @@ package enum ConvertActionConverter {
198198
if emitDigest {
199199
signposter.withIntervalSignpost("Emit digest", id: signposter.makeSignpostID()) {
200200
do {
201-
try outputConsumer.consume(problems: context.problems + conversionProblems)
201+
try (_Deprecated(outputConsumer) as (any _DeprecatedConsumeProblemsAccess))._consume(problems: context.problems + conversionProblems)
202202
} catch {
203203
recordProblem(from: error, in: &conversionProblems, withIdentifier: "problems")
204204
}

Sources/SwiftDocC/Infrastructure/ConvertOutputConsumer.swift

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

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

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

2122
/// Consumes a render node that was generated during a conversion.
@@ -58,3 +59,49 @@ public extension ConvertOutputConsumer {
5859
func consume(buildMetadata: BuildMetadata) throws {}
5960
func consume(linkResolutionInformation: SerializableLinkResolutionInformation) throws {}
6061
}
62+
63+
// Default implementation so that conforming types don't need to implement deprecated API.
64+
public extension ConvertOutputConsumer {
65+
func consume(problems: [Problem]) throws {}
66+
}
67+
68+
// A package-internal protocol that callers can cast to when they need to call `_consume(problems:)` for backwards compatibility (until `consume(problems:)` is removed).
69+
package protocol _DeprecatedConsumeProblemsAccess {
70+
func _consume(problems: [Problem]) throws
71+
}
72+
73+
// Because `ConvertOutputConsumer` is a public protocol, it can't conform to `_DeprecatedConsumeProblemsAccess`.
74+
// Also, it would both be a public change and a breaking change to add a non-deprecated `_consume(problems:)` to `ConvertOutputConsumer` directly.
75+
//
76+
// To work around, this while still allowing callers to call `_consume(problems:)` without deprecation warnings, we wrap the consumer in a generic box (`_Deprecated`).
77+
// This box can conform to `_DeprecatedConsumeProblemsAccess`, so the caller can cast the box to avoid the deprecation warning:
78+
//
79+
// (_Deprecated(outputConsumer) as _DeprecatedConsumeProblemsAccess)._consume(problems: ...)
80+
package struct _Deprecated<Consumer: ConvertOutputConsumer>: _DeprecatedConsumeProblemsAccess {
81+
private let consumer: Consumer
82+
package init(_ consumer: Consumer) {
83+
self.consumer = consumer
84+
}
85+
86+
// This needs to be deprecated to be able to call `consume(problems:)` without a deprecation warning.
87+
@available(*, deprecated, message: "This deprecated API will be removed after 6.2 is released")
88+
package func _consume(problems: [Problem]) throws {
89+
var problems = problems
90+
91+
if !problems.isEmpty {
92+
problems.insert(
93+
Problem(diagnostic: Diagnostic(
94+
severity: .warning,
95+
identifier: "org.swift.docc.DeprecatedDiagnosticsDigets",
96+
summary: """
97+
The 'diagnostics.json' digest file is deprecated and will be removed after 6.2 is released. \
98+
Pass a `--diagnostics-file <diagnostics-file>` to specify a custom location where DocC will write a diagnostics JSON file with more information.
99+
""")
100+
),
101+
at: 0
102+
)
103+
}
104+
105+
try consumer.consume(problems: problems)
106+
}
107+
}

Sources/SwiftDocC/Infrastructure/DocumentationConverter.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

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

77
See https://swift.org/LICENSE.txt for license information
@@ -212,7 +212,7 @@ public struct DocumentationConverter: DocumentationConverterProtocol {
212212
if let rootURL {
213213
throw Error.doesNotContainBundle(url: rootURL)
214214
} else {
215-
try outputConsumer.consume(problems: context.problems)
215+
try (_Deprecated(outputConsumer) as (any _DeprecatedConsumeProblemsAccess))._consume(problems: context.problems)
216216
throw GeneratedDataProvider.Error.notEnoughDataToGenerateBundle(options: bundleDiscoveryOptions, underlyingError: nil)
217217
}
218218
}
@@ -232,7 +232,7 @@ public struct DocumentationConverter: DocumentationConverterProtocol {
232232

233233
guard !context.problems.containsErrors else {
234234
if emitDigest {
235-
try outputConsumer.consume(problems: context.problems)
235+
try (_Deprecated(outputConsumer) as (any _DeprecatedConsumeProblemsAccess))._consume(problems: context.problems)
236236
}
237237
return (analysisProblems: context.problems, conversionProblems: [])
238238
}
@@ -367,7 +367,7 @@ public struct DocumentationConverter: DocumentationConverterProtocol {
367367

368368
if emitDigest {
369369
do {
370-
try outputConsumer.consume(problems: context.problems + conversionProblems)
370+
try (_Deprecated(outputConsumer) as (any _DeprecatedConsumeProblemsAccess))._consume(problems: context.problems + conversionProblems)
371371
} catch {
372372
recordProblem(from: error, in: &conversionProblems, withIdentifier: "problems")
373373
}

Sources/SwiftDocC/Servers/DocumentationSchemeHandler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
#if canImport(WebKit)
1212
public import WebKit
13-
public import Foundation
13+
import Foundation
1414

1515
public class DocumentationSchemeHandler: NSObject {
1616

Sources/SwiftDocC/SwiftDocC.docc/Resources/Diagnostics.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"openapi": "3.0.0",
33
"info": {
4-
"description": "Specification of the DocC diagnostics.json digest file.",
4+
"description": "Specification of the deprecated DocC diagnostics.json digest file. This deprecated file will be removed after 6.2 is released.",
55
"version": "0.1.0",
66
"title": "Diagnostics"
77
},

Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

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

77
See https://swift.org/LICENSE.txt for license information
@@ -330,7 +330,7 @@ public struct ConvertAction: AsyncAction {
330330
} catch {
331331
if emitDigest {
332332
let problem = Problem(description: (error as? (any DescribedError))?.errorDescription ?? error.localizedDescription, source: nil)
333-
try outputConsumer.consume(problems: context.problems + [problem])
333+
try (_Deprecated(outputConsumer) as (any _DeprecatedConsumeProblemsAccess))._consume(problems: context.problems + [problem])
334334
try moveOutput(from: temporaryFolder, to: targetDirectory)
335335
}
336336
throw error

Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertFileWritingConsumer.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

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

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

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

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

268+
@available(*, deprecated, message: "This deprecated API will be removed after 6.2 is released")
266269
private extension Digest.Diagnostic {
267270
init(diagnostic: Diagnostic, rootURL: URL?) {
268271
self.start = (diagnostic.range?.lowerBound).map { Location(line: $0.line, column: $0.column) }
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2025 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See https://swift.org/LICENSE.txt for license information
8+
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import Foundation
12+
import SwiftDocC
13+
import SwiftDocCTestUtilities
14+
import XCTest
15+
16+
class DeprecatedDiagnosticsDigestWarningTests: XCTestCase {
17+
func testNoDeprecationWarningWhenThereAreNoOtherWarnings() throws {
18+
let catalog = Folder(name: "unit-test.docc", content: [
19+
TextFile(name: "Root.md", utf8Content: """
20+
# Root
21+
22+
An empty root page
23+
""")
24+
])
25+
let (bundle, context) = try loadBundle(catalog: catalog)
26+
27+
let outputConsumer = TestOutputConsumer()
28+
29+
_ = try ConvertActionConverter.convert(
30+
bundle: bundle,
31+
context: context,
32+
outputConsumer: outputConsumer,
33+
sourceRepository: nil,
34+
emitDigest: true,
35+
documentationCoverageOptions: .noCoverage
36+
)
37+
38+
XCTAssert(outputConsumer.problems.isEmpty, "Unexpected problems: \(outputConsumer.problems.map(\.diagnostic.summary).joined(separator: "\n"))")
39+
}
40+
41+
func testDeprecationWarningWhenThereAreOtherWarnings() throws {
42+
let catalog = Folder(name: "unit-test.docc", content: [
43+
TextFile(name: "Root.md", utf8Content: """
44+
# Root
45+
46+
An empty root page
47+
48+
This link will result in a warning: ``NotFound``.
49+
""")
50+
])
51+
let (bundle, context) = try loadBundle(catalog: catalog)
52+
53+
let outputConsumer = TestOutputConsumer()
54+
55+
_ = try ConvertActionConverter.convert(
56+
bundle: bundle,
57+
context: context,
58+
outputConsumer: outputConsumer,
59+
sourceRepository: nil,
60+
emitDigest: true,
61+
documentationCoverageOptions: .noCoverage
62+
)
63+
64+
XCTAssertEqual(outputConsumer.problems.count, 2, "Unexpected problems: \(outputConsumer.problems.map(\.diagnostic.summary).joined(separator: "\n"))")
65+
66+
let deprecationWarning = try XCTUnwrap(outputConsumer.problems.first?.diagnostic)
67+
68+
XCTAssertEqual(deprecationWarning.identifier, "org.swift.docc.DeprecatedDiagnosticsDigets")
69+
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.")
70+
}
71+
}
72+
73+
private class TestOutputConsumer: ConvertOutputConsumer {
74+
var problems: [Problem] = []
75+
76+
func consume(problems: [Problem]) throws {
77+
self.problems.append(contentsOf: problems)
78+
}
79+
80+
func consume(renderNode: RenderNode) throws { }
81+
func consume(assetsInBundle bundle: DocumentationBundle) throws { }
82+
func consume(linkableElementSummaries: [LinkDestinationSummary]) throws { }
83+
func consume(indexingRecords: [IndexingRecord]) throws { }
84+
func consume(assets: [RenderReferenceType: [any RenderReference]]) throws { }
85+
func consume(benchmarks: Benchmark) throws { }
86+
func consume(documentationCoverageInfo: [CoverageDataEntry]) throws { }
87+
func consume(renderReferenceStore: RenderReferenceStore) throws { }
88+
func consume(buildMetadata: BuildMetadata) throws { }
89+
func consume(linkResolutionInformation: SerializableLinkResolutionInformation) throws { }
90+
}

Tests/SwiftDocCTests/TestRenderNodeOutputConsumer.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

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

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

24-
func consume(problems: [Problem]) throws { }
2524
func consume(assetsInBundle bundle: DocumentationBundle) throws { }
2625
func consume(linkableElementSummaries: [LinkDestinationSummary]) throws { }
2726
func consume(indexingRecords: [IndexingRecord]) throws { }

0 commit comments

Comments
 (0)