From f24a83bbba1e5c7d7360bf1cb54c5399387216c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Tue, 28 Feb 2023 11:20:35 -0800 Subject: [PATCH 01/16] Deprecate using diagnostics as errors. The error formatting is implicitly tied to a specific diagnostic writer The diagnostics include more information that gets lost when they are raised as errors. --- .../Diagnostics/Diagnostic.swift | 13 +++++--- .../Diagnostics/DiagnosticConsoleWriter.swift | 7 ++++- .../Diagnostics/DiagnosticNote.swift | 8 +++-- .../Infrastructure/Diagnostics/Problem.swift | 31 ++++++++++++------- 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift index 6381c8f497..d0f64ce82a 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift @@ -17,8 +17,7 @@ import SymbolKit public typealias BasicDiagnostic = Diagnostic /// A diagnostic explains a problem or issue that needs the end-user's attention. -public struct Diagnostic: DescribedError { - +public struct Diagnostic { /// The origin of the diagnostic, such as a file or process. public var source: URL? @@ -95,13 +94,19 @@ public extension Diagnostic { range?.offsetWithRange(docRange) } +} +// MARK: Deprecated + +@available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") +extension Diagnostic: DescribedError { + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") var localizedDescription: String { return DiagnosticConsoleWriter.formattedDescriptionFor(self) } - var errorDescription: String { + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") + public var errorDescription: String { return DiagnosticConsoleWriter.formattedDescriptionFor(self) } } - diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift index 6113880015..6cc0b38915 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift @@ -109,9 +109,14 @@ extension DiagnosticConsoleWriter { if !diagnostic.notes.isEmpty { result += "\n" - result += diagnostic.notes.map { $0.description }.joined(separator: "\n") + result += diagnostic.notes.map { formattedDescriptionFor($0) }.joined(separator: "\n") } return result } + + private static func formattedDescriptionFor(_ note: DiagnosticNote, options: DiagnosticFormattingOptions = []) -> String { + let location = "\(note.source.path):\(note.range.lowerBound.line):\(note.range.lowerBound.column)" + return "\(location): note: \(note.message)" + } } diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift index a87b2396ae..503f59e52a 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift @@ -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-2023 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 @@ -14,7 +14,7 @@ import Markdown /** A diagnostic note is a simple string message that should appear somewhere in a document. */ -public struct DiagnosticNote: CustomStringConvertible { +public struct DiagnosticNote { /// The source file to which to attach the `message`. public var source: URL @@ -23,7 +23,11 @@ public struct DiagnosticNote: CustomStringConvertible { /// The message to attach to the document. public var message: String +} +@available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") +extension DiagnosticNote: CustomStringConvertible { + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") public var description: String { let location = "\(source.path):\(range.lowerBound.line):\(range.lowerBound.column)" return "\(location): note: \(message)" diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift index ff3b76aa13..4832d4d190 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift @@ -29,16 +29,6 @@ public struct Problem { } } -extension Problem { - var localizedDescription: String { - return DiagnosticConsoleWriter.formattedDescriptionFor(self) - } - - func formattedLocalizedDescription(withOptions options: DiagnosticFormattingOptions = []) -> String { - return DiagnosticConsoleWriter.formattedDescriptionFor(self, options: options) - } -} - extension Problem { /// Offsets the problem using a certain SymbolKit `SourceRange`. /// @@ -61,12 +51,29 @@ extension Sequence where Element == Problem { $0.diagnostic.severity == .error } } - - /// The human readable summary description for the problems. +} + +// MARK: Deprecated + +extension Problem { + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") + var localizedDescription: String { + return DiagnosticConsoleWriter.formattedDescriptionFor(self) + } + + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") + func formattedLocalizedDescription(withOptions options: DiagnosticFormattingOptions = []) -> String { + return DiagnosticConsoleWriter.formattedDescriptionFor(self, options: options) + } +} + +extension Sequence where Element == Problem { + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") public var localizedDescription: String { return map { $0.localizedDescription }.joined(separator: "\n") } + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") public func formattedLocalizedDescription(withOptions options: DiagnosticFormattingOptions) -> String { return map { $0.formattedLocalizedDescription(withOptions: options) }.joined(separator: "\n") } From 00dc703671a83a687c532c524b17425167560342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Tue, 28 Feb 2023 11:27:36 -0800 Subject: [PATCH 02/16] Update calls to deprecated diagnostic-as-error properties --- .../Convert/ConvertService.swift | 4 ++-- .../ArgumentParsing/Subcommands/Convert.swift | 4 ++-- .../Diagnostics/DiagnosticEngineTests.swift | 12 ++++++------ .../Diagnostics/DiagnosticTests.swift | 18 +++++++++--------- .../Diagnostics/ProblemTests.swift | 6 +++--- .../Infrastructure/PathHierarchyTests.swift | 2 +- .../Model/RenderNodeSerializationTests.swift | 8 ++++---- .../Model/SemaToRenderNodeTests.swift | 6 +++--- .../Semantics/ArticleTests.swift | 12 ++++++------ .../HasAtMostOneTests.swift | 4 ++-- .../HasExactlyOneTests.swift | 6 +++--- .../HasOnlyKnownArgumentsTests.swift | 4 ++-- .../HasOnlyKnownDirectivesTests.swift | 4 ++-- .../Semantics/MetadataTests.swift | 6 +++--- .../Semantics/RedirectedTests.swift | 10 +++++----- .../SwiftDocCTests/Semantics/SymbolTests.swift | 4 ++-- .../ConvertActionTests.swift | 2 +- .../PreviewActionIntegrationTests.swift | 6 +++--- 18 files changed, 59 insertions(+), 59 deletions(-) diff --git a/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift b/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift index e13d78f2fe..f5864c5a91 100644 --- a/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift +++ b/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift @@ -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-2023 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 @@ -192,7 +192,7 @@ public struct ConvertService: DocumentationService { guard conversionProblems.isEmpty else { throw ConvertServiceError.conversionError( - underlyingError: conversionProblems.localizedDescription) + underlyingError: DiagnosticConsoleWriter.formattedDescriptionFor(conversionProblems)) } let references: RenderReferenceStore? diff --git a/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift b/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift index 132982bc93..9cccfd8c34 100644 --- a/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift +++ b/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2022 Apple Inc. and the Swift project authors + Copyright (c) 2021-2023 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 @@ -331,7 +331,7 @@ extension Docc { ) print( - invalidOrMissingTemplateDiagnostic.localizedDescription, + DiagnosticConsoleWriter.formattedDescriptionFor(invalidOrMissingTemplateDiagnostic), to: &Self._errorLogHandle ) diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift index f443237739..a893ef0456 100644 --- a/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2022 Apple Inc. and the Swift project authors + Copyright (c) 2021-2023 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 @@ -113,7 +113,7 @@ class DiagnosticEngineTests: XCTestCase { defaultEngine.emit(warning) defaultEngine.emit(information) defaultEngine.emit(hint) - XCTAssertEqual(defaultEngine.problems.localizedDescription, """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(defaultEngine.problems), """ error: Test error warning: Test warning """) @@ -123,7 +123,7 @@ class DiagnosticEngineTests: XCTestCase { engine.emit(warning) engine.emit(information) engine.emit(hint) - XCTAssertEqual(engine.problems.localizedDescription, """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(engine.problems), """ error: Test error warning: Test warning note: Test information @@ -139,7 +139,7 @@ class DiagnosticEngineTests: XCTestCase { defaultEngine.emit(error) defaultEngine.emit(warning) defaultEngine.emit(information) - XCTAssertEqual(defaultEngine.problems.localizedDescription, """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(defaultEngine.problems), """ error: Test error warning: Test warning """) @@ -148,7 +148,7 @@ class DiagnosticEngineTests: XCTestCase { engine.emit(error) engine.emit(warning) engine.emit(information) - XCTAssertEqual(engine.problems.localizedDescription, """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(engine.problems), """ error: Test error error: Test warning note: Test information @@ -158,7 +158,7 @@ class DiagnosticEngineTests: XCTestCase { errorFilterLevelEngine.emit(error) errorFilterLevelEngine.emit(warning) errorFilterLevelEngine.emit(information) - XCTAssertEqual(errorFilterLevelEngine.problems.localizedDescription, """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(errorFilterLevelEngine.problems), """ error: Test error error: Test warning """) diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift index bd07682118..1d4b050d39 100644 --- a/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift @@ -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-2023 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 @@ -66,7 +66,7 @@ class DiagnosticTests: XCTestCase { let range = SourceLocation(line: 1, column: 1, source: URL(fileURLWithPath: path))...Missing", problem.diagnostic.identifier) XCTAssertEqual( - problem.diagnostic.localizedDescription, + DiagnosticConsoleWriter.formattedDescriptionFor(problem.diagnostic), """ error: Missing 'Child' child directive The 'Parent' directive must have exactly one 'Child' child directive @@ -87,7 +87,7 @@ class HasExactlyOneTests: XCTestCase { XCTAssertEqual(""" error: Duplicate 'Child' child directive The 'Parent' directive must have exactly one 'Child' child directive - """, problems[0].diagnostic.localizedDescription) + """, DiagnosticConsoleWriter.formattedDescriptionFor(problems[0].diagnostic)) } } diff --git a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift index e8d2c227c2..45e6865142 100644 --- a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift +++ b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift @@ -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-2023 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 @@ -68,6 +68,6 @@ class HasOnlyKnownArgumentsTests: XCTestCase { XCTAssertEqual(problems.count, 1) guard let first = problems.first else { return } - XCTAssertEqual("error: Unknown argument 'baz' in Intro. These arguments are currently unused but allowed: 'bark', 'woof'.", first.diagnostic.localizedDescription) + XCTAssertEqual("error: Unknown argument 'baz' in Intro. These arguments are currently unused but allowed: 'bark', 'woof'.", DiagnosticConsoleWriter.formattedDescriptionFor(first.diagnostic)) } } diff --git a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift index 3412fa0c15..9fb5f72bda 100644 --- a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift +++ b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift @@ -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-2023 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 @@ -121,7 +121,7 @@ class HasOnlyKnownDirectivesTests: XCTestCase { XCTAssertEqual(problems.count, 1) guard let first = problems.first else { return } - XCTAssertEqual("error: 'baz' directive is unsupported as a child of the 'dir' directive\nThese directives are allowed: 'Comment', 'bar', 'bark', 'foo', 'woof'", first.diagnostic.localizedDescription) + XCTAssertEqual("error: 'baz' directive is unsupported as a child of the 'dir' directive\nThese directives are allowed: 'Comment', 'bar', 'bark', 'foo', 'woof'", DiagnosticConsoleWriter.formattedDescriptionFor(first.diagnostic)) } } diff --git a/Tests/SwiftDocCTests/Semantics/MetadataTests.swift b/Tests/SwiftDocCTests/Semantics/MetadataTests.swift index 9766fd9efd..e35f69df8f 100644 --- a/Tests/SwiftDocCTests/Semantics/MetadataTests.swift +++ b/Tests/SwiftDocCTests/Semantics/MetadataTests.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2022 Apple Inc. and the Swift project authors + Copyright (c) 2021-2023 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 @@ -169,7 +169,7 @@ class MetadataTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(analyzer.problems.localizedDescription)") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(DiagnosticConsoleWriter.formattedDescriptionFor(analyzer.problems))") } func testSymbolArticleSupportsMetadataDisplayName() throws { @@ -193,7 +193,7 @@ class MetadataTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(analyzer.problems.localizedDescription)") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(DiagnosticConsoleWriter.formattedDescriptionFor(analyzer.problems))") } func testArticleDoesNotSupportsMetadataDisplayName() throws { diff --git a/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift b/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift index 92ea9408f3..53d78cb47a 100644 --- a/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift +++ b/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift @@ -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-2023 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 @@ -138,7 +138,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(analyzer.problems.localizedDescription)") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescriptionFor( analyzer.problems))") } func testVolumeAndChapterSupportsRedirect() throws { @@ -235,7 +235,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(analyzer.problems.localizedDescription)") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescriptionFor( analyzer.problems))") } func testTutorialArticleSupportsRedirect() throws { @@ -263,7 +263,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(analyzer.problems.localizedDescription)") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescriptionFor( analyzer.problems))") } func testResourcesSupportsRedirect() throws { @@ -333,7 +333,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(analyzer.problems.localizedDescription)") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescriptionFor( analyzer.problems))") } func testIncorrectArgumentLabel() throws { diff --git a/Tests/SwiftDocCTests/Semantics/SymbolTests.swift b/Tests/SwiftDocCTests/Semantics/SymbolTests.swift index 961dd3fa0e..32df4aa1f8 100644 --- a/Tests/SwiftDocCTests/Semantics/SymbolTests.swift +++ b/Tests/SwiftDocCTests/Semantics/SymbolTests.swift @@ -1,7 +1,7 @@ /* This source file is part of the Swift.org open source project - Copyright (c) 2021-2022 Apple Inc. and the Swift project authors + Copyright (c) 2021-2023 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 @@ -1182,7 +1182,7 @@ class SymbolTests: XCTestCase { var problems = [Problem]() let article = Article(from: document, source: nil, for: bundle, in: context, problems: &problems) XCTAssertNotNil(article, "The sidecar Article couldn't be created.", file: (file), line: line) - XCTAssert(problems.isEmpty, "Unexpectedly found problems: \(problems.localizedDescription)", file: (file), line: line) + XCTAssert(problems.isEmpty, "Unexpectedly found problems: \(DiagnosticConsoleWriter.formattedDescriptionFor(problems))", file: (file), line: line) return article } diff --git a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift index 976adc003b..52127d9629 100644 --- a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift @@ -2948,7 +2948,7 @@ class ConvertActionTests: XCTestCase { return lhs.diagnostic.localizedSummary < rhs.diagnostic.localizedSummary } return lhs.diagnostic.identifier < rhs.diagnostic.identifier - }) .map { $0.diagnostic.localizedDescription }.sorted().joined(separator: "\n") + }) .map { DiagnosticConsoleWriter.formattedDescriptionFor($0.diagnostic) }.sorted().joined(separator: "\n") } #endif diff --git a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift index a34775b0e9..9fe4680424 100644 --- a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift @@ -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-2023 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 @@ -329,7 +329,7 @@ class PreviewActionIntegrationTests: XCTestCase { XCTAssertTrue(result.didEncounterError, "Did not find an error when running preview", file: file, line: line) XCTAssertNotNil(engine.problems.first(where: { problem -> Bool in - problem.diagnostic.localizedDescription.contains(expectedErrorMessage) + DiagnosticConsoleWriter.formattedDescriptionFor(problem.diagnostic).contains(expectedErrorMessage) }), "Didn't find expected error message '\(expectedErrorMessage)'", file: file, line: line) // Verify that the failed server is not added to the server list @@ -468,7 +468,7 @@ class PreviewActionIntegrationTests: XCTestCase { } if !result.problems.isEmpty { - print(result.problems.localizedDescription, to: &logHandle) + print(DiagnosticConsoleWriter.formattedDescriptionFor(result.problems), to: &logHandle) } } catch { XCTFail(error.localizedDescription) From 9e021f53b646fe3c3264f30a62f2ba06b615bc69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Tue, 28 Feb 2023 11:48:43 -0800 Subject: [PATCH 03/16] Add "features.json" to indicate feature availability to other tools --- Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC.md | 6 +++- .../SwiftDocC.docc/SwiftDocC/Features.md | 34 +++++++++++++++++++ build-script-helper.py | 17 ++++++++++ features.json | 7 ++++ 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Features.md create mode 100644 features.json diff --git a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC.md b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC.md index efe24ad101..627f5b1583 100644 --- a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC.md +++ b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC.md @@ -51,4 +51,8 @@ Converting in-memory documentation into rendering nodes and persisting them on d - - - +### Development + +- + + diff --git a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Features.md b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Features.md new file mode 100644 index 0000000000..cfb0416e0c --- /dev/null +++ b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Features.md @@ -0,0 +1,34 @@ +# Indicating Feature Availability to Tools + +Add features to DocC and indicate the feature's availability to other tools. + +Over time as we develop new features in DocC we also add, update, or remove the flags and options that the `docc` executable accepts. So that other tools can know what flags and options a certain version of the `docc` executable accepts, we add new entires in the "features.json" file. + +## Adding a New Feature + +When adding a new collection of command line flags or options to the `docc` executable that relate to some new feature, add a new entry to the "feature.json" file that name the new feature. For example: + +```json +{ + "features": [ + { + "name": "name-of-first-feature" + }, + { + "name": "name-of-second-feature" + } + ] +} +``` + +> Note: Use a single entry for multiple related command line flags and options if they are all added in the same build. + +## Checking what Features DocC Supports + +In a Swift toolchain, the `docc` executable is installed at `usr/bin/docc`. In the same toolchain, the "features.json" file is installed at `usr/share/docc/features.json`. + +Tools that call the `docc` executable from a Swift toolchain can read the "features.json" file to check if a specific feature is available in that build. + +> Note: The feature entry describes the feature name and doesn't list what command line flags or options that feature corresponds to. + + diff --git a/build-script-helper.py b/build-script-helper.py index f28acfc7e8..26bee8c870 100755 --- a/build-script-helper.py +++ b/build-script-helper.py @@ -253,6 +253,23 @@ def install(args, env): verbose=verbose ) + features_path = os.path.join(args.package_path, 'features.json') + # Install features.json relative to the docc executable at "../../share/docc/features.json" + features_install_path = os.path.join( + os.path.dirname( + os.path.dirname(docc_install_dir) + ), + 'share', + 'docc', + 'features.json' + ) + create_intermediate_directories(os.path.dirname(features_install_path), verbose=verbose) + check_and_sync( + file_path=features_path, + install_path=features_install_path, + verbose=verbose + ) + # Copy the content of the build_dir into the install dir with a call like # rsync -a src/ dest copy_render_from=args.copy_doccrender_from diff --git a/features.json b/features.json new file mode 100644 index 0000000000..be2e6d24b7 --- /dev/null +++ b/features.json @@ -0,0 +1,7 @@ +{ + "features": [ + { + "name": "diagnostics-file" + } + ] +} From 4b3f5b854ca41a31dede2e1cc430b3a72640c18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Tue, 28 Feb 2023 13:20:11 -0800 Subject: [PATCH 04/16] Add diagnostic consumer that writes to a file rdar://105181169 --- .../Diagnostics/Diagnostic.swift | 41 ++--- .../Diagnostics/DiagnosticConsoleWriter.swift | 10 +- .../Diagnostics/DiagnosticConsumer.swift | 5 +- .../Diagnostics/DiagnosticEngine.swift | 10 ++ .../Diagnostics/DiagnosticFile.swift | 151 ++++++++++++++++++ .../Diagnostics/DiagnosticFileWriter.swift | 30 ++++ .../DiagnosticFormattingOptions.swift | 10 +- .../DocumentationConverter.swift | 2 + .../Actions/Convert/ConvertAction.swift | 60 ++++++- .../ConvertAction+CommandInitialization.swift | 3 +- .../ArgumentParsing/Subcommands/Convert.swift | 28 +++- .../DiagnosticConsoleWriterTests.swift | 6 +- .../Diagnostics/DiagnosticEngineTests.swift | 1 + .../Diagnostics/ProblemTests.swift | 2 +- 14 files changed, 311 insertions(+), 48 deletions(-) create mode 100644 Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift create mode 100644 Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFileWriter.swift diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift index d0f64ce82a..6cdab5c75d 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift @@ -34,30 +34,21 @@ public struct Diagnostic { /// `org.swift.docc.SummaryContainsLink` public var identifier: String - /// Provides the short, localized abstract provided by ``localizedExplanation`` in plain text if an - /// explanation is available. - /// - /// At a bare minimum, all diagnostics must have at least one paragraph or sentence describing what the diagnostic is. - public var localizedSummary: String + /// A brief summary that describe the problem or issue. + public var summary: String + + @available(*, deprecated, renamed: "summary") + public var localizedSummary: String { + return summary + } - /// Provides a markup document for this diagnostic in the end-user's most preferred language, the base language - /// if one isn't available, or `nil` if no explanations are provided for this diagnostic's identifier. - /// - /// - Note: All diagnostics *must have* an explanation. If a diagnostic can't be explained in plain language - /// and easily understood by the reader, it should not be shown. - /// - /// An explanation should have at least the following items: - /// - /// - Document - /// - Abstract: A summary paragraph; one or two sentences. - /// - Discussion: A discussion of the situation and why it's interesting or a problem for the end-user. - /// This discussion should implicitly justify the diagnostic's existence. - /// - Heading, level 2, text: "Example" - /// - Problem Example: Show an example of the problematic situation and highlight important areas. - /// - Heading, level 2, text: "Solution" - /// - Solution: Explain what the end-user needs to do to correct the problem in plain language. - /// - Solution Example: Show the *Problem Example* as corrected and highlight the changes made. - public var localizedExplanation: String? + /// Additional details that explain the the problem or issue to the end-user in plain language. + public var explanation: String? + + @available(*, deprecated, renamed: "explanation") + public var localizedExplanation: String? { + return explanation + } /// Extra notes to tack onto the editor for additional information. /// @@ -78,8 +69,8 @@ public struct Diagnostic { self.severity = severity self.range = range self.identifier = identifier - self.localizedSummary = summary - self.localizedExplanation = explanation + self.summary = summary + self.explanation = explanation self.notes = notes } } diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift index 6cc0b38915..9692f642d1 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift @@ -38,6 +38,10 @@ public final class DiagnosticConsoleWriter: DiagnosticFormattingConsumer { let text = Self.formattedDescriptionFor(problems, options: formattingOptions).appending("\n") outputStream.write(text) } + + public func finalize() throws { + // The console writer writes each diagnostic as they are received. + } } // MARK: Formatted descriptions @@ -49,7 +53,7 @@ extension DiagnosticConsoleWriter { } public static func formattedDescriptionFor(_ problem: Problem, options: DiagnosticFormattingOptions = []) -> String { - guard let source = problem.diagnostic.source, options.contains(.showFixits) else { + guard let source = problem.diagnostic.source, options.contains(.formatConsoleOutputForTools) else { return formattedDescriptionFor(problem.diagnostic) } @@ -95,7 +99,7 @@ extension DiagnosticConsoleWriter { result += "\(url.path): " } - result += "\(diagnostic.severity): \(diagnostic.localizedSummary)" + result += "\(diagnostic.severity): \(diagnostic.summary)" return result } @@ -103,7 +107,7 @@ extension DiagnosticConsoleWriter { private static func formattedDiagnosticDetails(_ diagnostic: Diagnostic) -> String { var result = "" - if let explanation = diagnostic.localizedExplanation { + if let explanation = diagnostic.explanation { result += "\n\(explanation)" } diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsumer.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsumer.swift index 7dbfe620f0..65faa0ad06 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsumer.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsumer.swift @@ -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-2023 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 @@ -15,6 +15,9 @@ public protocol DiagnosticConsumer: AnyObject { /// Receive diagnostics encountered by a ``DiagnosticEngine``. /// - Parameter problems: The encountered diagnostics. func receive(_ problems: [Problem]) + + /// Inform the consumer that the engine has sent all diagnostics for this build. + func finalize() throws } /// A type that can format received diagnostics in way that's suitable for writing to a destination such as a file or `TextOutputStream`. diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticEngine.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticEngine.swift index 6966a477f5..75d6e59309 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticEngine.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticEngine.swift @@ -95,6 +95,16 @@ public final class DiagnosticEngine { } } } + + public func finalize() { + workQueue.async { [weak self] in + // If the engine isn't around then return early + guard let self = self else { return } + for consumer in self.consumers.sync({ $0.values }) { + try? consumer.finalize() + } + } + } /// Subscribes a given consumer to the diagnostics emitted by this engine. /// - Parameter consumer: The consumer to subscribe to this engine. diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift new file mode 100644 index 0000000000..f67487972f --- /dev/null +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift @@ -0,0 +1,151 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2023 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 struct Markdown.SourceLocation + +struct DiagnosticFile: Codable { + var version: VersionTriplet + var diagnostics: [Diagnostic] + + init(version: VersionTriplet = .current, problems: [Problem]) { + self.version = version + self.diagnostics = problems.map { .init($0) } + } + + struct Diagnostic: Codable { + struct Range: Codable { + var start: Location + var end: Location + struct Location: Codable { + var line: Int + var column: Int + } + } + var source: URL? + var range: Range? + var severity: DiagnosticSeverity + var summary: String + var explanation: String? + var solutions: [Solution] + struct Solution: Codable { + var summary: String + var replacements: [Replacement] + struct Replacement: Codable { + var range: Range + var text: String + } + } + var notes: [Note] + struct Note: Codable { + var source: URL? + var range: Range? + var message: String + } + } + + enum CodingKeys: String, CodingKey { + case version, diagnostics + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + version = try container.decode(VersionTriplet.self, forKey: .version) + try version.verifyIsSupported() + + diagnostics = try container.decode([Diagnostic].self, forKey: .diagnostics) + } +} + +extension VersionTriplet: Codable { + // This file format follows semantic versioning. + // Breaking changes should increment the major version component. + // Non breaking additions should increment the minor version. + // Bug fixes should increment the patch version. + static var current = VersionTriplet(1, 0, 0) + + enum Error: Swift.Error { + case unknownMajorVersion(found: VersionTriplet, latestKnown: VersionTriplet) + } + + func verifyIsSupported() throws { + guard major <= Self.current.major else { + throw Error.unknownMajorVersion(found: self, latestKnown: Self.current) + } + } + + enum CodingKeys: String, CodingKey { + case major, minor, patch + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(major, forKey: .major) + try container.encode(minor, forKey: .minor) + try container.encode(patch, forKey: .patch) + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + major = try container.decode(Int.self, forKey: .major) + minor = try container.decode(Int.self, forKey: .minor) + patch = try container.decode(Int.self, forKey: .patch) + } +} + +// MARK: Initialization + +extension DiagnosticFile.Diagnostic { + init(_ problem: Problem) { + self.source = problem.diagnostic.source + self.range = problem.diagnostic.range.map { .init($0) } + self.severity = problem.diagnostic.severity + self.summary = problem.diagnostic.summary + self.explanation = problem.diagnostic.explanation + self.solutions = problem.possibleSolutions.map { .init($0) } + self.notes = problem.diagnostic.notes.map { .init($0) } + } +} + +extension DiagnosticFile.Diagnostic.Range { + init(_ sourceRange: Range) { + start = .init(sourceRange.lowerBound) + end = .init(sourceRange.upperBound) + } +} + +extension DiagnosticFile.Diagnostic.Range.Location { + init(_ sourceLocation: SourceLocation) { + self.line = sourceLocation.line + self.column = sourceLocation.column + } +} + +extension DiagnosticFile.Diagnostic.Solution { + init(_ solution: Solution) { + self.summary = solution.summary + self.replacements = solution.replacements.map { .init($0) } + } +} + +extension DiagnosticFile.Diagnostic.Solution.Replacement { + init(_ replacement: Replacement) { + self.range = .init(replacement.range) + self.text = replacement.replacement + } +} + +extension DiagnosticFile.Diagnostic.Note { + init(_ note: DiagnosticNote) { + self.source = note.source + self.range = .init(note.range) + self.message = note.message + } +} diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFileWriter.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFileWriter.swift new file mode 100644 index 0000000000..8ea19ad3c4 --- /dev/null +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFileWriter.swift @@ -0,0 +1,30 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2023 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 + +public final class DiagnosticFileWriter: DiagnosticConsumer { + var outputPath: URL + public init(outputPath: URL) { + self.outputPath = outputPath + } + private var receivedProblems: [Problem] = [] + + public func receive(_ problems: [Problem]) { + receivedProblems.append(contentsOf: problems) + } + + public func finalize() throws { + let fileContent = DiagnosticFile(problems: receivedProblems) + receivedProblems = [] + let encoder = RenderJSONEncoder.makeEncoder(emitVariantOverrides: false) + try encoder.encode(fileContent).write(to: outputPath, options: .atomic) + } +} diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFormattingOptions.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFormattingOptions.swift index 6a759e67b9..1b653f0220 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFormattingOptions.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFormattingOptions.swift @@ -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-2023 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 @@ -17,8 +17,12 @@ public struct DiagnosticFormattingOptions: OptionSet { } /// Problem fix-its should be included when printing diagnostics to a file or output stream. - public static let showFixits = DiagnosticFormattingOptions(rawValue: 1 << 0) + @available(*, deprecated, renamed: "formatConsoleOutputForTools") + public static let showFixits = formatConsoleOutputForTools + + /// Output to the console should be formatted for an IDE or other tool to parse. + public static let formatConsoleOutputForTools = DiagnosticFormattingOptions(rawValue: 1 << 0) /// All of the available formatting options. - public static let all: DiagnosticFormattingOptions = [.showFixits] + public static let all: DiagnosticFormattingOptions = [.formatConsoleOutputForTools] } diff --git a/Sources/SwiftDocC/Infrastructure/DocumentationConverter.swift b/Sources/SwiftDocC/Infrastructure/DocumentationConverter.swift index 8256d0ae32..1c2102eed0 100644 --- a/Sources/SwiftDocC/Infrastructure/DocumentationConverter.swift +++ b/Sources/SwiftDocC/Infrastructure/DocumentationConverter.swift @@ -381,6 +381,8 @@ public struct DocumentationConverter: DocumentationConverterProtocol { context.linkResolutionMismatches.reportGatheredMismatchesIfEnabled() + diagnosticEngine.finalize() + return (analysisProblems: context.problems, conversionProblems: conversionProblems) } diff --git a/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift b/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift index e5ca056521..cf9e5ed040 100644 --- a/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift +++ b/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift @@ -98,7 +98,8 @@ public struct ConvertAction: Action, RecreatingContext { bundleDiscoveryOptions: BundleDiscoveryOptions = .init(), diagnosticLevel: String? = nil, diagnosticEngine: DiagnosticEngine? = nil, - emitFixits: Bool = false, + diagnosticFilePath: URL? = nil, + formatConsoleOutputForTools: Bool = false, inheritDocs: Bool = false, treatWarningsAsErrors: Bool = false, experimentalEnableCustomTemplates: Bool = false, @@ -131,8 +132,8 @@ public struct ConvertAction: Action, RecreatingContext { } let formattingOptions: DiagnosticFormattingOptions - if emitFixits { - formattingOptions = [.showFixits] + if formatConsoleOutputForTools || diagnosticFilePath != nil { + formattingOptions = [.formatConsoleOutputForTools] } else { formattingOptions = [] } @@ -144,6 +145,9 @@ public struct ConvertAction: Action, RecreatingContext { let engine = diagnosticEngine ?? DiagnosticEngine(treatWarningsAsErrors: treatWarningsAsErrors) engine.filterLevel = filterLevel engine.add(DiagnosticConsoleWriter(formattingOptions: formattingOptions)) + if let diagnosticFilePath = diagnosticFilePath { + engine.add(DiagnosticFileWriter(outputPath: diagnosticFilePath)) + } self.diagnosticEngine = engine self.context = try context ?? DocumentationContext(dataProvider: workspace, diagnosticEngine: engine) @@ -192,6 +196,52 @@ public struct ConvertAction: Action, RecreatingContext { ) } + @available(*, deprecated, renamed: "init(documentationBundleURL:outOfProcessResolver:analyze:targetDirectory:htmlTemplateDirectory:emitDigest:currentPlatforms:buildIndex:workspace:context:dataProvider:documentationCoverageOptions:bundleDiscoveryOptions:diagnosticLevel:diagnosticEngine:formatConsoleOutputForTools:inheritDocs:experimentalEnableCustomTemplates:transformForStaticHosting:hostingBasePath:sourceRepository:temporaryDirectory:)") + public init( + documentationBundleURL: URL, outOfProcessResolver: OutOfProcessReferenceResolver?, + analyze: Bool, targetDirectory: URL, htmlTemplateDirectory: URL?, emitDigest: Bool, + currentPlatforms: [String : PlatformVersion]?, buildIndex: Bool = false, + workspace: DocumentationWorkspace = DocumentationWorkspace(), + context: DocumentationContext? = nil, + dataProvider: DocumentationWorkspaceDataProvider? = nil, + documentationCoverageOptions: DocumentationCoverageOptions = .noCoverage, + bundleDiscoveryOptions: BundleDiscoveryOptions = .init(), + diagnosticLevel: String? = nil, + diagnosticEngine: DiagnosticEngine? = nil, + emitFixits: Bool, // No default value, this argument has been renamed + inheritDocs: Bool = false, + experimentalEnableCustomTemplates: Bool = false, + transformForStaticHosting: Bool, + hostingBasePath: String?, + sourceRepository: SourceRepository? = nil, + temporaryDirectory: URL + ) throws { + try self.init( + documentationBundleURL: documentationBundleURL, + outOfProcessResolver: outOfProcessResolver, + analyze: analyze, + targetDirectory: targetDirectory, + htmlTemplateDirectory: htmlTemplateDirectory, + emitDigest: emitDigest, + currentPlatforms: currentPlatforms, + buildIndex: buildIndex, + workspace: workspace, + context: context, + dataProvider: dataProvider, + documentationCoverageOptions: documentationCoverageOptions, + bundleDiscoveryOptions: bundleDiscoveryOptions, + diagnosticLevel: diagnosticLevel, + diagnosticEngine: diagnosticEngine, + formatConsoleOutputForTools: emitFixits, + inheritDocs: inheritDocs, + experimentalEnableCustomTemplates: experimentalEnableCustomTemplates, + transformForStaticHosting: transformForStaticHosting, + hostingBasePath: hostingBasePath, + sourceRepository: sourceRepository, + temporaryDirectory: temporaryDirectory + ) + } + /// Initializes the action with the given validated options, creates or uses the given action workspace & context. /// - Parameter workspace: A provided documentation workspace. Creates a new empty workspace if value is `nil` /// - Parameter context: A provided documentation context. Creates a new empty context in the workspace if value is `nil` @@ -210,7 +260,7 @@ public struct ConvertAction: Action, RecreatingContext { bundleDiscoveryOptions: BundleDiscoveryOptions = .init(), diagnosticLevel: String? = nil, diagnosticEngine: DiagnosticEngine? = nil, - emitFixits: Bool = false, + formatConsoleOutputForTools: Bool = false, inheritDocs: Bool = false, experimentalEnableCustomTemplates: Bool = false, transformForStaticHosting: Bool, @@ -243,7 +293,7 @@ public struct ConvertAction: Action, RecreatingContext { bundleDiscoveryOptions: bundleDiscoveryOptions, diagnosticLevel: diagnosticLevel, diagnosticEngine: diagnosticEngine, - emitFixits: emitFixits, + formatConsoleOutputForTools: formatConsoleOutputForTools, inheritDocs: inheritDocs, experimentalEnableCustomTemplates: experimentalEnableCustomTemplates, transformForStaticHosting: transformForStaticHosting, diff --git a/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift b/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift index d8aaef70cd..b870a203b4 100644 --- a/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift +++ b/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift @@ -78,7 +78,8 @@ extension ConvertAction { ), bundleDiscoveryOptions: bundleDiscoveryOptions, diagnosticLevel: convert.diagnosticLevel, - emitFixits: convert.emitFixits, + diagnosticFilePath: convert.diagnosticsOutputPath, + formatConsoleOutputForTools: convert.formatConsoleOutputForTools, inheritDocs: convert.enableInheritedDocs, treatWarningsAsErrors: convert.warningsAsErrors, experimentalEnableCustomTemplates: convert.experimentalEnableCustomTemplates, diff --git a/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift b/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift index 9cccfd8c34..9d0001b99b 100644 --- a/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift +++ b/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift @@ -99,12 +99,28 @@ extension Docc { @Flag(help: .hidden) public var index = false - /// A user-provided value that is true if fix-its should be written to output. - /// - /// Defaults to false. - @Flag(inversion: .prefixedNo, help: "Outputs fixits for common issues") - public var emitFixits = false - + @available(*, deprecated, renamed: "formatConsoleOutputForTools") + public var emitFixits: Bool { + return formatConsoleOutputForTools + } + + /// A user-provided value that is true if output to the console should be formatted for an IDE or other tool to parse. + @Flag( + name: [.customLong("ide-console-output"), .customLong("emit-fixits")], + help: "Format output to the console intended for an IDE or other tool to parse.") + public var formatConsoleOutputForTools = false + + /// A user-provided location where the convert action writes the diagnostics file. + @Option( + name: [.customLong("diagnostics-file"), .customLong("diagnostics-output-path")], + help: ArgumentHelp( + "The location where the documentation compiler writes the diagnostics file.", + discussion: "Specifying a diagnostic file path implies '--ide-console-output'." + ), + transform: URL.init(fileURLWithPath:) + ) + var diagnosticsOutputPath: URL? + /// A user-provided value that is true if the user wants to opt in to Experimental documentation coverage generation. /// /// Defaults to none. diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticConsoleWriterTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticConsoleWriterTests.swift index e07e86c63b..d488431359 100644 --- a/Tests/SwiftDocCTests/Diagnostics/DiagnosticConsoleWriterTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticConsoleWriterTests.swift @@ -75,7 +75,7 @@ class DiagnosticConsoleWriterTests: XCTestCase { let problem = Problem(diagnostic: diagnostic, possibleSolutions: [solution]) let logger = Logger() - let consumer = DiagnosticConsoleWriter(logger, formattingOptions: [.showFixits]) + let consumer = DiagnosticConsoleWriter(logger, formattingOptions: [.formatConsoleOutputForTools]) consumer.receive([problem]) XCTAssertEqual(logger.output, """ \(expectedLocation): error: \(summary). \(solutionSummary). @@ -95,7 +95,7 @@ class DiagnosticConsoleWriterTests: XCTestCase { let problem = Problem(diagnostic: diagnostic, possibleSolutions: [firstSolution, secondSolution]) let logger = Logger() - let consumer = DiagnosticConsoleWriter(logger, formattingOptions: [.showFixits]) + let consumer = DiagnosticConsoleWriter(logger, formattingOptions: [.formatConsoleOutputForTools]) consumer.receive([problem]) XCTAssertEqual(logger.output, """ \(expectedLocation): error: \(summary). \(firstSolutionSummary) \(secondSolutionSummary). @@ -116,7 +116,7 @@ class DiagnosticConsoleWriterTests: XCTestCase { let problem = Problem(diagnostic: diagnostic, possibleSolutions: [solution]) let logger = Logger() - let consumer = DiagnosticConsoleWriter(logger, formattingOptions: [.showFixits]) + let consumer = DiagnosticConsoleWriter(logger, formattingOptions: [.formatConsoleOutputForTools]) consumer.receive([problem]) XCTAssertEqual(logger.output, """ \(expectedLocation): error: \(summary). \(solutionSummary). diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift index a893ef0456..41ce4a8262 100644 --- a/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift @@ -21,6 +21,7 @@ class DiagnosticEngineTests: XCTestCase { func receive(_ problems: [Problem]) { expectation.fulfill() } + func finalize() { } } func testEmitDiagnostic() { diff --git a/Tests/SwiftDocCTests/Diagnostics/ProblemTests.swift b/Tests/SwiftDocCTests/Diagnostics/ProblemTests.swift index 0b8557029f..18ca8d8ba9 100644 --- a/Tests/SwiftDocCTests/Diagnostics/ProblemTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/ProblemTests.swift @@ -50,7 +50,7 @@ class ProblemTests: XCTestCase { let diagnostic = Diagnostic(source: source, severity: .error, range: range, identifier: identifier, summary: summary, explanation: explanation) let problem = Problem(diagnostic: diagnostic, possibleSolutions: [solution]) - XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(problem, options: [.showFixits]), """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(problem, options: [.formatConsoleOutputForTools]), """ \(expectedLocation): error: \(summary). \(solutionSummary). \(explanation) \(source):1:8-1:24: fixit: Replacement text From b3f1cf532e02e1fc9a0079bded6d1fb5716a2866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Tue, 28 Feb 2023 14:29:47 -0800 Subject: [PATCH 05/16] Update calls to deprecated diagnostic properties --- .../Convert/ConvertFileWritingConsumer.swift | 4 +- .../Diagnostics/DiagnosticTests.swift | 8 ++-- .../DocumentationContextTests.swift | 16 +++---- .../DocumentationCuratorTests.swift | 4 +- .../ExternalReferenceResolverTests.swift | 2 +- .../ReferenceResolverTests.swift | 2 +- .../Model/SemaToRenderNodeTests.swift | 6 +-- .../HasOnlySequentialHeadingsTests.swift | 4 +- .../Semantics/MetadataTests.swift | 8 ++-- .../Semantics/RedirectedTests.swift | 14 +++--- .../Semantics/SymbolTests.swift | 48 +++++++++---------- .../Semantics/TutorialArticleTests.swift | 4 +- .../ConvertActionTests.swift | 2 +- .../ProblemTests.swift | 2 +- .../SemanticAnalyzerTests.swift | 6 +-- 15 files changed, 65 insertions(+), 65 deletions(-) diff --git a/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertFileWritingConsumer.swift b/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertFileWritingConsumer.swift index bb4eeaf731..b4bc2d5e3a 100644 --- a/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertFileWritingConsumer.swift +++ b/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertFileWritingConsumer.swift @@ -253,8 +253,8 @@ private extension Digest.Diagnostic { self.start = (diagnostic.range?.lowerBound).map { Location(line: $0.line, column: $0.column) } self.source = rootURL.flatMap { diagnostic.source?.relative(to: $0) } self.severity = diagnostic.severity - self.summary = diagnostic.localizedSummary - self.explanation = diagnostic.localizedExplanation + self.summary = diagnostic.summary + self.explanation = diagnostic.explanation self.notes = diagnostic.notes.map { Note(location: Location(line: $0.range.lowerBound.line, column: $0.range.lowerBound.column), message: $0.message) } diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift index 1d4b050d39..14b3ca197b 100644 --- a/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift @@ -22,13 +22,13 @@ class DiagnosticTests: XCTestCase { func testLocalizedSummary() { let expectedDump = "This is a test diagnostic" - XCTAssertEqual(expectedDump, basicDiagnostic.localizedSummary) + XCTAssertEqual(expectedDump, basicDiagnostic.summary) } func testLocalizedExplanation() { - XCTAssertNil(nonexistentDiagnostic.localizedExplanation) - guard let explanation = basicDiagnostic.localizedExplanation else { - XCTFail("basicDiagnostic.localizedExplanation was nil.") + XCTAssertNil(nonexistentDiagnostic.explanation) + guard let explanation = basicDiagnostic.explanation else { + XCTFail("basicDiagnostic.explanation was nil.") return } let expectedDump = """ diff --git a/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift b/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift index b79b4453ac..9c428189d4 100644 --- a/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift @@ -649,7 +649,7 @@ class DocumentationContextTests: XCTestCase { XCTAssertEqual(problemWithDuplicate.count, 1) - let localizedSummary = try XCTUnwrap(problemWithDuplicate.first?.diagnostic.localizedSummary) + let localizedSummary = try XCTUnwrap(problemWithDuplicate.first?.diagnostic.summary) XCTAssertEqual(localizedSummary, "Redeclaration of 'TestTutorial.tutorial'; this file will be skipped") } @@ -661,10 +661,10 @@ class DocumentationContextTests: XCTestCase { XCTAssertEqual(problemWithDuplicateReference.count, 2) - let localizedSummary = try XCTUnwrap(problemWithDuplicateReference.first?.diagnostic.localizedSummary) + let localizedSummary = try XCTUnwrap(problemWithDuplicateReference.first?.diagnostic.summary) XCTAssertEqual(localizedSummary, "Redeclaration of \'overview.md\'; this file will be skipped") - let localizedSummarySecond = try XCTUnwrap(problemWithDuplicateReference[1].diagnostic.localizedSummary) + let localizedSummarySecond = try XCTUnwrap(problemWithDuplicateReference[1].diagnostic.summary) XCTAssertEqual(localizedSummarySecond, "Redeclaration of \'overview.md\'; this file will be skipped") } @@ -1172,12 +1172,12 @@ class DocumentationContextTests: XCTestCase { XCTAssertNotNil(context.problems .map { $0.diagnostic } .filter { $0.identifier == "org.swift.docc.DuplicateMarkdownTitleSymbolReferences" - && $0.localizedSummary.contains("'/mykit'") } + && $0.summary.contains("'/mykit'") } ) XCTAssertNotNil(context.problems .map { $0.diagnostic } .filter { $0.identifier == "org.swift.docc.DuplicateMarkdownTitleSymbolReferences" - && $0.localizedSummary.contains("'/myprotocol'") } + && $0.summary.contains("'/myprotocol'") } ) } @@ -1760,7 +1760,7 @@ let expected = """ if let unmatchedSidecarDiagnostic = unmatchedSidecarProblem?.diagnostic { XCTAssertTrue(sidecarFilesForUnknownSymbol.contains(unmatchedSidecarDiagnostic.source?.standardizedFileURL), "One of the files should be the diagnostic source") XCTAssertEqual(unmatchedSidecarDiagnostic.range, SourceLocation(line: 1, column: 3, source: unmatchedSidecarProblem?.diagnostic.source).. Bool in return problem.diagnostic.identifier == "org.swift.docc.InvalidDocumentationLink" - && problem.diagnostic.localizedSummary.contains("https://external.com/link") + && problem.diagnostic.summary.contains("https://external.com/link") })) } @@ -2696,7 +2696,7 @@ Document return p.diagnostic.identifier == "org.swift.docc.unresolvedResource" } XCTAssertFalse(missingResources.contains(where: { p -> Bool in - return p.diagnostic.localizedSummary == "Resource 'my-inherited-image.png' couldn't be found" + return p.diagnostic.summary == "Resource 'my-inherited-image.png' couldn't be found" })) let myFuncReference = ResolvedTopicReference(bundleIdentifier: bundle.identifier, path: "/documentation/SideKit/SideClass/Element/inherited()", sourceLanguage: .swift) @@ -2899,7 +2899,7 @@ Document // Verify that we don't reference resolve inherited docs. XCTAssertFalse(context.diagnosticEngine.problems.contains(where: { problem in - problem.diagnostic.localizedSummary.contains("my-inherited-image.png") + problem.diagnostic.summary.contains("my-inherited-image.png") })) let myFuncReference = ResolvedTopicReference(bundleIdentifier: bundle.identifier, path: "/documentation/SideKit/SideClass/Element/inherited()", sourceLanguage: .swift) diff --git a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlySequentialHeadingsTests.swift b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlySequentialHeadingsTests.swift index 932a8ffdcd..2b504ccc44 100644 --- a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlySequentialHeadingsTests.swift +++ b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlySequentialHeadingsTests.swift @@ -70,7 +70,7 @@ some more *stuff* var problems: [Problem] = [] Semantic.Analyses.HasOnlySequentialHeadings(severityIfFound: .warning, startingFromLevel: 2).analyze(containerDirective, children: document.children, source: nil, for: bundle, in: context, problems: &problems) - XCTAssertEqual(problems.map { $0.diagnostic.localizedSummary }, + XCTAssertEqual(problems.map { $0.diagnostic.summary }, [ "This heading doesn't meet or exceed the minimum allowed heading level (2)", "This heading doesn't meet or exceed the minimum allowed heading level (2)", @@ -91,7 +91,7 @@ some more *stuff* var problems: [Problem] = [] Semantic.Analyses.HasOnlySequentialHeadings(severityIfFound: .warning, startingFromLevel: 2).analyze(containerDirective, children: document.children, source: nil, for: bundle, in: context, problems: &problems) - XCTAssertEqual(problems.map { $0.diagnostic.localizedSummary }, + XCTAssertEqual(problems.map { $0.diagnostic.summary }, [ "This heading doesn't sequentially follow the previous heading", "This heading doesn't sequentially follow the previous heading", diff --git a/Tests/SwiftDocCTests/Semantics/MetadataTests.swift b/Tests/SwiftDocCTests/Semantics/MetadataTests.swift index e35f69df8f..d0e6bb20a6 100644 --- a/Tests/SwiftDocCTests/Semantics/MetadataTests.swift +++ b/Tests/SwiftDocCTests/Semantics/MetadataTests.swift @@ -126,7 +126,7 @@ class MetadataTests: XCTestCase { var problems = [Problem]() let metadata = Metadata(from: directive, source: nil, for: bundle, in: context, problems: &problems) XCTAssertNotNil(metadata) - XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.localizedSummary })") + XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.summary })") XCTAssertEqual(metadata?.displayName?.name, "Custom Name") } @@ -165,7 +165,7 @@ class MetadataTests: XCTestCase { var problems = [Problem]() let article = Article(from: document, source: nil, for: bundle, in: context, problems: &problems) XCTAssertNotNil(article, "An Article value can be created with a Metadata child.") - XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.localizedSummary })") + XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.summary })") var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) @@ -189,7 +189,7 @@ class MetadataTests: XCTestCase { XCTAssertNotNil(article, "An Article value can be created with a Metadata child with a DisplayName child.") XCTAssertNotNil(article?.metadata?.displayName, "The Article has the parsed DisplayName metadata.") - XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.localizedSummary })") + XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.summary })") var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) @@ -218,7 +218,7 @@ class MetadataTests: XCTestCase { let problem = try XCTUnwrap(problems.first) XCTAssertEqual(problem.diagnostic.identifier, "org.swift.docc.Article.DisplayName.NotSupported") - XCTAssertEqual(problem.diagnostic.localizedSummary, "A 'DisplayName' directive is only supported in documentation extension files. To customize the display name of an article, change the content of the level-1 heading.") + XCTAssertEqual(problem.diagnostic.summary, "A 'DisplayName' directive is only supported in documentation extension files. To customize the display name of an article, change the content of the level-1 heading.") XCTAssertEqual(problem.possibleSolutions.count, 1) let solution = try XCTUnwrap(problem.possibleSolutions.first) diff --git a/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift b/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift index 53d78cb47a..95a6299ad9 100644 --- a/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift +++ b/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift @@ -58,7 +58,7 @@ class RedirectedTests: XCTestCase { XCTAssertEqual(1, problems.count) XCTAssertEqual(problems.first?.diagnostic.identifier, "org.swift.docc.HasArgument.from.ConversionFailed") XCTAssertEqual( - problems.first?.diagnostic.localizedSummary, + problems.first?.diagnostic.summary, "Cannot convert '\(pathWithInvalidCharacter)' to type 'URL'" ) } @@ -134,7 +134,7 @@ class RedirectedTests: XCTestCase { var problems = [Problem]() let technology = Technology(from: directive, source: nil, for: bundle, in: context, problems: &problems) XCTAssertNotNil(technology, "A Technology value can be created with a Redirected child.") - XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.localizedSummary })") + XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.summary })") var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) @@ -166,7 +166,7 @@ class RedirectedTests: XCTestCase { var problems = [Problem]() let volume = Volume(from: directive, source: nil, for: bundle, in: context, problems: &problems) XCTAssertNotNil(volume, "A Volume value can be created with a Redirected child.") - XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.localizedSummary })") + XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.summary })") } func testTutorialAndSectionsSupportsRedirect() throws { @@ -231,7 +231,7 @@ class RedirectedTests: XCTestCase { var problems = [Problem]() let tutorial = Tutorial(from: directive, source: nil, for: bundle, in: context, problems: &problems) XCTAssertNotNil(tutorial, "A Tutorial value can be created with a Redirected child.") - XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.localizedSummary })") + XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.summary })") var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) @@ -259,7 +259,7 @@ class RedirectedTests: XCTestCase { var problems = [Problem]() let article = TutorialArticle(from: directive, source: nil, for: bundle, in: context, problems: &problems) XCTAssertNotNil(article, "A TutorialArticle value can be created with a Redirected child.") - XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.localizedSummary })") + XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.summary })") var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) @@ -308,7 +308,7 @@ class RedirectedTests: XCTestCase { var problems = [Problem]() let article = Resources(from: directive, source: nil, for: bundle, in: context, problems: &problems) XCTAssertNotNil(article, "A Resources value can be created with a Redirected child.") - XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.localizedSummary })") + XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.summary })") } func testArticleSupportsRedirect() throws { @@ -329,7 +329,7 @@ class RedirectedTests: XCTestCase { var problems = [Problem]() let article = Article(from: document, source: nil, for: bundle, in: context, problems: &problems) XCTAssertNotNil(article, "An Article value can be created with a Redirected child.") - XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.localizedSummary })") + XCTAssert(problems.isEmpty, "There shouldn't be any problems. Got:\n\(problems.map { $0.diagnostic.summary })") var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) diff --git a/Tests/SwiftDocCTests/Semantics/SymbolTests.swift b/Tests/SwiftDocCTests/Semantics/SymbolTests.swift index 32df4aa1f8..98c5a1f700 100644 --- a/Tests/SwiftDocCTests/Semantics/SymbolTests.swift +++ b/Tests/SwiftDocCTests/Semantics/SymbolTests.swift @@ -560,26 +560,26 @@ class SymbolTests: XCTestCase { let unresolvedTopicProblems = context.problems.filter { $0.diagnostic.identifier == "org.swift.docc.unresolvedTopicReference" } - XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.localizedSummary == "Topic reference 'doc://com.test.external/ExternalPage' couldn't be resolved. No external resolver registered for 'com.test.external'." })) + XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.summary == "Topic reference 'doc://com.test.external/ExternalPage' couldn't be resolved. No external resolver registered for 'com.test.external'." })) if LinkResolutionMigrationConfiguration.shouldUseHierarchyBasedLinkResolver { var problem: Problem - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'UnresolvableSymbolLinkInMyClassOverview<>(_:))' couldn't be resolved. Reference at '/MyKit/MyClass' can't resolve 'UnresolvableSymbolLinkInMyClassOverview<>(_:))'. No similar pages." })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'UnresolvableSymbolLinkInMyClassOverview<>(_:))' couldn't be resolved. Reference at '/MyKit/MyClass' can't resolve 'UnresolvableSymbolLinkInMyClassOverview<>(_:))'. No similar pages." })) XCTAssertEqual(problem.diagnostic.notes.map(\.message), ["Available children: init(), myFunction()."]) XCTAssertEqual(problem.possibleSolutions.count, 2) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'UnresolvableClassInMyClassTopicCuration' couldn't be resolved. Reference at '/MyKit/MyClass' can't resolve 'UnresolvableClassInMyClassTopicCuration'. No similar pages." })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'UnresolvableClassInMyClassTopicCuration' couldn't be resolved. Reference at '/MyKit/MyClass' can't resolve 'UnresolvableClassInMyClassTopicCuration'. No similar pages." })) XCTAssertEqual(problem.diagnostic.notes.map(\.message), ["Available children: init(), myFunction()."]) XCTAssertEqual(problem.possibleSolutions.count, 2) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'MyClass/unresolvablePropertyInMyClassTopicCuration' couldn't be resolved. Reference at '/MyKit/MyClass' can't resolve 'unresolvablePropertyInMyClassTopicCuration'. No similar pages." })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'MyClass/unresolvablePropertyInMyClassTopicCuration' couldn't be resolved. Reference at '/MyKit/MyClass' can't resolve 'unresolvablePropertyInMyClassTopicCuration'. No similar pages." })) XCTAssertEqual(problem.diagnostic.notes.map(\.message), ["Available children: init(), myFunction()."]) XCTAssertEqual(problem.possibleSolutions.count, 2) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'init()' couldn't be resolved. Reference is ambiguous after '/MyKit/MyClass'." })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'init()' couldn't be resolved. Reference is ambiguous after '/MyKit/MyClass'." })) XCTAssert(problem.diagnostic.notes.isEmpty) XCTAssertEqual(problem.possibleSolutions.count, 2) XCTAssert(problem.possibleSolutions.map(\.replacements.count).allSatisfy { $0 == 1 }) @@ -625,7 +625,7 @@ class SymbolTests: XCTestCase { """) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'MyClass/init()-swift.init' couldn't be resolved. Reference is ambiguous after '/MyKit/MyClass'." })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'MyClass/init()-swift.init' couldn't be resolved. Reference is ambiguous after '/MyKit/MyClass'." })) XCTAssert(problem.diagnostic.notes.isEmpty) XCTAssertEqual(problem.possibleSolutions.count, 2) XCTAssert(problem.possibleSolutions.map(\.replacements.count).allSatisfy { $0 == 1 }) @@ -671,7 +671,7 @@ class SymbolTests: XCTestCase { """) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'doc:MyClass/init()-swift.init' couldn't be resolved. Reference is ambiguous after '/MyKit/MyClass'." })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'doc:MyClass/init()-swift.init' couldn't be resolved. Reference is ambiguous after '/MyKit/MyClass'." })) XCTAssert(problem.diagnostic.notes.isEmpty) XCTAssertEqual(problem.possibleSolutions.count, 2) XCTAssert(problem.possibleSolutions.map(\.replacements.count).allSatisfy { $0 == 1 }) @@ -717,7 +717,7 @@ class SymbolTests: XCTestCase { """) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'otherFunction()' couldn't be resolved. Reference at '/MyKit/MyClass' can't resolve 'otherFunction()'. Did you mean myFunction()?" })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'otherFunction()' couldn't be resolved. Reference at '/MyKit/MyClass' can't resolve 'otherFunction()'. Did you mean myFunction()?" })) XCTAssertEqual(problem.diagnostic.notes.map(\.message), ["Available children: init(), myFunction()."]) XCTAssertEqual(problem.possibleSolutions.count, 1) XCTAssert(problem.possibleSolutions.map(\.replacements.count).allSatisfy { $0 == 1 }) @@ -762,7 +762,7 @@ class SymbolTests: XCTestCase { """) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference '/MyKit/MyClas' couldn't be resolved. Reference at '/MyKit' can't resolve 'MyClas'. Did you mean MyClass?" })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference '/MyKit/MyClas' couldn't be resolved. Reference at '/MyKit' can't resolve 'MyClas'. Did you mean MyClass?" })) XCTAssertEqual(problem.diagnostic.notes.map(\.message), ["Available children: Discussion, globalFunction(_:considering:), MyClass, MyProtocol."]) XCTAssertEqual(problem.possibleSolutions.count, 1) XCTAssert(problem.possibleSolutions.map(\.replacements.count).allSatisfy { $0 == 1 }) @@ -807,7 +807,7 @@ class SymbolTests: XCTestCase { """) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'MyKit/MyClas/myFunction()' couldn't be resolved. Reference at '/MyKit' can't resolve 'MyClas/myFunction()'. Did you mean MyClass?" })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'MyKit/MyClas/myFunction()' couldn't be resolved. Reference at '/MyKit' can't resolve 'MyClas/myFunction()'. Did you mean MyClass?" })) XCTAssertEqual(problem.diagnostic.notes.map(\.message), ["Available children: Discussion, globalFunction(_:considering:), MyClass, MyProtocol."]) XCTAssertEqual(problem.possibleSolutions.count, 1) XCTAssert(problem.possibleSolutions.map(\.replacements.count).allSatisfy { $0 == 1 }) @@ -852,7 +852,7 @@ class SymbolTests: XCTestCase { """) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'MyKit/MyClas/myFunction()' couldn't be resolved. Reference at '/MyKit' can't resolve 'MyClas/myFunction()'. Did you mean MyClass?" })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'MyKit/MyClas/myFunction()' couldn't be resolved. Reference at '/MyKit' can't resolve 'MyClas/myFunction()'. Did you mean MyClass?" })) XCTAssertEqual(problem.diagnostic.notes.map(\.message), ["Available children: Discussion, globalFunction(_:considering:), MyClass, MyProtocol."]) XCTAssertEqual(problem.possibleSolutions.count, 1) XCTAssert(problem.possibleSolutions.map(\.replacements.count).allSatisfy { $0 == 1 }) @@ -897,7 +897,7 @@ class SymbolTests: XCTestCase { """) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'doc:MyKit/MyClas/myFunction()' couldn't be resolved. Reference at '/MyKit' can't resolve 'MyClas/myFunction()'. Did you mean MyClass?" })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'doc:MyKit/MyClas/myFunction()' couldn't be resolved. Reference at '/MyKit' can't resolve 'MyClas/myFunction()'. Did you mean MyClass?" })) XCTAssertEqual(problem.diagnostic.notes.map(\.message), ["Available children: Discussion, globalFunction(_:considering:), MyClass, MyProtocol."]) XCTAssertEqual(problem.possibleSolutions.count, 1) XCTAssert(problem.possibleSolutions.map(\.replacements.count).allSatisfy { $0 == 1 }) @@ -941,11 +941,11 @@ class SymbolTests: XCTestCase { - """) } else { - XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.localizedSummary == "Topic reference 'UnresolvableSymbolLinkInMyClassOverview<>(_:))' couldn't be resolved. No local documentation matches this reference." })) - XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.localizedSummary == "Topic reference 'UnresolvableClassInMyClassTopicCuration' couldn't be resolved. No local documentation matches this reference." })) - XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.localizedSummary == "Topic reference 'MyClass/unresolvablePropertyInMyClassTopicCuration' couldn't be resolved. No local documentation matches this reference." })) - XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.localizedSummary == "Topic reference 'init()' couldn't be resolved. No local documentation matches this reference." })) - XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.localizedSummary == "Topic reference 'MyClass/init()-swift.init' couldn't be resolved. No local documentation matches this reference." })) + XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.summary == "Topic reference 'UnresolvableSymbolLinkInMyClassOverview<>(_:))' couldn't be resolved. No local documentation matches this reference." })) + XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.summary == "Topic reference 'UnresolvableClassInMyClassTopicCuration' couldn't be resolved. No local documentation matches this reference." })) + XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.summary == "Topic reference 'MyClass/unresolvablePropertyInMyClassTopicCuration' couldn't be resolved. No local documentation matches this reference." })) + XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.summary == "Topic reference 'init()' couldn't be resolved. No local documentation matches this reference." })) + XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.summary == "Topic reference 'MyClass/init()-swift.init' couldn't be resolved. No local documentation matches this reference." })) } } @@ -988,7 +988,7 @@ class SymbolTests: XCTestCase { if LinkResolutionMigrationConfiguration.shouldUseHierarchyBasedLinkResolver { var problem: Problem - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'UnresolvableSymbolLinkInMyClassOverview' couldn't be resolved. Reference at '/MyKit/MyClass/myFunction()' can't resolve 'UnresolvableSymbolLinkInMyClassOverview'. Did you mean Unresolvable-curation?" })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'UnresolvableSymbolLinkInMyClassOverview' couldn't be resolved. Reference at '/MyKit/MyClass/myFunction()' can't resolve 'UnresolvableSymbolLinkInMyClassOverview'. Did you mean Unresolvable-curation?" })) XCTAssert(problem.diagnostic.notes.isEmpty) XCTAssertEqual(problem.possibleSolutions.count, 1) XCTAssert(problem.possibleSolutions.map(\.replacements.count).allSatisfy { $0 == 1 }) @@ -1013,7 +1013,7 @@ class SymbolTests: XCTestCase { - """) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'UnresolvableClassInMyClassTopicCuration' couldn't be resolved. Reference at '/MyKit/MyClass/myFunction()' can't resolve 'UnresolvableClassInMyClassTopicCuration'. Did you mean Unresolvable-curation?" })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'UnresolvableClassInMyClassTopicCuration' couldn't be resolved. Reference at '/MyKit/MyClass/myFunction()' can't resolve 'UnresolvableClassInMyClassTopicCuration'. Did you mean Unresolvable-curation?" })) XCTAssert(problem.diagnostic.notes.isEmpty) XCTAssertEqual(problem.possibleSolutions.count, 1) XCTAssert(problem.possibleSolutions.map(\.replacements.count).allSatisfy { $0 == 1 }) @@ -1039,7 +1039,7 @@ class SymbolTests: XCTestCase { """) - problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.localizedSummary == "Topic reference 'MyClass/unresolvablePropertyInMyClassTopicCuration' couldn't be resolved. Reference at '/MyKit/MyClass' can't resolve 'unresolvablePropertyInMyClassTopicCuration'. No similar pages." })) + problem = try XCTUnwrap(unresolvedTopicProblems.first(where: { $0.diagnostic.summary == "Topic reference 'MyClass/unresolvablePropertyInMyClassTopicCuration' couldn't be resolved. Reference at '/MyKit/MyClass' can't resolve 'unresolvablePropertyInMyClassTopicCuration'. No similar pages." })) XCTAssert(problem.diagnostic.notes.isEmpty) XCTAssertEqual(problem.possibleSolutions.count, 2) XCTAssert(problem.possibleSolutions.map(\.replacements.count).allSatisfy { $0 == 1 }) @@ -1065,11 +1065,11 @@ class SymbolTests: XCTestCase { - """) } else { - XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.localizedSummary == "Topic reference 'UnresolvableSymbolLinkInMyClassOverview' couldn't be resolved. No local documentation matches this reference." })) - XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.localizedSummary == "Topic reference 'UnresolvableClassInMyClassTopicCuration' couldn't be resolved. No local documentation matches this reference." })) - XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.localizedSummary == "Topic reference 'MyClass/unresolvablePropertyInMyClassTopicCuration' couldn't be resolved. No local documentation matches this reference." })) + XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.summary == "Topic reference 'UnresolvableSymbolLinkInMyClassOverview' couldn't be resolved. No local documentation matches this reference." })) + XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.summary == "Topic reference 'UnresolvableClassInMyClassTopicCuration' couldn't be resolved. No local documentation matches this reference." })) + XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.summary == "Topic reference 'MyClass/unresolvablePropertyInMyClassTopicCuration' couldn't be resolved. No local documentation matches this reference." })) } - XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.localizedSummary == "Topic reference 'doc://com.test.external/ExternalPage' couldn't be resolved. No external resolver registered for 'com.test.external'." })) + XCTAssertTrue(unresolvedTopicProblems.contains(where: { $0.diagnostic.summary == "Topic reference 'doc://com.test.external/ExternalPage' couldn't be resolved. No external resolver registered for 'com.test.external'." })) } func testTopicSectionInDocComment() throws { diff --git a/Tests/SwiftDocCTests/Semantics/TutorialArticleTests.swift b/Tests/SwiftDocCTests/Semantics/TutorialArticleTests.swift index caa0f00290..8d144d68b2 100644 --- a/Tests/SwiftDocCTests/Semantics/TutorialArticleTests.swift +++ b/Tests/SwiftDocCTests/Semantics/TutorialArticleTests.swift @@ -275,8 +275,8 @@ TutorialArticle @1:1-23:2 title: 'Basic Augmented Reality App' time: '20' XCTAssertEqual(3, problems.count) let arbitraryMarkupProblem = problems.first(where: { $0.diagnostic.identifier == "org.swift.docc.Stack.UnexpectedContent" }) XCTAssertNotNil(arbitraryMarkupProblem) - XCTAssertEqual(arbitraryMarkupProblem?.diagnostic.localizedSummary, "'Stack' contains unexpected content") - XCTAssertEqual(arbitraryMarkupProblem?.diagnostic.localizedExplanation, "Arbitrary markup content is not allowed as a child of the 'Stack' directive.") + XCTAssertEqual(arbitraryMarkupProblem?.diagnostic.summary, "'Stack' contains unexpected content") + XCTAssertEqual(arbitraryMarkupProblem?.diagnostic.explanation, "Arbitrary markup content is not allowed as a child of the 'Stack' directive.") article.map { article in let expectedDump = """ TutorialArticle @1:1-81:2 diff --git a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift index 52127d9629..574bf5555d 100644 --- a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift @@ -2945,7 +2945,7 @@ class ConvertActionTests: XCTestCase { private func uniformlyPrintDiagnosticMessages(_ problems: [Problem]) -> String { return problems.sorted(by: { (lhs, rhs) -> Bool in guard lhs.diagnostic.identifier != rhs.diagnostic.identifier else { - return lhs.diagnostic.localizedSummary < rhs.diagnostic.localizedSummary + return lhs.diagnostic.summary < rhs.diagnostic.summary } return lhs.diagnostic.identifier < rhs.diagnostic.identifier }) .map { DiagnosticConsoleWriter.formattedDescriptionFor($0.diagnostic) }.sorted().joined(separator: "\n") diff --git a/Tests/SwiftDocCUtilitiesTests/ProblemTests.swift b/Tests/SwiftDocCUtilitiesTests/ProblemTests.swift index 9b89bffb84..f5f18a41be 100644 --- a/Tests/SwiftDocCUtilitiesTests/ProblemTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ProblemTests.swift @@ -19,6 +19,6 @@ class ProblemTests: XCTestCase { let problem = Problem(description: "Lorem ipsum", source: nil) XCTAssertNil(problem.diagnostic.source, "Convenience initializer for Problem should not capture source file location") XCTAssertEqual(problem.diagnostic.identifier, "org.swift.docc.ProblemTests") - XCTAssertEqual(problem.diagnostic.localizedSummary, "Lorem ipsum") + XCTAssertEqual(problem.diagnostic.summary, "Lorem ipsum") } } diff --git a/Tests/SwiftDocCUtilitiesTests/SemanticAnalyzerTests.swift b/Tests/SwiftDocCUtilitiesTests/SemanticAnalyzerTests.swift index 59af3ff9e7..510fe98977 100644 --- a/Tests/SwiftDocCUtilitiesTests/SemanticAnalyzerTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/SemanticAnalyzerTests.swift @@ -98,7 +98,7 @@ class SemanticAnalyzerTests: XCTestCase { XCTAssertEqual(problems.unsupportedTopLevelChildProblems.count, 1) if let diagnostic = problems.unsupportedTopLevelChildProblems.first?.diagnostic { - XCTAssertEqual(diagnostic.localizedSummary, "Found unsupported 'Article' directive in '.md' file") + XCTAssertEqual(diagnostic.summary, "Found unsupported 'Article' directive in '.md' file") XCTAssertEqual(diagnostic.severity, .warning) XCTAssertEqual(diagnostic.source?.lastPathComponent, "FileWithDirective.md") } @@ -111,8 +111,8 @@ class SemanticAnalyzerTests: XCTestCase { XCTAssertEqual(problems.unsupportedTopLevelChildProblems.count, 0) if let diagnostic = problems.missingTopLevelChildProblems.first?.diagnostic { - XCTAssertEqual(diagnostic.localizedSummary, "No valid content was found in this file") - XCTAssertEqual(diagnostic.localizedExplanation, "A '.tutorial' file should contain a top-level directive ('Tutorials', 'Tutorial', or 'Article') and valid child content. Only '.md' files support content without a top-level directive") + XCTAssertEqual(diagnostic.summary, "No valid content was found in this file") + XCTAssertEqual(diagnostic.explanation, "A '.tutorial' file should contain a top-level directive ('Tutorials', 'Tutorial', or 'Article') and valid child content. Only '.md' files support content without a top-level directive") XCTAssertEqual(diagnostic.severity, .warning) XCTAssertEqual(diagnostic.source?.lastPathComponent, "FileWithoutDirective.tutorial") } From 7c81333a8cbb980e1f984833dbb1ac65ac5eee1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Tue, 28 Feb 2023 14:30:30 -0800 Subject: [PATCH 06/16] Fix bug in preview test where some diagnostics were written twice --- .../PreviewActionIntegrationTests.swift | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift index 9fe4680424..70c8a22490 100644 --- a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift @@ -285,8 +285,6 @@ class PreviewActionIntegrationTests: XCTestCase { let workspace = DocumentationWorkspace() _ = try! DocumentationContext(dataProvider: workspace) - let engine = DiagnosticEngine() - let convertActionTempDirectory = try createTemporaryDirectory() let createConvertAction = { try ConvertAction( @@ -298,8 +296,7 @@ class PreviewActionIntegrationTests: XCTestCase { emitDigest: false, currentPlatforms: nil, fileManager: FileManager.default, - temporaryDirectory: convertActionTempDirectory, - diagnosticEngine: engine) + temporaryDirectory: convertActionTempDirectory) } guard let preview = try? PreviewAction( @@ -308,9 +305,10 @@ class PreviewActionIntegrationTests: XCTestCase { XCTFail("Could not create preview action from parameters", file: file, line: line) return } - // Start watching the source and get the initial (successful) state. do { + let engine = preview.convertAction.diagnosticEngine + // Wait for watch to produce output. let logOutputExpectation = expectation(description: "Did produce log output") let logChecker = OutputChecker(fileURL: pipeURL, expectation: logOutputExpectation) { output in From 05b6fb8b8c95ea52efe77b2ee92b95141141c510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Tue, 28 Feb 2023 14:31:28 -0800 Subject: [PATCH 07/16] Fix issue where preview tests would assert if one encountered an error --- .../PreviewActionIntegrationTests.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift index 70c8a22490..50a3aabfe4 100644 --- a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift @@ -305,6 +305,13 @@ class PreviewActionIntegrationTests: XCTestCase { XCTFail("Could not create preview action from parameters", file: file, line: line) return } + defer { + do { + try preview.stop() + } catch { + XCTFail("Failed to stop preview server", file: file, line: line) + } + } // Start watching the source and get the initial (successful) state. do { let engine = preview.convertAction.diagnosticEngine @@ -340,7 +347,6 @@ class PreviewActionIntegrationTests: XCTestCase { wait(for: [logOutputExpectation, erroredExpectation], timeout: 20.0) logTimer.invalidate() } - try preview.stop() #endif } From 8c199f6fb7afe933e6442595047e168613a86e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Wed, 1 Mar 2023 11:36:43 -0800 Subject: [PATCH 08/16] Separate formatting of diagnostics for tools and for people --- .../Diagnostics/DiagnosticConsoleWriter.swift | 75 ++++++++++++++++--- 1 file changed, 64 insertions(+), 11 deletions(-) diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift index 9692f642d1..78b8b610e5 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift @@ -17,14 +17,14 @@ public final class DiagnosticConsoleWriter: DiagnosticFormattingConsumer { var outputStream: TextOutputStream public var formattingOptions: DiagnosticFormattingOptions + private var diagnosticFormatter: DiagnosticConsoleFormatter /// Creates a new instance of this class with the provided output stream and filter level. /// - Parameter stream: The output stream to which this instance will write. /// - Parameter filterLevel: Determines what diagnostics should be printed. This filter level is inclusive, i.e. if a level of ``DiagnosticSeverity/information`` is specified, diagnostics with a severity up to and including `.information` will be printed. @available(*, deprecated, message: "Use init(_:formattingOptions:) instead") - public init(_ stream: TextOutputStream = LogHandle.standardError, filterLevel: DiagnosticSeverity = .warning) { - outputStream = stream - formattingOptions = [] + public convenience init(_ stream: TextOutputStream = LogHandle.standardError, filterLevel: DiagnosticSeverity = .warning) { + self.init(stream, formattingOptions: []) } /// Creates a new instance of this class with the provided output stream. @@ -32,16 +32,26 @@ public final class DiagnosticConsoleWriter: DiagnosticFormattingConsumer { public init(_ stream: TextOutputStream = LogHandle.standardError, formattingOptions options: DiagnosticFormattingOptions = []) { outputStream = stream formattingOptions = options + diagnosticFormatter = Self.makeDiagnosticFormatter(options) } public func receive(_ problems: [Problem]) { - let text = Self.formattedDescriptionFor(problems, options: formattingOptions).appending("\n") + // Add a newline after each formatter description, including the last one. + let text = problems.map { diagnosticFormatter.formattedDescription($0).appending("\n") }.joined() outputStream.write(text) } public func finalize() throws { // The console writer writes each diagnostic as they are received. } + + private static func makeDiagnosticFormatter(_ options: DiagnosticFormattingOptions) -> DiagnosticConsoleFormatter { + if options.contains(.formatConsoleOutputForTools) { + return IDEDiagnosticConsoleFormatter(options: options) + } else { + return DefaultDiagnosticConsoleFormatter(options: options) + } + } } // MARK: Formatted descriptions @@ -53,8 +63,38 @@ extension DiagnosticConsoleWriter { } public static func formattedDescriptionFor(_ problem: Problem, options: DiagnosticFormattingOptions = []) -> String { - guard let source = problem.diagnostic.source, options.contains(.formatConsoleOutputForTools) else { - return formattedDescriptionFor(problem.diagnostic) + let diagnosticFormatter = makeDiagnosticFormatter(options) + return diagnosticFormatter.formattedDescription(problem) + } + + public static func formattedDescriptionFor(_ diagnostic: Diagnostic, options: DiagnosticFormattingOptions = []) -> String { + let diagnosticFormatter = makeDiagnosticFormatter(options) + return diagnosticFormatter.formattedDescription(diagnostic) + } +} + +protocol DiagnosticConsoleFormatter { + var options: DiagnosticFormattingOptions { get set } + + func formattedDescription(_ problems: Problems) -> String where Problems: Sequence, Problems.Element == Problem + func formattedDescription(_ problem: Problem) -> String + func formattedDescription(_ diagnostic: Diagnostic) -> String +} + +extension DiagnosticConsoleFormatter { + func formattedDescription(_ problems: Problems) -> String where Problems: Sequence, Problems.Element == Problem { + return problems.map { formattedDescription($0) }.joined(separator: "\n") + } +} + +// MARK: IDE formatting + +struct IDEDiagnosticConsoleFormatter: DiagnosticConsoleFormatter { + var options: DiagnosticFormattingOptions + + func formattedDescription(_ problem: Problem) -> String { + guard let source = problem.diagnostic.source else { + return formattedDescription(problem.diagnostic) } var description = formattedDiagnosticSummary(problem.diagnostic) @@ -86,11 +126,11 @@ extension DiagnosticConsoleWriter { return description } - public static func formattedDescriptionFor(_ diagnostic: Diagnostic, options: DiagnosticFormattingOptions = []) -> String { + public func formattedDescription(_ diagnostic: Diagnostic) -> String { return formattedDiagnosticSummary(diagnostic) + formattedDiagnosticDetails(diagnostic) } - private static func formattedDiagnosticSummary(_ diagnostic: Diagnostic) -> String { + private func formattedDiagnosticSummary(_ diagnostic: Diagnostic) -> String { var result = "" if let range = diagnostic.range, let url = diagnostic.source { @@ -104,7 +144,7 @@ extension DiagnosticConsoleWriter { return result } - private static func formattedDiagnosticDetails(_ diagnostic: Diagnostic) -> String { + private func formattedDiagnosticDetails(_ diagnostic: Diagnostic) -> String { var result = "" if let explanation = diagnostic.explanation { @@ -113,14 +153,27 @@ extension DiagnosticConsoleWriter { if !diagnostic.notes.isEmpty { result += "\n" - result += diagnostic.notes.map { formattedDescriptionFor($0) }.joined(separator: "\n") + result += diagnostic.notes.map { formattedDescription($0) }.joined(separator: "\n") } return result } - private static func formattedDescriptionFor(_ note: DiagnosticNote, options: DiagnosticFormattingOptions = []) -> String { + private func formattedDescription(_ note: DiagnosticNote) -> String { let location = "\(note.source.path):\(note.range.lowerBound.line):\(note.range.lowerBound.column)" return "\(location): note: \(note.message)" } } + +// FIXME: Improve the readability for diagnostics on the command line https://github.com/apple/swift-docc/issues/496 +struct DefaultDiagnosticConsoleFormatter: DiagnosticConsoleFormatter { + var options: DiagnosticFormattingOptions + + func formattedDescription(_ problem: Problem) -> String { + formattedDescription(problem.diagnostic) + } + + func formattedDescription(_ diagnostic: Diagnostic) -> String { + return IDEDiagnosticConsoleFormatter(options: options).formattedDescription(diagnostic) + } +} From 1ffd90b75dc50019ede44adba45bf527b84f0c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Wed, 1 Mar 2023 11:44:31 -0800 Subject: [PATCH 09/16] Rename 'formattedDescriptionFor(...)' to 'formattedDescription(...)' --- .../Convert/ConvertService.swift | 2 +- .../Infrastructure/Diagnostics/Diagnostic.swift | 10 +++++----- .../Diagnostics/DiagnosticConsoleWriter.swift | 8 ++++---- .../Diagnostics/DiagnosticNote.swift | 4 ++-- .../Infrastructure/Diagnostics/Problem.swift | 12 ++++++------ .../ArgumentParsing/Subcommands/Convert.swift | 2 +- .../Diagnostics/DiagnosticEngineTests.swift | 10 +++++----- .../Diagnostics/DiagnosticTests.swift | 14 +++++++------- .../SwiftDocCTests/Diagnostics/ProblemTests.swift | 6 +++--- .../Infrastructure/PathHierarchyTests.swift | 2 +- .../Model/RenderNodeSerializationTests.swift | 6 +++--- .../Model/SemaToRenderNodeTests.swift | 6 +++--- Tests/SwiftDocCTests/Semantics/ArticleTests.swift | 10 +++++----- .../HasAtMostOneTests.swift | 2 +- .../HasExactlyOneTests.swift | 4 ++-- .../HasOnlyKnownArgumentsTests.swift | 2 +- .../HasOnlyKnownDirectivesTests.swift | 2 +- Tests/SwiftDocCTests/Semantics/MetadataTests.swift | 4 ++-- .../SwiftDocCTests/Semantics/RedirectedTests.swift | 8 ++++---- Tests/SwiftDocCTests/Semantics/SymbolTests.swift | 2 +- .../ConvertActionTests.swift | 2 +- .../PreviewActionIntegrationTests.swift | 4 ++-- 22 files changed, 61 insertions(+), 61 deletions(-) diff --git a/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift b/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift index f5864c5a91..7fb4cbceee 100644 --- a/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift +++ b/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift @@ -192,7 +192,7 @@ public struct ConvertService: DocumentationService { guard conversionProblems.isEmpty else { throw ConvertServiceError.conversionError( - underlyingError: DiagnosticConsoleWriter.formattedDescriptionFor(conversionProblems)) + underlyingError: DiagnosticConsoleWriter.formattedDescription(conversionProblems)) } let references: RenderReferenceStore? diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift index 6cdab5c75d..e5ae9452c6 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift @@ -89,15 +89,15 @@ public extension Diagnostic { // MARK: Deprecated -@available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") +@available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") extension Diagnostic: DescribedError { - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") var localizedDescription: String { - return DiagnosticConsoleWriter.formattedDescriptionFor(self) + return DiagnosticConsoleWriter.formattedDescription(self) } - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") public var errorDescription: String { - return DiagnosticConsoleWriter.formattedDescriptionFor(self) + return DiagnosticConsoleWriter.formattedDescription(self) } } diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift index 78b8b610e5..a8a584c8d5 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift @@ -58,16 +58,16 @@ public final class DiagnosticConsoleWriter: DiagnosticFormattingConsumer { extension DiagnosticConsoleWriter { - public static func formattedDescriptionFor(_ problems: Problems, options: DiagnosticFormattingOptions = []) -> String where Problems: Sequence, Problems.Element == Problem { - return problems.map { formattedDescriptionFor($0, options: options) }.joined(separator: "\n") + public static func formattedDescription(_ problems: Problems, options: DiagnosticFormattingOptions = []) -> String where Problems: Sequence, Problems.Element == Problem { + return problems.map { formattedDescription($0, options: options) }.joined(separator: "\n") } - public static func formattedDescriptionFor(_ problem: Problem, options: DiagnosticFormattingOptions = []) -> String { + public static func formattedDescription(_ problem: Problem, options: DiagnosticFormattingOptions = []) -> String { let diagnosticFormatter = makeDiagnosticFormatter(options) return diagnosticFormatter.formattedDescription(problem) } - public static func formattedDescriptionFor(_ diagnostic: Diagnostic, options: DiagnosticFormattingOptions = []) -> String { + public static func formattedDescription(_ diagnostic: Diagnostic, options: DiagnosticFormattingOptions = []) -> String { let diagnosticFormatter = makeDiagnosticFormatter(options) return diagnosticFormatter.formattedDescription(diagnostic) } diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift index 503f59e52a..54b9afdb1b 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift @@ -25,9 +25,9 @@ public struct DiagnosticNote { public var message: String } -@available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") +@available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") extension DiagnosticNote: CustomStringConvertible { - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") public var description: String { let location = "\(source.path):\(range.lowerBound.line):\(range.lowerBound.column)" return "\(location): note: \(message)" diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift index 4832d4d190..6c36ec2f44 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift @@ -56,24 +56,24 @@ extension Sequence where Element == Problem { // MARK: Deprecated extension Problem { - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") var localizedDescription: String { - return DiagnosticConsoleWriter.formattedDescriptionFor(self) + return DiagnosticConsoleWriter.formattedDescription(self) } - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") func formattedLocalizedDescription(withOptions options: DiagnosticFormattingOptions = []) -> String { - return DiagnosticConsoleWriter.formattedDescriptionFor(self, options: options) + return DiagnosticConsoleWriter.formattedDescription(self, options: options) } } extension Sequence where Element == Problem { - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") public var localizedDescription: String { return map { $0.localizedDescription }.joined(separator: "\n") } - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescriptionFor(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") public func formattedLocalizedDescription(withOptions options: DiagnosticFormattingOptions) -> String { return map { $0.formattedLocalizedDescription(withOptions: options) }.joined(separator: "\n") } diff --git a/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift b/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift index 9d0001b99b..fb564dcdf8 100644 --- a/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift +++ b/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift @@ -347,7 +347,7 @@ extension Docc { ) print( - DiagnosticConsoleWriter.formattedDescriptionFor(invalidOrMissingTemplateDiagnostic), + DiagnosticConsoleWriter.formattedDescription(invalidOrMissingTemplateDiagnostic), to: &Self._errorLogHandle ) diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift index 41ce4a8262..99eac74bbe 100644 --- a/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift @@ -114,7 +114,7 @@ class DiagnosticEngineTests: XCTestCase { defaultEngine.emit(warning) defaultEngine.emit(information) defaultEngine.emit(hint) - XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(defaultEngine.problems), """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(defaultEngine.problems), """ error: Test error warning: Test warning """) @@ -124,7 +124,7 @@ class DiagnosticEngineTests: XCTestCase { engine.emit(warning) engine.emit(information) engine.emit(hint) - XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(engine.problems), """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(engine.problems), """ error: Test error warning: Test warning note: Test information @@ -140,7 +140,7 @@ class DiagnosticEngineTests: XCTestCase { defaultEngine.emit(error) defaultEngine.emit(warning) defaultEngine.emit(information) - XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(defaultEngine.problems), """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(defaultEngine.problems), """ error: Test error warning: Test warning """) @@ -149,7 +149,7 @@ class DiagnosticEngineTests: XCTestCase { engine.emit(error) engine.emit(warning) engine.emit(information) - XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(engine.problems), """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(engine.problems), """ error: Test error error: Test warning note: Test information @@ -159,7 +159,7 @@ class DiagnosticEngineTests: XCTestCase { errorFilterLevelEngine.emit(error) errorFilterLevelEngine.emit(warning) errorFilterLevelEngine.emit(information) - XCTAssertEqual(DiagnosticConsoleWriter.formattedDescriptionFor(errorFilterLevelEngine.problems), """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(errorFilterLevelEngine.problems), """ error: Test error error: Test warning """) diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift index 14b3ca197b..062733fe18 100644 --- a/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift @@ -66,7 +66,7 @@ class DiagnosticTests: XCTestCase { let range = SourceLocation(line: 1, column: 1, source: URL(fileURLWithPath: path))...Missing", problem.diagnostic.identifier) XCTAssertEqual( - DiagnosticConsoleWriter.formattedDescriptionFor(problem.diagnostic), + DiagnosticConsoleWriter.formattedDescription(problem.diagnostic), """ error: Missing 'Child' child directive The 'Parent' directive must have exactly one 'Child' child directive @@ -87,7 +87,7 @@ class HasExactlyOneTests: XCTestCase { XCTAssertEqual(""" error: Duplicate 'Child' child directive The 'Parent' directive must have exactly one 'Child' child directive - """, DiagnosticConsoleWriter.formattedDescriptionFor(problems[0].diagnostic)) + """, DiagnosticConsoleWriter.formattedDescription(problems[0].diagnostic)) } } diff --git a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift index 45e6865142..eaf5282ccd 100644 --- a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift +++ b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift @@ -68,6 +68,6 @@ class HasOnlyKnownArgumentsTests: XCTestCase { XCTAssertEqual(problems.count, 1) guard let first = problems.first else { return } - XCTAssertEqual("error: Unknown argument 'baz' in Intro. These arguments are currently unused but allowed: 'bark', 'woof'.", DiagnosticConsoleWriter.formattedDescriptionFor(first.diagnostic)) + XCTAssertEqual("error: Unknown argument 'baz' in Intro. These arguments are currently unused but allowed: 'bark', 'woof'.", DiagnosticConsoleWriter.formattedDescription(first.diagnostic)) } } diff --git a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift index 9fb5f72bda..c373de0be1 100644 --- a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift +++ b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift @@ -121,7 +121,7 @@ class HasOnlyKnownDirectivesTests: XCTestCase { XCTAssertEqual(problems.count, 1) guard let first = problems.first else { return } - XCTAssertEqual("error: 'baz' directive is unsupported as a child of the 'dir' directive\nThese directives are allowed: 'Comment', 'bar', 'bark', 'foo', 'woof'", DiagnosticConsoleWriter.formattedDescriptionFor(first.diagnostic)) + XCTAssertEqual("error: 'baz' directive is unsupported as a child of the 'dir' directive\nThese directives are allowed: 'Comment', 'bar', 'bark', 'foo', 'woof'", DiagnosticConsoleWriter.formattedDescription(first.diagnostic)) } } diff --git a/Tests/SwiftDocCTests/Semantics/MetadataTests.swift b/Tests/SwiftDocCTests/Semantics/MetadataTests.swift index d0e6bb20a6..a250967644 100644 --- a/Tests/SwiftDocCTests/Semantics/MetadataTests.swift +++ b/Tests/SwiftDocCTests/Semantics/MetadataTests.swift @@ -169,7 +169,7 @@ class MetadataTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(DiagnosticConsoleWriter.formattedDescriptionFor(analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(DiagnosticConsoleWriter.formattedDescription(analyzer.problems))") } func testSymbolArticleSupportsMetadataDisplayName() throws { @@ -193,7 +193,7 @@ class MetadataTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(DiagnosticConsoleWriter.formattedDescriptionFor(analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(DiagnosticConsoleWriter.formattedDescription(analyzer.problems))") } func testArticleDoesNotSupportsMetadataDisplayName() throws { diff --git a/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift b/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift index 95a6299ad9..67e2420b49 100644 --- a/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift +++ b/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift @@ -138,7 +138,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescriptionFor( analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription( analyzer.problems))") } func testVolumeAndChapterSupportsRedirect() throws { @@ -235,7 +235,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescriptionFor( analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription( analyzer.problems))") } func testTutorialArticleSupportsRedirect() throws { @@ -263,7 +263,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescriptionFor( analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription( analyzer.problems))") } func testResourcesSupportsRedirect() throws { @@ -333,7 +333,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescriptionFor( analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription( analyzer.problems))") } func testIncorrectArgumentLabel() throws { diff --git a/Tests/SwiftDocCTests/Semantics/SymbolTests.swift b/Tests/SwiftDocCTests/Semantics/SymbolTests.swift index 98c5a1f700..69649c5cdc 100644 --- a/Tests/SwiftDocCTests/Semantics/SymbolTests.swift +++ b/Tests/SwiftDocCTests/Semantics/SymbolTests.swift @@ -1182,7 +1182,7 @@ class SymbolTests: XCTestCase { var problems = [Problem]() let article = Article(from: document, source: nil, for: bundle, in: context, problems: &problems) XCTAssertNotNil(article, "The sidecar Article couldn't be created.", file: (file), line: line) - XCTAssert(problems.isEmpty, "Unexpectedly found problems: \(DiagnosticConsoleWriter.formattedDescriptionFor(problems))", file: (file), line: line) + XCTAssert(problems.isEmpty, "Unexpectedly found problems: \(DiagnosticConsoleWriter.formattedDescription(problems))", file: (file), line: line) return article } diff --git a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift index 574bf5555d..0e2b2df74f 100644 --- a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift @@ -2948,7 +2948,7 @@ class ConvertActionTests: XCTestCase { return lhs.diagnostic.summary < rhs.diagnostic.summary } return lhs.diagnostic.identifier < rhs.diagnostic.identifier - }) .map { DiagnosticConsoleWriter.formattedDescriptionFor($0.diagnostic) }.sorted().joined(separator: "\n") + }) .map { DiagnosticConsoleWriter.formattedDescription($0.diagnostic) }.sorted().joined(separator: "\n") } #endif diff --git a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift index 50a3aabfe4..9fda7745e5 100644 --- a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift @@ -334,7 +334,7 @@ class PreviewActionIntegrationTests: XCTestCase { XCTAssertTrue(result.didEncounterError, "Did not find an error when running preview", file: file, line: line) XCTAssertNotNil(engine.problems.first(where: { problem -> Bool in - DiagnosticConsoleWriter.formattedDescriptionFor(problem.diagnostic).contains(expectedErrorMessage) + DiagnosticConsoleWriter.formattedDescription(problem.diagnostic).contains(expectedErrorMessage) }), "Didn't find expected error message '\(expectedErrorMessage)'", file: file, line: line) // Verify that the failed server is not added to the server list @@ -472,7 +472,7 @@ class PreviewActionIntegrationTests: XCTestCase { } if !result.problems.isEmpty { - print(DiagnosticConsoleWriter.formattedDescriptionFor(result.problems), to: &logHandle) + print(DiagnosticConsoleWriter.formattedDescription(result.problems), to: &logHandle) } } catch { XCTFail(error.localizedDescription) From 2978be8bd38d23cde8134ef26a629b340622f035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Wed, 1 Mar 2023 12:24:25 -0800 Subject: [PATCH 10/16] Add tests for DiagnosticFileWriter --- .../Diagnostics/DiagnosticFile.swift | 36 ++-- .../DiagnosticFileWriterTests.swift | 189 ++++++++++++++++++ 2 files changed, 207 insertions(+), 18 deletions(-) create mode 100644 Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift index f67487972f..0c96667977 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift @@ -15,11 +15,27 @@ struct DiagnosticFile: Codable { var version: VersionTriplet var diagnostics: [Diagnostic] - init(version: VersionTriplet = .current, problems: [Problem]) { + init(version: VersionTriplet = Self.currentVersion, problems: [Problem]) { self.version = version self.diagnostics = problems.map { .init($0) } } + // This file format follows semantic versioning. + // Breaking changes should increment the major version component. + // Non breaking additions should increment the minor version. + // Bug fixes should increment the patch version. + static var currentVersion = VersionTriplet(1, 0, 0) + + enum Error: Swift.Error { + case unknownMajorVersion(found: VersionTriplet, latestKnown: VersionTriplet) + } + + static func verifyIsSupported(_ version: VersionTriplet, current: VersionTriplet = Self.currentVersion) throws { + guard version.major == current.major else { + throw Error.unknownMajorVersion(found: version, latestKnown: current) + } + } + struct Diagnostic: Codable { struct Range: Codable { var start: Location @@ -58,29 +74,13 @@ struct DiagnosticFile: Codable { init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) version = try container.decode(VersionTriplet.self, forKey: .version) - try version.verifyIsSupported() + try Self.verifyIsSupported(version) diagnostics = try container.decode([Diagnostic].self, forKey: .diagnostics) } } extension VersionTriplet: Codable { - // This file format follows semantic versioning. - // Breaking changes should increment the major version component. - // Non breaking additions should increment the minor version. - // Bug fixes should increment the patch version. - static var current = VersionTriplet(1, 0, 0) - - enum Error: Swift.Error { - case unknownMajorVersion(found: VersionTriplet, latestKnown: VersionTriplet) - } - - func verifyIsSupported() throws { - guard major <= Self.current.major else { - throw Error.unknownMajorVersion(found: self, latestKnown: Self.current) - } - } - enum CodingKeys: String, CodingKey { case major, minor, patch } diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift new file mode 100644 index 0000000000..6c39f8afa0 --- /dev/null +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift @@ -0,0 +1,189 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2023 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 XCTest +import Markdown +@testable import SwiftDocC + +class DiagnosticFileWriterTests: XCTestCase { + + func testWritesDiagnosticsWhenFinalized() throws { + let diagnosticFileURL = try createTemporaryDirectory().appendingPathComponent("test-diagnostics.json") + let writer = DiagnosticFileWriter(outputPath: diagnosticFileURL) + + let source = URL(string: "/path/to/file.md")! + let range = SourceLocation(line: 1, column: 8, source: source).. Date: Thu, 2 Mar 2023 11:07:42 -0800 Subject: [PATCH 11/16] Use SemanticVersion type for DiagnosticFile version --- .../Diagnostics/DiagnosticFile.swift | 32 ++++--------------- .../DiagnosticFileWriterTests.swift | 8 ++--- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift index 0c96667977..c5971c8dd5 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift @@ -12,10 +12,10 @@ import Foundation import struct Markdown.SourceLocation struct DiagnosticFile: Codable { - var version: VersionTriplet + var version: SemanticVersion var diagnostics: [Diagnostic] - init(version: VersionTriplet = Self.currentVersion, problems: [Problem]) { + init(version: SemanticVersion = Self.currentVersion, problems: [Problem]) { self.version = version self.diagnostics = problems.map { .init($0) } } @@ -24,13 +24,13 @@ struct DiagnosticFile: Codable { // Breaking changes should increment the major version component. // Non breaking additions should increment the minor version. // Bug fixes should increment the patch version. - static var currentVersion = VersionTriplet(1, 0, 0) + static var currentVersion = SemanticVersion(major: 1, minor: 0, patch: 0, prerelease: nil, buildMetadata: nil) enum Error: Swift.Error { - case unknownMajorVersion(found: VersionTriplet, latestKnown: VersionTriplet) + case unknownMajorVersion(found: SemanticVersion, latestKnown: SemanticVersion) } - static func verifyIsSupported(_ version: VersionTriplet, current: VersionTriplet = Self.currentVersion) throws { + static func verifyIsSupported(_ version: SemanticVersion, current: SemanticVersion = Self.currentVersion) throws { guard version.major == current.major else { throw Error.unknownMajorVersion(found: version, latestKnown: current) } @@ -73,33 +73,13 @@ struct DiagnosticFile: Codable { init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - version = try container.decode(VersionTriplet.self, forKey: .version) + version = try container.decode(SemanticVersion.self, forKey: .version) try Self.verifyIsSupported(version) diagnostics = try container.decode([Diagnostic].self, forKey: .diagnostics) } } -extension VersionTriplet: Codable { - enum CodingKeys: String, CodingKey { - case major, minor, patch - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(major, forKey: .major) - try container.encode(minor, forKey: .minor) - try container.encode(patch, forKey: .patch) - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - major = try container.decode(Int.self, forKey: .major) - minor = try container.decode(Int.self, forKey: .minor) - patch = try container.decode(Int.self, forKey: .patch) - } -} - // MARK: Initialization extension DiagnosticFile.Diagnostic { diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift index 6c39f8afa0..9fca564c0f 100644 --- a/Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift @@ -161,10 +161,10 @@ class DiagnosticFileWriterTests: XCTestCase { } func testVerifyVersionIsValidForDecoding() throws { - let version1_0_0 = VersionTriplet(1, 0, 0) - let version1_0_1 = VersionTriplet(1, 0, 1) - let version1_2_3 = VersionTriplet(1, 2, 3) - let version2_0_0 = VersionTriplet(2, 0, 0) + let version1_0_0 = SemanticVersion(major: 1, minor: 0, patch: 0) + let version1_0_1 = SemanticVersion(major: 1, minor: 0, patch: 1) + let version1_2_3 = SemanticVersion(major: 1, minor: 2, patch: 3) + let version2_0_0 = SemanticVersion(major: 2, minor: 0, patch: 0) XCTAssertNoThrow(try DiagnosticFile.verifyIsSupported(version1_0_0, current: version1_0_0)) XCTAssertNoThrow(try DiagnosticFile.verifyIsSupported(version1_0_0, current: version1_0_1)) From 8258eff6916b265e1bf6fd3f35c5f19f8b72e7f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Thu, 2 Mar 2023 11:09:10 -0800 Subject: [PATCH 12/16] Use dedicated diagnostic file severity type --- .../Diagnostics/DiagnosticFile.swift | 20 +++++++++++++++++-- .../DiagnosticFileWriterTests.swift | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift index c5971c8dd5..407861f62a 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFile.swift @@ -47,7 +47,7 @@ struct DiagnosticFile: Codable { } var source: URL? var range: Range? - var severity: DiagnosticSeverity + var severity: Severity var summary: String var explanation: String? var solutions: [Solution] @@ -65,6 +65,9 @@ struct DiagnosticFile: Codable { var range: Range? var message: String } + enum Severity: String, Codable { + case error, warning, note, remark + } } enum CodingKeys: String, CodingKey { @@ -86,7 +89,7 @@ extension DiagnosticFile.Diagnostic { init(_ problem: Problem) { self.source = problem.diagnostic.source self.range = problem.diagnostic.range.map { .init($0) } - self.severity = problem.diagnostic.severity + self.severity = .init(problem.diagnostic.severity) self.summary = problem.diagnostic.summary self.explanation = problem.diagnostic.explanation self.solutions = problem.possibleSolutions.map { .init($0) } @@ -129,3 +132,16 @@ extension DiagnosticFile.Diagnostic.Note { self.message = note.message } } + +extension DiagnosticFile.Diagnostic.Severity { + init(_ severity: DiagnosticSeverity) { + switch severity { + case .error: + self = .error + case .warning: + self = .warning + case .information, .hint: + self = .note + } + } +} diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift index 9fca564c0f..5216ae2283 100644 --- a/Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticFileWriterTests.swift @@ -103,7 +103,7 @@ class DiagnosticFileWriterTests: XCTestCase { XCTAssertEqual(diagnostic.range?.start.column, 8) XCTAssertEqual(diagnostic.range?.end.line, 10) XCTAssertEqual(diagnostic.range?.end.column, 21) - XCTAssertEqual(diagnostic.severity, .information) + XCTAssertEqual(diagnostic.severity, .note) XCTAssertEqual(diagnostic.summary, summary) XCTAssertEqual(diagnostic.explanation, explanation) XCTAssertEqual(diagnostic.solutions.count, 2, "Found unexpected solutions: \(diagnostic.solutions)") From 326a931486abc6fc2e6cb3e4815583d84f981d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Thu, 2 Mar 2023 11:15:29 -0800 Subject: [PATCH 13/16] Rename 'formattedDescription(_:)' to 'formattedDescription(for:)' --- .../Convert/ConvertService.swift | 2 +- .../Diagnostics/Diagnostic.swift | 10 ++--- .../Diagnostics/DiagnosticConsoleWriter.swift | 42 +++++++++---------- .../Diagnostics/DiagnosticNote.swift | 4 +- .../Infrastructure/Diagnostics/Problem.swift | 12 +++--- .../ArgumentParsing/Subcommands/Convert.swift | 2 +- .../Diagnostics/DiagnosticEngineTests.swift | 10 ++--- .../Diagnostics/DiagnosticTests.swift | 14 +++---- .../Diagnostics/ProblemTests.swift | 6 +-- .../Infrastructure/PathHierarchyTests.swift | 2 +- .../Model/RenderNodeSerializationTests.swift | 6 +-- .../Model/SemaToRenderNodeTests.swift | 6 +-- .../Semantics/ArticleTests.swift | 10 ++--- .../HasAtMostOneTests.swift | 2 +- .../HasExactlyOneTests.swift | 4 +- .../HasOnlyKnownArgumentsTests.swift | 2 +- .../HasOnlyKnownDirectivesTests.swift | 2 +- .../Semantics/MetadataTests.swift | 4 +- .../Semantics/RedirectedTests.swift | 8 ++-- .../Semantics/SymbolTests.swift | 2 +- .../ConvertActionTests.swift | 2 +- .../PreviewActionIntegrationTests.swift | 4 +- 22 files changed, 78 insertions(+), 78 deletions(-) diff --git a/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift b/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift index 7fb4cbceee..6af2b63403 100644 --- a/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift +++ b/Sources/SwiftDocC/DocumentationService/Convert/ConvertService.swift @@ -192,7 +192,7 @@ public struct ConvertService: DocumentationService { guard conversionProblems.isEmpty else { throw ConvertServiceError.conversionError( - underlyingError: DiagnosticConsoleWriter.formattedDescription(conversionProblems)) + underlyingError: DiagnosticConsoleWriter.formattedDescription(for: conversionProblems)) } let references: RenderReferenceStore? diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift index e5ae9452c6..a695e87555 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/Diagnostic.swift @@ -89,15 +89,15 @@ public extension Diagnostic { // MARK: Deprecated -@available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") +@available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(for:options:)' instead.") extension Diagnostic: DescribedError { - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(for:options:)' instead.") var localizedDescription: String { - return DiagnosticConsoleWriter.formattedDescription(self) + return DiagnosticConsoleWriter.formattedDescription(for: self) } - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(for:options:)' instead.") public var errorDescription: String { - return DiagnosticConsoleWriter.formattedDescription(self) + return DiagnosticConsoleWriter.formattedDescription(for: self) } } diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift index a8a584c8d5..48d2cab77d 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticConsoleWriter.swift @@ -37,7 +37,7 @@ public final class DiagnosticConsoleWriter: DiagnosticFormattingConsumer { public func receive(_ problems: [Problem]) { // Add a newline after each formatter description, including the last one. - let text = problems.map { diagnosticFormatter.formattedDescription($0).appending("\n") }.joined() + let text = problems.map { diagnosticFormatter.formattedDescription(for: $0).appending("\n") }.joined() outputStream.write(text) } @@ -58,32 +58,32 @@ public final class DiagnosticConsoleWriter: DiagnosticFormattingConsumer { extension DiagnosticConsoleWriter { - public static func formattedDescription(_ problems: Problems, options: DiagnosticFormattingOptions = []) -> String where Problems: Sequence, Problems.Element == Problem { - return problems.map { formattedDescription($0, options: options) }.joined(separator: "\n") + public static func formattedDescription(for problems: Problems, options: DiagnosticFormattingOptions = []) -> String where Problems: Sequence, Problems.Element == Problem { + return problems.map { formattedDescription(for: $0, options: options) }.joined(separator: "\n") } - public static func formattedDescription(_ problem: Problem, options: DiagnosticFormattingOptions = []) -> String { + public static func formattedDescription(for problem: Problem, options: DiagnosticFormattingOptions = []) -> String { let diagnosticFormatter = makeDiagnosticFormatter(options) - return diagnosticFormatter.formattedDescription(problem) + return diagnosticFormatter.formattedDescription(for: problem) } - public static func formattedDescription(_ diagnostic: Diagnostic, options: DiagnosticFormattingOptions = []) -> String { + public static func formattedDescription(for diagnostic: Diagnostic, options: DiagnosticFormattingOptions = []) -> String { let diagnosticFormatter = makeDiagnosticFormatter(options) - return diagnosticFormatter.formattedDescription(diagnostic) + return diagnosticFormatter.formattedDescription(for: diagnostic) } } protocol DiagnosticConsoleFormatter { var options: DiagnosticFormattingOptions { get set } - func formattedDescription(_ problems: Problems) -> String where Problems: Sequence, Problems.Element == Problem - func formattedDescription(_ problem: Problem) -> String - func formattedDescription(_ diagnostic: Diagnostic) -> String + func formattedDescription(for problems: Problems) -> String where Problems: Sequence, Problems.Element == Problem + func formattedDescription(for problem: Problem) -> String + func formattedDescription(for diagnostic: Diagnostic) -> String } extension DiagnosticConsoleFormatter { - func formattedDescription(_ problems: Problems) -> String where Problems: Sequence, Problems.Element == Problem { - return problems.map { formattedDescription($0) }.joined(separator: "\n") + func formattedDescription(for problems: Problems) -> String where Problems: Sequence, Problems.Element == Problem { + return problems.map { formattedDescription(for: $0) }.joined(separator: "\n") } } @@ -92,9 +92,9 @@ extension DiagnosticConsoleFormatter { struct IDEDiagnosticConsoleFormatter: DiagnosticConsoleFormatter { var options: DiagnosticFormattingOptions - func formattedDescription(_ problem: Problem) -> String { + func formattedDescription(for problem: Problem) -> String { guard let source = problem.diagnostic.source else { - return formattedDescription(problem.diagnostic) + return formattedDescription(for: problem.diagnostic) } var description = formattedDiagnosticSummary(problem.diagnostic) @@ -126,7 +126,7 @@ struct IDEDiagnosticConsoleFormatter: DiagnosticConsoleFormatter { return description } - public func formattedDescription(_ diagnostic: Diagnostic) -> String { + public func formattedDescription(for diagnostic: Diagnostic) -> String { return formattedDiagnosticSummary(diagnostic) + formattedDiagnosticDetails(diagnostic) } @@ -153,13 +153,13 @@ struct IDEDiagnosticConsoleFormatter: DiagnosticConsoleFormatter { if !diagnostic.notes.isEmpty { result += "\n" - result += diagnostic.notes.map { formattedDescription($0) }.joined(separator: "\n") + result += diagnostic.notes.map { formattedDescription(for: $0) }.joined(separator: "\n") } return result } - private func formattedDescription(_ note: DiagnosticNote) -> String { + private func formattedDescription(for note: DiagnosticNote) -> String { let location = "\(note.source.path):\(note.range.lowerBound.line):\(note.range.lowerBound.column)" return "\(location): note: \(note.message)" } @@ -169,11 +169,11 @@ struct IDEDiagnosticConsoleFormatter: DiagnosticConsoleFormatter { struct DefaultDiagnosticConsoleFormatter: DiagnosticConsoleFormatter { var options: DiagnosticFormattingOptions - func formattedDescription(_ problem: Problem) -> String { - formattedDescription(problem.diagnostic) + func formattedDescription(for problem: Problem) -> String { + formattedDescription(for: problem.diagnostic) } - func formattedDescription(_ diagnostic: Diagnostic) -> String { - return IDEDiagnosticConsoleFormatter(options: options).formattedDescription(diagnostic) + func formattedDescription(for diagnostic: Diagnostic) -> String { + return IDEDiagnosticConsoleFormatter(options: options).formattedDescription(for: diagnostic) } } diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift index 54b9afdb1b..c98b62d757 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticNote.swift @@ -25,9 +25,9 @@ public struct DiagnosticNote { public var message: String } -@available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") +@available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(for:options:)' instead.") extension DiagnosticNote: CustomStringConvertible { - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(for:options:)' instead.") public var description: String { let location = "\(source.path):\(range.lowerBound.line):\(range.lowerBound.column)" return "\(location): note: \(message)" diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift index 6c36ec2f44..6b011ad27f 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/Problem.swift @@ -56,24 +56,24 @@ extension Sequence where Element == Problem { // MARK: Deprecated extension Problem { - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(for:options:)' instead.") var localizedDescription: String { - return DiagnosticConsoleWriter.formattedDescription(self) + return DiagnosticConsoleWriter.formattedDescription(for: self) } - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(for:options:)' instead.") func formattedLocalizedDescription(withOptions options: DiagnosticFormattingOptions = []) -> String { - return DiagnosticConsoleWriter.formattedDescription(self, options: options) + return DiagnosticConsoleWriter.formattedDescription(for: self, options: options) } } extension Sequence where Element == Problem { - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(for:options:)' instead.") public var localizedDescription: String { return map { $0.localizedDescription }.joined(separator: "\n") } - @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(_:options:)' instead.") + @available(*, deprecated, message: "Use 'DiagnosticConsoleWriter.formattedDescription(for:options:)' instead.") public func formattedLocalizedDescription(withOptions options: DiagnosticFormattingOptions) -> String { return map { $0.formattedLocalizedDescription(withOptions: options) }.joined(separator: "\n") } diff --git a/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift b/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift index fb564dcdf8..98ea118b26 100644 --- a/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift +++ b/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift @@ -347,7 +347,7 @@ extension Docc { ) print( - DiagnosticConsoleWriter.formattedDescription(invalidOrMissingTemplateDiagnostic), + DiagnosticConsoleWriter.formattedDescription(for: invalidOrMissingTemplateDiagnostic), to: &Self._errorLogHandle ) diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift index 99eac74bbe..df23ce0054 100644 --- a/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticEngineTests.swift @@ -114,7 +114,7 @@ class DiagnosticEngineTests: XCTestCase { defaultEngine.emit(warning) defaultEngine.emit(information) defaultEngine.emit(hint) - XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(defaultEngine.problems), """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(for: defaultEngine.problems), """ error: Test error warning: Test warning """) @@ -124,7 +124,7 @@ class DiagnosticEngineTests: XCTestCase { engine.emit(warning) engine.emit(information) engine.emit(hint) - XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(engine.problems), """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(for: engine.problems), """ error: Test error warning: Test warning note: Test information @@ -140,7 +140,7 @@ class DiagnosticEngineTests: XCTestCase { defaultEngine.emit(error) defaultEngine.emit(warning) defaultEngine.emit(information) - XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(defaultEngine.problems), """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(for: defaultEngine.problems), """ error: Test error warning: Test warning """) @@ -149,7 +149,7 @@ class DiagnosticEngineTests: XCTestCase { engine.emit(error) engine.emit(warning) engine.emit(information) - XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(engine.problems), """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(for: engine.problems), """ error: Test error error: Test warning note: Test information @@ -159,7 +159,7 @@ class DiagnosticEngineTests: XCTestCase { errorFilterLevelEngine.emit(error) errorFilterLevelEngine.emit(warning) errorFilterLevelEngine.emit(information) - XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(errorFilterLevelEngine.problems), """ + XCTAssertEqual(DiagnosticConsoleWriter.formattedDescription(for: errorFilterLevelEngine.problems), """ error: Test error error: Test warning """) diff --git a/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift b/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift index 062733fe18..75d5cbef79 100644 --- a/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift +++ b/Tests/SwiftDocCTests/Diagnostics/DiagnosticTests.swift @@ -66,7 +66,7 @@ class DiagnosticTests: XCTestCase { let range = SourceLocation(line: 1, column: 1, source: URL(fileURLWithPath: path))...Missing", problem.diagnostic.identifier) XCTAssertEqual( - DiagnosticConsoleWriter.formattedDescription(problem.diagnostic), + DiagnosticConsoleWriter.formattedDescription(for: problem.diagnostic), """ error: Missing 'Child' child directive The 'Parent' directive must have exactly one 'Child' child directive @@ -87,7 +87,7 @@ class HasExactlyOneTests: XCTestCase { XCTAssertEqual(""" error: Duplicate 'Child' child directive The 'Parent' directive must have exactly one 'Child' child directive - """, DiagnosticConsoleWriter.formattedDescription(problems[0].diagnostic)) + """, DiagnosticConsoleWriter.formattedDescription(for: problems[0].diagnostic)) } } diff --git a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift index eaf5282ccd..922b1fc644 100644 --- a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift +++ b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownArgumentsTests.swift @@ -68,6 +68,6 @@ class HasOnlyKnownArgumentsTests: XCTestCase { XCTAssertEqual(problems.count, 1) guard let first = problems.first else { return } - XCTAssertEqual("error: Unknown argument 'baz' in Intro. These arguments are currently unused but allowed: 'bark', 'woof'.", DiagnosticConsoleWriter.formattedDescription(first.diagnostic)) + XCTAssertEqual("error: Unknown argument 'baz' in Intro. These arguments are currently unused but allowed: 'bark', 'woof'.", DiagnosticConsoleWriter.formattedDescription(for: first.diagnostic)) } } diff --git a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift index c373de0be1..a3350051b6 100644 --- a/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift +++ b/Tests/SwiftDocCTests/Semantics/General Purpose Analyses/HasOnlyKnownDirectivesTests.swift @@ -121,7 +121,7 @@ class HasOnlyKnownDirectivesTests: XCTestCase { XCTAssertEqual(problems.count, 1) guard let first = problems.first else { return } - XCTAssertEqual("error: 'baz' directive is unsupported as a child of the 'dir' directive\nThese directives are allowed: 'Comment', 'bar', 'bark', 'foo', 'woof'", DiagnosticConsoleWriter.formattedDescription(first.diagnostic)) + XCTAssertEqual("error: 'baz' directive is unsupported as a child of the 'dir' directive\nThese directives are allowed: 'Comment', 'bar', 'bark', 'foo', 'woof'", DiagnosticConsoleWriter.formattedDescription(for: first.diagnostic)) } } diff --git a/Tests/SwiftDocCTests/Semantics/MetadataTests.swift b/Tests/SwiftDocCTests/Semantics/MetadataTests.swift index a250967644..af038b49d2 100644 --- a/Tests/SwiftDocCTests/Semantics/MetadataTests.swift +++ b/Tests/SwiftDocCTests/Semantics/MetadataTests.swift @@ -169,7 +169,7 @@ class MetadataTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(DiagnosticConsoleWriter.formattedDescription(analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(DiagnosticConsoleWriter.formattedDescription(for: analyzer.problems))") } func testSymbolArticleSupportsMetadataDisplayName() throws { @@ -193,7 +193,7 @@ class MetadataTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(DiagnosticConsoleWriter.formattedDescription(analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got:\n \(DiagnosticConsoleWriter.formattedDescription(for: analyzer.problems))") } func testArticleDoesNotSupportsMetadataDisplayName() throws { diff --git a/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift b/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift index 67e2420b49..df646e7f4d 100644 --- a/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift +++ b/Tests/SwiftDocCTests/Semantics/RedirectedTests.swift @@ -138,7 +138,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription( analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription(for: analyzer.problems))") } func testVolumeAndChapterSupportsRedirect() throws { @@ -235,7 +235,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription( analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription(for: analyzer.problems))") } func testTutorialArticleSupportsRedirect() throws { @@ -263,7 +263,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription( analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription(for: analyzer.problems))") } func testResourcesSupportsRedirect() throws { @@ -333,7 +333,7 @@ class RedirectedTests: XCTestCase { var analyzer = SemanticAnalyzer(source: nil, context: context, bundle: bundle) _ = analyzer.visit(document) - XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription( analyzer.problems))") + XCTAssert(analyzer.problems.isEmpty, "Expected no problems. Got \(DiagnosticConsoleWriter.formattedDescription(for: analyzer.problems))") } func testIncorrectArgumentLabel() throws { diff --git a/Tests/SwiftDocCTests/Semantics/SymbolTests.swift b/Tests/SwiftDocCTests/Semantics/SymbolTests.swift index 69649c5cdc..e3a68a2f23 100644 --- a/Tests/SwiftDocCTests/Semantics/SymbolTests.swift +++ b/Tests/SwiftDocCTests/Semantics/SymbolTests.swift @@ -1182,7 +1182,7 @@ class SymbolTests: XCTestCase { var problems = [Problem]() let article = Article(from: document, source: nil, for: bundle, in: context, problems: &problems) XCTAssertNotNil(article, "The sidecar Article couldn't be created.", file: (file), line: line) - XCTAssert(problems.isEmpty, "Unexpectedly found problems: \(DiagnosticConsoleWriter.formattedDescription(problems))", file: (file), line: line) + XCTAssert(problems.isEmpty, "Unexpectedly found problems: \(DiagnosticConsoleWriter.formattedDescription(for: problems))", file: (file), line: line) return article } diff --git a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift index 0e2b2df74f..f796d8e63b 100644 --- a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift @@ -2948,7 +2948,7 @@ class ConvertActionTests: XCTestCase { return lhs.diagnostic.summary < rhs.diagnostic.summary } return lhs.diagnostic.identifier < rhs.diagnostic.identifier - }) .map { DiagnosticConsoleWriter.formattedDescription($0.diagnostic) }.sorted().joined(separator: "\n") + }) .map { DiagnosticConsoleWriter.formattedDescription(for: $0.diagnostic) }.sorted().joined(separator: "\n") } #endif diff --git a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift index 9fda7745e5..ed916ff2b0 100644 --- a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift @@ -334,7 +334,7 @@ class PreviewActionIntegrationTests: XCTestCase { XCTAssertTrue(result.didEncounterError, "Did not find an error when running preview", file: file, line: line) XCTAssertNotNil(engine.problems.first(where: { problem -> Bool in - DiagnosticConsoleWriter.formattedDescription(problem.diagnostic).contains(expectedErrorMessage) + DiagnosticConsoleWriter.formattedDescription(for: problem.diagnostic).contains(expectedErrorMessage) }), "Didn't find expected error message '\(expectedErrorMessage)'", file: file, line: line) // Verify that the failed server is not added to the server list @@ -472,7 +472,7 @@ class PreviewActionIntegrationTests: XCTestCase { } if !result.problems.isEmpty { - print(DiagnosticConsoleWriter.formattedDescription(result.problems), to: &logHandle) + print(DiagnosticConsoleWriter.formattedDescription(for: result.problems), to: &logHandle) } } catch { XCTFail(error.localizedDescription) From 0d08bf690f8fac3d462e0a739028ec34493bd6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Thu, 2 Mar 2023 11:23:28 -0800 Subject: [PATCH 14/16] Document DiagnosticFileWriter API --- .../Infrastructure/Diagnostics/DiagnosticFileWriter.swift | 8 ++++++++ Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Features.md | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFileWriter.swift b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFileWriter.swift index 8ea19ad3c4..521ff761d8 100644 --- a/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFileWriter.swift +++ b/Sources/SwiftDocC/Infrastructure/Diagnostics/DiagnosticFileWriter.swift @@ -10,8 +10,16 @@ import Foundation +/// A diagnostic consumer that writes detailed diagnostic information to a file. +/// +/// For tools interacting with DocC, the diagnostic file format includes more information about the diagnostics than what +/// is output to the consoles. public final class DiagnosticFileWriter: DiagnosticConsumer { + /// The path where the diagnostic file writer should write the diagnostics file. var outputPath: URL + + /// Creates a new diagnostic file writer with a specific output path. + /// - Parameter outputPath: The path where the diagnostic file writer should write the diagnostics file. public init(outputPath: URL) { self.outputPath = outputPath } diff --git a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Features.md b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Features.md index cfb0416e0c..dbd0c6a827 100644 --- a/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Features.md +++ b/Sources/SwiftDocC/SwiftDocC.docc/SwiftDocC/Features.md @@ -2,7 +2,7 @@ Add features to DocC and indicate the feature's availability to other tools. -Over time as we develop new features in DocC we also add, update, or remove the flags and options that the `docc` executable accepts. So that other tools can know what flags and options a certain version of the `docc` executable accepts, we add new entires in the "features.json" file. +Over time as we develop new features in DocC we also add, update, or remove the flags and options that the `docc` executable accepts. So that other tools can know what flags and options a certain version of the `docc` executable accepts, we add new entries in the "features.json" file. ## Adding a New Feature From 83151b144e0e9855c72bfbfc897f017bff6b7053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Thu, 2 Mar 2023 17:09:25 -0800 Subject: [PATCH 15/16] Correct install location of features.json file --- build-script-helper.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/build-script-helper.py b/build-script-helper.py index 26bee8c870..5a4e1db216 100755 --- a/build-script-helper.py +++ b/build-script-helper.py @@ -256,12 +256,9 @@ def install(args, env): features_path = os.path.join(args.package_path, 'features.json') # Install features.json relative to the docc executable at "../../share/docc/features.json" features_install_path = os.path.join( - os.path.dirname( - os.path.dirname(docc_install_dir) - ), + os.path.dirname(docc_install_dir), 'share', - 'docc', - 'features.json' + 'docc' ) create_intermediate_directories(os.path.dirname(features_install_path), verbose=verbose) check_and_sync( From 74ae8f9003e36297a66fc9d0e1bb0d7e8813a688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Thu, 2 Mar 2023 18:36:21 -0800 Subject: [PATCH 16/16] Correct install location of features.json file --- build-script-helper.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build-script-helper.py b/build-script-helper.py index 5a4e1db216..13b4134d72 100755 --- a/build-script-helper.py +++ b/build-script-helper.py @@ -258,7 +258,8 @@ def install(args, env): features_install_path = os.path.join( os.path.dirname(docc_install_dir), 'share', - 'docc' + 'docc', + 'features.json' ) create_intermediate_directories(os.path.dirname(features_install_path), verbose=verbose) check_and_sync(