Skip to content

Commit 6c565df

Browse files
author
Jesse Haigh
committed
WIP diagnostics
1 parent 2cf5ac1 commit 6c565df

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2025 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See https://swift.org/LICENSE.txt for license information
8+
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
public import Foundation
12+
public import Markdown
13+
14+
/**
15+
Code blocks can have a `nocopy` option after the \`\`\`, in the language line.
16+
`nocopy` can be immediately after the \`\`\` or after a specified language and a comma (`,`).
17+
*/
18+
public struct InvalidCodeBlockOption: Checker {
19+
public var problems = [Problem]()
20+
21+
// FIXME: populate this from the parse options
22+
/// Parsing options for code blocks
23+
private let knownOptions = ["nocopy"]
24+
25+
private var sourceFile: URL?
26+
27+
/// Creates a new checker that detects documents with multiple titles.
28+
///
29+
/// - Parameter sourceFile: The URL to the documentation file that the checker checks.
30+
public init(sourceFile: URL?) {
31+
self.sourceFile = sourceFile
32+
}
33+
34+
public mutating func visitCodeBlock(_ codeBlock: CodeBlock) {
35+
let info = codeBlock.language?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
36+
guard !info.isEmpty else { return }
37+
38+
let tokens = info
39+
.split(separator: ",")
40+
.map { $0.trimmingCharacters(in: .whitespaces) }
41+
.filter { !$0.isEmpty }
42+
43+
guard !tokens.isEmpty else { return }
44+
45+
for token in tokens {
46+
// if the token is an exact match, we don't need to do anything
47+
guard !knownOptions.contains(token) else { continue }
48+
49+
let matches = NearMiss.bestMatches(for: knownOptions, against: token)
50+
51+
if !matches.isEmpty {
52+
let diagnostic = Diagnostic(source: sourceFile, severity: .warning, range: codeBlock.range, identifier: "org.swift.docc.InvalidCodeBlockOption", summary: "Unknown option \(token) in code block. Did you mean \(matches)?", explanation: nil)
53+
// FIXME: figure out the position of 'token' and provide solutions
54+
problems.append(Problem(diagnostic: diagnostic, possibleSolutions: []))
55+
}
56+
}
57+
}
58+
}

Sources/SwiftDocC/Infrastructure/DocumentationContext.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ public class DocumentationContext {
438438
MissingAbstract(sourceFile: source).any(),
439439
NonOverviewHeadingChecker(sourceFile: source).any(),
440440
SeeAlsoInTopicsHeadingChecker(sourceFile: source).any(),
441+
InvalidCodeBlockOption(sourceFile: source).any(),
441442
])
442443
checker.visit(document)
443444
diagnosticEngine.emit(checker.problems)

0 commit comments

Comments
 (0)