mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
83 lines
3.4 KiB
Swift
83 lines
3.4 KiB
Swift
//
|
|
// File+SwiftLint.swift
|
|
// SwiftLint
|
|
//
|
|
// Created by JP Simard on 2015-05-16.
|
|
// Copyright (c) 2015 Realm. All rights reserved.
|
|
//
|
|
|
|
import SourceKittenFramework
|
|
import SwiftXPC
|
|
|
|
public typealias Line = (index: Int, content: String)
|
|
|
|
public typealias Region = (startLine: Int, endLine: Int, disabledRules: [String])
|
|
|
|
public enum CommandAction: String {
|
|
case Enable = "enable"
|
|
case Disable = "disable"
|
|
}
|
|
|
|
public typealias Command = (CommandAction, String, Int)
|
|
|
|
extension File {
|
|
public func regions() -> [Region] {
|
|
let nsStringContents = contents as NSString
|
|
let commands = matchPattern("swiftlint:(enable|disable)\\ .+",
|
|
withSyntaxKinds: [.Comment]).flatMap { range -> Command? in
|
|
let scanner = NSScanner(string: nsStringContents.substringWithRange(range))
|
|
scanner.scanString("swiftlint:", intoString: nil)
|
|
var actionString: NSString? = nil
|
|
scanner.scanUpToString(" ", intoString: &actionString)
|
|
let start = range.location
|
|
if let actionString = actionString as String?,
|
|
action = CommandAction(rawValue: actionString),
|
|
lineRange = nsStringContents.lineRangeWithByteRange(start: start, length: 0) {
|
|
let ruleLocation = scanner.scanLocation + 1
|
|
let ruleStart = scanner.string.startIndex.advancedBy(ruleLocation)
|
|
let rule = scanner.string.substringFromIndex(ruleStart)
|
|
return (action, rule, lineRange.start)
|
|
}
|
|
return nil
|
|
}
|
|
let totalNumberOfLines = contents.lines().count
|
|
var regions: [Region] = [(1, commands.first?.2 ?? totalNumberOfLines, [])]
|
|
var disabledRules = Set<String>()
|
|
let commandPairs = zip(commands, Array(commands.dropFirst().map({Optional($0)})) + [nil])
|
|
for (command, nextCommand) in commandPairs {
|
|
switch command.0 {
|
|
case .Disable: disabledRules.insert(command.1)
|
|
case .Enable: disabledRules.remove(command.1)
|
|
}
|
|
regions.append((command.2, nextCommand?.2 ?? totalNumberOfLines, Array(disabledRules)))
|
|
}
|
|
return regions
|
|
}
|
|
|
|
public func matchPattern(pattern: String,
|
|
withSyntaxKinds syntaxKinds: [SyntaxKind]) -> [NSRange] {
|
|
return matchPattern(pattern).filter { _, kindsInRange in
|
|
return kindsInRange.count == syntaxKinds.count &&
|
|
zip(kindsInRange, syntaxKinds).filter({ $0.0 != $0.1 }).count == 0
|
|
}.map { $0.0 }
|
|
}
|
|
|
|
public func matchPattern(pattern: String) -> [(NSRange, [SyntaxKind])] {
|
|
let regex = try! NSRegularExpression(pattern: pattern, options: [])
|
|
let range = NSRange(location: 0, length: contents.utf16.count)
|
|
let syntax = syntaxMap
|
|
let matches = regex.matchesInString(contents, options: [], range: range)
|
|
return matches.map { match in
|
|
let tokensInRange = syntax.tokens.filter {
|
|
NSLocationInRange($0.offset, match.range) ||
|
|
NSLocationInRange(match.range.location,
|
|
NSRange(location: $0.offset, length: $0.length))
|
|
}
|
|
let kindsInRange = tokensInRange.flatMap {
|
|
SyntaxKind(rawValue: $0.type)
|
|
}
|
|
return (match.range, kindsInRange)
|
|
}
|
|
}
|
|
}
|