Files
2025-10-08 08:12:05 +02:00

48 lines
1.8 KiB
Swift

import Foundation
import SwiftSyntax
// MARK: - CommandVisitor
/// Visits the source syntax tree to collect all SwiftLint-style comment commands.
final class CommandVisitor: SyntaxVisitor {
private(set) var commands: [Command] = []
let locationConverter: SourceLocationConverter
init(locationConverter: SourceLocationConverter) {
self.locationConverter = locationConverter
super.init(viewMode: .sourceAccurate)
}
override func visitPost(_ node: TokenSyntax) {
collectCommands(in: node.leadingTrivia, offset: node.position)
collectCommands(in: node.trailingTrivia, offset: node.endPositionBeforeTrailingTrivia)
}
private func collectCommands(in trivia: Trivia, offset: AbsolutePosition) {
var position = offset
for piece in trivia {
switch piece {
case .lineComment(let comment):
guard let lower = comment.range(of: "swiftlint:")?.lowerBound.samePosition(in: comment.utf8) else {
break
}
let offset = comment.utf8.distance(from: comment.utf8.startIndex, to: lower)
let location = locationConverter.location(for: position.advanced(by: offset))
let line = locationConverter.sourceLines[location.line - 1]
guard let character = line.characterPosition(of: location.column) else {
break
}
let command = Command(
commandString: String(comment[lower...]),
line: location.line,
range: character..<(character + piece.sourceLength.utf8Length - offset)
)
commands.append(command)
default:
break
}
position += piece.sourceLength
}
}
}