diff --git a/.gitignore b/.gitignore index 2b9c66988..777cb057b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,12 @@ # Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore +## Build generated build/ +DerivedData + +## Various settings *.pbxuser !default.pbxuser *.mode1v3 @@ -10,11 +16,32 @@ build/ *.perspectivev3 !default.perspectivev3 xcuserdata + +## Other *.xccheckout *.moved-aside -DerivedData +*.xcuserstate +*.xcscmblueprint + +## Obj-C/Swift specific *.hmap *.ipa -*.xcuserstate + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +#Pods/ + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build + +# SwiftLint SwiftLint.pkg diff --git a/.gitmodules b/.gitmodules index 32f887e87..5afa9b035 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,9 @@ [submodule "Carthage/Checkouts/SourceKitten"] path = Carthage/Checkouts/SourceKitten url = https://github.com/jpsim/SourceKitten.git +[submodule "Carthage/Checkouts/Result"] + path = Carthage/Checkouts/Result + url = https://github.com/antitypical/Result.git +[submodule "Carthage/Checkouts/YamlSwift"] + path = Carthage/Checkouts/YamlSwift + url = https://github.com/behrang/YamlSwift.git diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 000000000..4e8698361 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,2 @@ +included: + - Source diff --git a/.travis.yml b/.travis.yml index 065327299..4be693b54 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: beta-xcode6.3 +osx_image: xcode7 git: submodules: false branches: diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dabda01b..28a633632 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +## Master + +##### Breaking + +* SwiftLint now exclusively supports Swift 2.0. + [JP Simard](https://github.com/jpsim) + [#77](https://github.com/realm/SwiftLint/issues/77) + +##### Enhancements + +* Configure SwiftLint via a YAML file: + Supports `disabled_rules`, `included` and `excluded`. + Pass a configuration file path to `--config`, defaults to `.swiftlint.yml`. + [JP Simard](https://github.com/jpsim) + [#3](https://github.com/realm/SwiftLint/issues/3) + +##### Bug Fixes + +* None. + + ## 0.1.2: FabricSoftenerRule ##### Breaking diff --git a/Cartfile b/Cartfile index 66306c6c2..346878590 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1 @@ -github "jpsim/SourceKitten" ~> 0.4 +github "jpsim/SourceKitten" "master" diff --git a/Cartfile.private b/Cartfile.private index a99553424..e5831ffc3 100644 --- a/Cartfile.private +++ b/Cartfile.private @@ -1,2 +1,3 @@ -github "Carthage/Commandant" ~> 0.5 +github "Carthage/Commandant" "swift-2.0" github "jspahrsummers/xcconfigs" >= 0.8 +github "behrang/YamlSwift" "master" diff --git a/Cartfile.resolved b/Cartfile.resolved index 8ed4b5a5a..1efd11e1f 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,6 +1,7 @@ -github "LlamaKit/LlamaKit" "v0.6.0" -github "drmohundro/SWXMLHash" "1.0.0" -github "jpsim/SwiftXPC" "1.0.0" -github "jspahrsummers/xcconfigs" "0.8" -github "Carthage/Commandant" "0.5" -github "jpsim/SourceKitten" "0.4.5" +github "antitypical/Result" "0.6-beta.1" +github "drmohundro/SWXMLHash" "050154bfc56032f04fcca37464693a17f897200a" +github "jpsim/SwiftXPC" "d32e70f1b35cfa833be85fd40e70401f4190f5b0" +github "behrang/YamlSwift" "243ebbafb8ed60f57f9d5a7c2a4ff8099824644a" +github "jspahrsummers/xcconfigs" "0.8.1" +github "Carthage/Commandant" "40f503c33121431dc098adb7c44d9496e3a1de2f" +github "jpsim/SourceKitten" "ace729472170a4ec2996b8f921fc66784e5ef4fe" diff --git a/Carthage/Checkouts/Commandant b/Carthage/Checkouts/Commandant index 3866cadd4..40f503c33 160000 --- a/Carthage/Checkouts/Commandant +++ b/Carthage/Checkouts/Commandant @@ -1 +1 @@ -Subproject commit 3866cadd431b1c3ba8091383b80ec023beb1897f +Subproject commit 40f503c33121431dc098adb7c44d9496e3a1de2f diff --git a/Carthage/Checkouts/LlamaKit b/Carthage/Checkouts/LlamaKit deleted file mode 160000 index e28d7f6e8..000000000 --- a/Carthage/Checkouts/LlamaKit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e28d7f6e82fbd5dcd5388b36e2acf4eedb44b4e8 diff --git a/Carthage/Checkouts/Result b/Carthage/Checkouts/Result new file mode 160000 index 000000000..18a10d680 --- /dev/null +++ b/Carthage/Checkouts/Result @@ -0,0 +1 @@ +Subproject commit 18a10d680af395d93b47ff4a3d8b0af3b8cad094 diff --git a/Carthage/Checkouts/SWXMLHash b/Carthage/Checkouts/SWXMLHash index 3f64d009c..050154bfc 160000 --- a/Carthage/Checkouts/SWXMLHash +++ b/Carthage/Checkouts/SWXMLHash @@ -1 +1 @@ -Subproject commit 3f64d009ca1e2b737bf93d22bcaa837d3be1d90c +Subproject commit 050154bfc56032f04fcca37464693a17f897200a diff --git a/Carthage/Checkouts/SourceKitten b/Carthage/Checkouts/SourceKitten index a9b100ab0..ace729472 160000 --- a/Carthage/Checkouts/SourceKitten +++ b/Carthage/Checkouts/SourceKitten @@ -1 +1 @@ -Subproject commit a9b100ab0803d79ef42c775895a40726d3128f07 +Subproject commit ace729472170a4ec2996b8f921fc66784e5ef4fe diff --git a/Carthage/Checkouts/SwiftXPC b/Carthage/Checkouts/SwiftXPC index bfc256492..d32e70f1b 160000 --- a/Carthage/Checkouts/SwiftXPC +++ b/Carthage/Checkouts/SwiftXPC @@ -1 +1 @@ -Subproject commit bfc256492840ff6e8d05b851cb57af38d83469bf +Subproject commit d32e70f1b35cfa833be85fd40e70401f4190f5b0 diff --git a/Carthage/Checkouts/YamlSwift b/Carthage/Checkouts/YamlSwift new file mode 160000 index 000000000..ed060df01 --- /dev/null +++ b/Carthage/Checkouts/YamlSwift @@ -0,0 +1 @@ +Subproject commit ed060df018b5693a045f207088b95ce15f433065 diff --git a/Carthage/Checkouts/xcconfigs b/Carthage/Checkouts/xcconfigs index 813127f87..99624a6af 160000 --- a/Carthage/Checkouts/xcconfigs +++ b/Carthage/Checkouts/xcconfigs @@ -1 +1 @@ -Subproject commit 813127f87f66fa14a7da03d3fa8410c02d2075d6 +Subproject commit 99624a6af366c015b678a1135e4c558776a59be6 diff --git a/README.md b/README.md index 2f347bc4d..307f0e5b4 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,12 @@ Using [Homebrew](http://brew.sh/) brew install swiftlint ``` -You can also install SwiftLint by downloading `SwiftLint.pkg` from the [latest GitHub release](https://github.com/realm/SwiftLint/releases/latest) and running it. +You can also install SwiftLint by downloading `SwiftLint.pkg` from the +[latest GitHub release](https://github.com/realm/SwiftLint/releases/latest) and +running it. -You can also build from source by cloning this project and running `make install`. +You can also build from source by cloning this project and running +`make install` (Xcode 7 Beta 6 required). ## Usage @@ -36,7 +39,8 @@ as its contents. Like this: ### Atom To integrate SwiftLint with [Atom](https://atom.io/) install the -[`linter-swiftlint`](https://atom.io/packages/linter-swiftlint) package from APM. +[`linter-swiftlint`](https://atom.io/packages/linter-swiftlint) package from +APM. ### Command Line @@ -62,8 +66,23 @@ encouraged. The rules that *are* currently implemented are mostly there as a starting point and are subject to change. -See the [Source/SwiftLintFramework/Rules](Source/SwiftLintFramework/Rules) directory to see the currently -implemented rules. +See the [Source/SwiftLintFramework/Rules](Source/SwiftLintFramework/Rules) +directory to see the currently implemented rules. + +### Configuration + +Configure SwiftLint by adding a `.swiftlint.yml` file from the directory you'll +run SwiftLint from. The following parameters can be configured: + +```yaml +disabled_rules: # rule identifiers to exclude from running + - todo +included: # paths to include during linting. `--path` is ignored if present. takes precendence over `excluded`. + - Source +excluded: # paths to ignore during linting. overridden by `included`. + - Carthage + - Pods +``` ## License diff --git a/Source/SwiftLintFramework/Configuration.swift b/Source/SwiftLintFramework/Configuration.swift new file mode 100644 index 000000000..3804bd4d7 --- /dev/null +++ b/Source/SwiftLintFramework/Configuration.swift @@ -0,0 +1,103 @@ +// +// Configuration.swift +// SwiftLint +// +// Created by JP Simard on 2015-08-23. +// Copyright (c) 2015 Realm. All rights reserved. +// + +import Yaml + +extension Yaml { + var arrayOfStrings: [Swift.String]? { + return array?.flatMap { $0.string } + } +} + +public struct Configuration { + public let disabledRules: [String] // disabled_rules + public let included: [String] // included + public let excluded: [String] // excluded + + public var rules: [Rule] { + return allRules.filter { !disabledRules.contains($0.identifier) } + } + + public init?(disabledRules: [String] = [], included: [String] = [], excluded: [String] = []) { + self.disabledRules = disabledRules + self.included = included + self.excluded = excluded + + // Validate that all rule identifiers map to a defined rule + + let validRuleIdentifiers = allRules.map { $0.identifier } + + let ruleSet = Set(disabledRules) + let invalidRules = ruleSet.filter({ !validRuleIdentifiers.contains($0) }) + if invalidRules.count > 0 { + for invalidRule in invalidRules { + fputs("config error: '\(invalidRule)' is not a valid rule identifier\n", stderr) + let listOfValidRuleIdentifiers = validRuleIdentifiers.joinWithSeparator("\n") + fputs("Valid rule identifiers:\n\(listOfValidRuleIdentifiers)\n", stderr) + } + return nil + } + + // Validate that rule identifiers aren't listed multiple times + + if ruleSet.count != disabledRules.count { + let duplicateRules = disabledRules.reduce([String: Int]()) { (var accu, element) in + accu[element] = accu[element]?.successor() ?? 1 + return accu + }.filter { + $0.1 > 1 + } + for duplicateRule in duplicateRules { + fputs("config error: '\(duplicateRule.0)' is listed \(duplicateRule.1) times\n", + stderr) + } + return nil + } + } + + public init?(yaml: String) { + guard let yamlConfig = Yaml.load(yaml).value else { + return nil + } + self.init( + disabledRules: yamlConfig["disabled_rules"].arrayOfStrings ?? [], + included: yamlConfig["included"].arrayOfStrings ?? [], + excluded: yamlConfig["excluded"].arrayOfStrings ?? [] + ) + } + + public init(path: String = ".swiftlint.yml", optional: Bool = true) { + let fullPath = (path as NSString).absolutePathRepresentation() + let failIfRequired = { + if !optional { fatalError("Could not read configuration file at path '\(fullPath)'") } + } + if path.isEmpty { + failIfRequired() + self.init()! + } else { + if !NSFileManager.defaultManager().fileExistsAtPath(fullPath) { + failIfRequired() + self.init()! + return + } + do { + let yamlContents = try NSString(contentsOfFile: fullPath, + encoding: NSUTF8StringEncoding) as String + if let _ = Configuration(yaml: yamlContents) { + print("Loading configuration from '\(path)'") + self.init(yaml: yamlContents)! + } else { + self.init()! + } + } catch { + failIfRequired() + self.init()! + } + } + } +} diff --git a/Source/SwiftLintFramework/File+SwiftLint.swift b/Source/SwiftLintFramework/File+SwiftLint.swift index e3571877e..59dd517fd 100644 --- a/Source/SwiftLintFramework/File+SwiftLint.swift +++ b/Source/SwiftLintFramework/File+SwiftLint.swift @@ -16,26 +16,23 @@ extension File { withSyntaxKinds syntaxKinds: [SyntaxKind]) -> [NSRange] { return matchPattern(pattern).filter { _, kindsInRange in return kindsInRange.count == syntaxKinds.count && - filter(zip(kindsInRange, syntaxKinds), { $0.0 != $0.1 }).count == 0 + zip(kindsInRange, syntaxKinds).filter({ $0.0 != $0.1 }).count == 0 }.map { $0.0 } } public func matchPattern(pattern: String) -> [(NSRange, [SyntaxKind])] { - return flatMap(NSRegularExpression(pattern: pattern, options: nil, error: nil)) { regex in - let range = NSRange(location: 0, length: count(contents.utf16)) - let syntax = syntaxMap - let matches = regex.matchesInString(contents, options: nil, range: range) - return map(matches as? [NSTextCheckingResult]) { matches in - return matches.map { match in - let tokensInRange = syntax.tokens.filter { - NSLocationInRange($0.offset, match.range) - } - let kindsInRange = compact(map(tokensInRange) { - SyntaxKind(rawValue: $0.type) - }) - return (match.range, kindsInRange) - } + 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) } - } ?? [] + let kindsInRange = tokensInRange.flatMap { + SyntaxKind(rawValue: $0.type) + } + return (match.range, kindsInRange) + } } } diff --git a/Source/SwiftLintFramework/Info.plist b/Source/SwiftLintFramework/Info.plist index 8c798dbec..186eccf12 100644 --- a/Source/SwiftLintFramework/Info.plist +++ b/Source/SwiftLintFramework/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - io.realm.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Source/SwiftLintFramework/Linter.swift b/Source/SwiftLintFramework/Linter.swift index e04e60c53..fcafcc94e 100644 --- a/Source/SwiftLintFramework/Linter.swift +++ b/Source/SwiftLintFramework/Linter.swift @@ -13,31 +13,14 @@ import SourceKittenFramework public struct Linter { private let file: File - private let rules: [Rule] = [ - LineLengthRule(), - LeadingWhitespaceRule(), - TrailingWhitespaceRule(), - ReturnArrowWhitespaceRule(), - TrailingNewlineRule(), - OperatorFunctionWhitespaceRule(), - ForceCastRule(), - FileLengthRule(), - TodoRule(), - ColonRule(), - TypeNameRule(), - VariableNameRule(), - TypeBodyLengthRule(), - FunctionBodyLengthRule(), - NestingRule(), - ControlStatementRule() - ] + private let rules: [Rule] public var styleViolations: [StyleViolation] { - return rules.flatMap { $0.validateFile(file) } + return rules.flatMap { $0.validateFile(self.file) } } public var ruleExamples: [RuleExample] { - return compact(rules.map { $0.example }) + return rules.flatMap { $0.example } } /** @@ -45,7 +28,8 @@ public struct Linter { :param: file File to lint. */ - public init(file: File) { + public init(file: File, configuration: Configuration = Configuration()!) { self.file = file + rules = configuration.rules } } diff --git a/Source/SwiftLintFramework/Location.swift b/Source/SwiftLintFramework/Location.swift index 9cb786dce..5c773d1ab 100644 --- a/Source/SwiftLintFramework/Location.swift +++ b/Source/SwiftLintFramework/Location.swift @@ -8,7 +8,7 @@ import SourceKittenFramework -public struct Location: Printable, Equatable { +public struct Location: CustomStringConvertible, Equatable { public let file: String? public let line: Int? public let character: Int? @@ -16,8 +16,8 @@ public struct Location: Printable, Equatable { // Xcode likes warnings and errors in the following format: // {full_path_to_file}{:line}{:character}: {error,warning}: {content} return (file ?? "") + - (map(line, { ":\($0)" }) ?? "") + - (map(character, { ":\($0)" }) ?? "") + (line.map({ ":\($0)" }) ?? "") + + (character.map({ ":\($0)" }) ?? "") } public init(file: String?, line: Int? = nil, character: Int? = nil) { diff --git a/Source/SwiftLintFramework/NSFileManager+SwiftLint.swift b/Source/SwiftLintFramework/NSFileManager+SwiftLint.swift index 44a3944da..cf5f656af 100644 --- a/Source/SwiftLintFramework/NSFileManager+SwiftLint.swift +++ b/Source/SwiftLintFramework/NSFileManager+SwiftLint.swift @@ -7,14 +7,11 @@ // import Foundation -import SourceKittenFramework extension NSFileManager { - public func allFilesRecursively(# directory: String) -> [String] { - let relativeFiles = (contentsOfDirectoryAtPath(directory, error: nil) as? [String] ?? []) + - (subpathsOfDirectoryAtPath(directory, error: nil) as? [String] ?? []) - return relativeFiles.map { - directory.stringByAppendingPathComponent($0) - } + public func allFilesRecursively(directory directory: String) -> [String] { + let relativeFiles = (try! contentsOfDirectoryAtPath(directory)) + + (try! subpathsOfDirectoryAtPath(directory)) + return relativeFiles.map((directory as NSString).stringByAppendingPathComponent) } } diff --git a/Source/SwiftLintFramework/Rule.swift b/Source/SwiftLintFramework/Rule.swift index 5f5534e14..8a73f30ec 100644 --- a/Source/SwiftLintFramework/Rule.swift +++ b/Source/SwiftLintFramework/Rule.swift @@ -18,3 +18,22 @@ public protocol ParameterizedRule: Rule { typealias ParameterType var parameters: [RuleParameter] { get } } + +public let allRules: [Rule] = [ + LineLengthRule(), + LeadingWhitespaceRule(), + TrailingWhitespaceRule(), + ReturnArrowWhitespaceRule(), + TrailingNewlineRule(), + OperatorFunctionWhitespaceRule(), + ForceCastRule(), + FileLengthRule(), + TodoRule(), + ColonRule(), + TypeNameRule(), + VariableNameRule(), + TypeBodyLengthRule(), + FunctionBodyLengthRule(), + NestingRule(), + ControlStatementRule() +] diff --git a/Source/SwiftLintFramework/Rules/ControlStatementRule.swift b/Source/SwiftLintFramework/Rules/ControlStatementRule.swift index 8c78c6fb7..7218c3f59 100644 --- a/Source/SwiftLintFramework/Rules/ControlStatementRule.swift +++ b/Source/SwiftLintFramework/Rules/ControlStatementRule.swift @@ -14,9 +14,9 @@ public struct ControlStatementRule: Rule { public let identifier = "control_statement" public func validateFile(file: File) -> [StyleViolation] { - return ["if", "for", "switch", "while"].flatMap { statementKind in + return ["if", "for", "switch", "while"].flatMap { statementKind -> [StyleViolation] in let pattern = "\(statementKind)\\s*\\([^,]*\\)\\s*\\{" - return compact(file.matchPattern(pattern).map { match, syntaxKinds in + return file.matchPattern(pattern).flatMap { match, syntaxKinds in if syntaxKinds.first != .Keyword { return nil } @@ -25,7 +25,7 @@ public struct ControlStatementRule: Rule { severity: .Low, reason: "\(statementKind) statements shouldn't wrap their conditionals in " + "parentheses.") - }) + } } } diff --git a/Source/SwiftLintFramework/Rules/FileLengthRule.swift b/Source/SwiftLintFramework/Rules/FileLengthRule.swift index 6b6088711..d7099a380 100644 --- a/Source/SwiftLintFramework/Rules/FileLengthRule.swift +++ b/Source/SwiftLintFramework/Rules/FileLengthRule.swift @@ -23,7 +23,7 @@ public struct FileLengthRule: ParameterizedRule { public func validateFile(file: File) -> [StyleViolation] { let lines = file.contents.lines() - for parameter in reverse(parameters) { + for parameter in parameters.reverse() { if lines.count > parameter.value { return [StyleViolation(type: .Length, location: Location(file: file.path, line: lines.count), diff --git a/Source/SwiftLintFramework/Rules/FunctionBodyLengthRule.swift b/Source/SwiftLintFramework/Rules/FunctionBodyLengthRule.swift index 46e0991c3..8fb60d37d 100644 --- a/Source/SwiftLintFramework/Rules/FunctionBodyLengthRule.swift +++ b/Source/SwiftLintFramework/Rules/FunctionBodyLengthRule.swift @@ -27,13 +27,16 @@ public struct FunctionBodyLengthRule: ASTRule, ParameterizedRule { } public func validateFile(file: File, dictionary: XPCDictionary) -> [StyleViolation] { - return (dictionary["key.substructure"] as? XPCArray ?? []).flatMap { subItem in + let substructure = dictionary["key.substructure"] as? XPCArray ?? [] + return substructure.flatMap { subItem -> [StyleViolation] in var violations = [StyleViolation]() if let subDict = subItem as? XPCDictionary, let kindString = subDict["key.kind"] as? String, - let kind = flatMap(kindString, { SwiftDeclarationKind(rawValue: $0) }) { - violations.extend(validateFile(file, dictionary: subDict)) - violations.extend(validateFile(file, kind: kind, dictionary: subDict)) + let kind = SwiftDeclarationKind(rawValue: kindString) { + violations.appendContentsOf( + self.validateFile(file, dictionary: subDict) + + self.validateFile(file, kind: kind, dictionary: subDict) + ) } return violations } @@ -58,16 +61,16 @@ public struct FunctionBodyLengthRule: ASTRule, ParameterizedRule { .FunctionOperator, .FunctionSubscript ] - if !contains(functionKinds, kind) { + if !functionKinds.contains(kind) { return [] } - if let offset = flatMap(dictionary["key.offset"] as? Int64, { Int($0) }), - let bodyOffset = flatMap(dictionary["key.bodyoffset"] as? Int64, { Int($0) }), - let bodyLength = flatMap(dictionary["key.bodylength"] as? Int64, { Int($0) }) { + if let offset = (dictionary["key.offset"] as? Int64).flatMap({ Int($0) }), + let bodyOffset = (dictionary["key.bodyoffset"] as? Int64).flatMap({ Int($0) }), + let bodyLength = (dictionary["key.bodylength"] as? Int64).flatMap({ Int($0) }) { let location = Location(file: file, offset: offset) let startLine = file.contents.lineAndCharacterForByteOffset(bodyOffset) let endLine = file.contents.lineAndCharacterForByteOffset(bodyOffset + bodyLength) - for parameter in reverse(parameters) { + for parameter in parameters.reverse() { if let startLine = startLine?.line, let endLine = endLine?.line where endLine - startLine > parameter.value { return [StyleViolation(type: .Length, diff --git a/Source/SwiftLintFramework/Rules/LineLengthRule.swift b/Source/SwiftLintFramework/Rules/LineLengthRule.swift index fb0b9ef6e..26549e76d 100644 --- a/Source/SwiftLintFramework/Rules/LineLengthRule.swift +++ b/Source/SwiftLintFramework/Rules/LineLengthRule.swift @@ -22,18 +22,18 @@ public struct LineLengthRule: ParameterizedRule { ] public func validateFile(file: File) -> [StyleViolation] { - return compact(file.contents.lines().map { line in - for parameter in reverse(self.parameters) { - if count(line.content) > parameter.value { + return file.contents.lines().flatMap { line in + for parameter in parameters.reverse() { + if line.content.characters.count > parameter.value { return StyleViolation(type: .Length, location: Location(file: file.path, line: line.index), severity: parameter.severity, reason: "Line should be 100 characters or less: currently " + - "\(count(line.content)) characters") + "\(line.content.characters.count) characters") } } return nil - }) + } } public let example = RuleExample( diff --git a/Source/SwiftLintFramework/Rules/NestingRule.swift b/Source/SwiftLintFramework/Rules/NestingRule.swift index ea792e135..04c759530 100644 --- a/Source/SwiftLintFramework/Rules/NestingRule.swift +++ b/Source/SwiftLintFramework/Rules/NestingRule.swift @@ -19,13 +19,16 @@ public struct NestingRule: ASTRule { } public func validateFile(file: File, dictionary: XPCDictionary) -> [StyleViolation] { - return (dictionary["key.substructure"] as? XPCArray ?? []).flatMap { subItem in + let substructure = dictionary["key.substructure"] as? XPCArray ?? [] + return substructure.flatMap { subItem -> [StyleViolation] in var violations = [StyleViolation]() if let subDict = subItem as? XPCDictionary, let kindString = subDict["key.kind"] as? String, - let kind = flatMap(kindString, { SwiftDeclarationKind(rawValue: $0) }) { - violations.extend(validateFile(file, dictionary: subDict)) - violations.extend(validateFile(file, kind: kind, dictionary: subDict)) + let kind = SwiftDeclarationKind(rawValue: kindString) { + violations.appendContentsOf( + self.validateFile(file, dictionary: subDict) + + self.validateFile(file, kind: kind, dictionary: subDict) + ) } return violations } @@ -34,7 +37,7 @@ public struct NestingRule: ASTRule { public func validateFile(file: File, kind: SwiftDeclarationKind, dictionary: XPCDictionary) -> [StyleViolation] { - return self.validateFile(file, kind: kind, dictionary: dictionary, level: 0) + return validateFile(file, kind: kind, dictionary: dictionary, level: 0) } func validateFile(file: File, @@ -47,10 +50,15 @@ public struct NestingRule: ASTRule { .Struct, .Typealias, .Enum, - .Enumelement + .Enumcase ] - if let offset = flatMap(dictionary["key.offset"] as? Int64, { Int($0) }) { - if level > 1 && contains(typeKinds, kind) { + if let offset = (dictionary["key.offset"] as? Int64).flatMap({ Int($0) }) { + if level > 1 && typeKinds.contains(kind) { + violations.append(StyleViolation(type: .Nesting, + location: Location(file: file, offset: offset), + reason: "Types should be nested at most 1 level deep")) + } else if level > 2 && kind == .Enumelement { + // Enum elements are implicitly wrapped in an .Enumcase violations.append(StyleViolation(type: .Nesting, location: Location(file: file, offset: offset), reason: "Types should be nested at most 1 level deep")) @@ -61,18 +69,18 @@ public struct NestingRule: ASTRule { } } let substructure = dictionary["key.substructure"] as? XPCArray ?? [] - violations.extend(compact(substructure.map { subItem in + violations.appendContentsOf(substructure.flatMap { subItem in let subDict = subItem as? XPCDictionary let kindString = subDict?["key.kind"] as? String - let kind = flatMap(kindString) { kindString in + let kind = kindString.flatMap { kindString in return SwiftDeclarationKind(rawValue: kindString) } if let kind = kind, subDict = subDict { return (kind, subDict) } return nil - } as [(SwiftDeclarationKind, XPCDictionary)?]).flatMap { (kind, dict) in - return validateFile(file, kind: kind, dictionary: dict, level: level + 1) + }.flatMap { (kind, dict) -> [StyleViolation] in + return self.validateFile(file, kind: kind, dictionary: dict, level: level + 1) }) return violations } diff --git a/Source/SwiftLintFramework/Rules/OperatorFunctionWhitespaceRule.swift b/Source/SwiftLintFramework/Rules/OperatorFunctionWhitespaceRule.swift index 1e87f166c..95aae2bb7 100644 --- a/Source/SwiftLintFramework/Rules/OperatorFunctionWhitespaceRule.swift +++ b/Source/SwiftLintFramework/Rules/OperatorFunctionWhitespaceRule.swift @@ -17,15 +17,19 @@ public struct OperatorFunctionWhitespaceRule: Rule { let operators = ["/", "=", "-", "+", "!", "*", "|", "^", "~", "?", "."].map({"\\\($0)"}) + ["%", "<", ">", "&"] let zeroOrManySpaces = "(\\s{0}|\\s{2,})" - let pattern1 = "func\\s+[" + "".join(operators) + "]+\(zeroOrManySpaces)(<[A-Z]+>)?\\(" - let pattern2 = "func\(zeroOrManySpaces)[" + "".join(operators) + "]+\\s+(<[A-Z]+>)?\\(" + let pattern1 = "func\\s+[" + + operators.joinWithSeparator("") + + "]+\(zeroOrManySpaces)(<[A-Z]+>)?\\(" + let pattern2 = "func\(zeroOrManySpaces)[" + + operators.joinWithSeparator("") + + "]+\\s+(<[A-Z]+>)?\\(" return file.matchPattern("(\(pattern1)|\(pattern2))").filter { _, syntaxKinds in return syntaxKinds.first == .Keyword }.map { range, _ in return StyleViolation(type: .OperatorFunctionWhitespace, location: Location(file: file, offset: range.location), severity: .Medium, - reason: self.example.ruleDescription) + reason: example.ruleDescription) } } diff --git a/Source/SwiftLintFramework/Rules/ReturnArrowWhitespaceRule.swift b/Source/SwiftLintFramework/Rules/ReturnArrowWhitespaceRule.swift index e8d6a0fcb..a5003cd98 100644 --- a/Source/SwiftLintFramework/Rules/ReturnArrowWhitespaceRule.swift +++ b/Source/SwiftLintFramework/Rules/ReturnArrowWhitespaceRule.swift @@ -6,6 +6,7 @@ // Copyright (c) 2015 Realm. All rights reserved. // +import Foundation import SourceKittenFramework public struct ReturnArrowWhitespaceRule: Rule { diff --git a/Source/SwiftLintFramework/Rules/TrailingNewlineRule.swift b/Source/SwiftLintFramework/Rules/TrailingNewlineRule.swift index eccc53fc4..e8751c247 100644 --- a/Source/SwiftLintFramework/Rules/TrailingNewlineRule.swift +++ b/Source/SwiftLintFramework/Rules/TrailingNewlineRule.swift @@ -15,13 +15,13 @@ public struct TrailingNewlineRule: Rule { public func validateFile(file: File) -> [StyleViolation] { let string = file.contents - let start = advance(string.endIndex, -2, string.startIndex) + let start = string.endIndex.advancedBy(-2, limit: string.startIndex) let range = Range(start: start, end: string.endIndex) let substring = string[range].utf16 let newLineSet = NSCharacterSet.newlineCharacterSet() - let slices = split(substring, allowEmptySlices: true) { !newLineSet.characterIsMember($0) } + let slices = substring.split(allowEmptySlices: true) { !newLineSet.characterIsMember($0) } - if let slice = slices.last where count(slice) != 1 { + if let slice = slices.last where slice.count != 1 { return [StyleViolation(type: .TrailingNewline, location: Location(file: file.path, line: file.contents.lines().count + 1), severity: .Medium, diff --git a/Source/SwiftLintFramework/Rules/TypeBodyLengthRule.swift b/Source/SwiftLintFramework/Rules/TypeBodyLengthRule.swift index bf2f0fef2..5a2d12613 100644 --- a/Source/SwiftLintFramework/Rules/TypeBodyLengthRule.swift +++ b/Source/SwiftLintFramework/Rules/TypeBodyLengthRule.swift @@ -27,13 +27,16 @@ public struct TypeBodyLengthRule: ASTRule, ParameterizedRule { } public func validateFile(file: File, dictionary: XPCDictionary) -> [StyleViolation] { - return (dictionary["key.substructure"] as? XPCArray ?? []).flatMap { subItem in + let substructure = dictionary["key.substructure"] as? XPCArray ?? [] + return substructure.flatMap { subItem -> [StyleViolation] in var violations = [StyleViolation]() if let subDict = subItem as? XPCDictionary, let kindString = subDict["key.kind"] as? String, - let kind = flatMap(kindString, { SwiftDeclarationKind(rawValue: $0) }) { - violations.extend(validateFile(file, dictionary: subDict)) - violations.extend(validateFile(file, kind: kind, dictionary: subDict)) + let kind = SwiftDeclarationKind(rawValue: kindString) { + violations.appendContentsOf( + self.validateFile(file, dictionary: subDict) + + self.validateFile(file, kind: kind, dictionary: subDict) + ) } return violations } @@ -47,16 +50,16 @@ public struct TypeBodyLengthRule: ASTRule, ParameterizedRule { .Struct, .Enum ] - if !contains(typeKinds, kind) { + if !typeKinds.contains(kind) { return [] } - if let offset = flatMap(dictionary["key.offset"] as? Int64, { Int($0) }), - let bodyOffset = flatMap(dictionary["key.bodyoffset"] as? Int64, { Int($0) }), - let bodyLength = flatMap(dictionary["key.bodylength"] as? Int64, { Int($0) }) { + if let offset = (dictionary["key.offset"] as? Int64).flatMap({ Int($0) }), + let bodyOffset = (dictionary["key.bodyoffset"] as? Int64).flatMap({ Int($0) }), + let bodyLength = (dictionary["key.bodylength"] as? Int64).flatMap({ Int($0) }) { let location = Location(file: file, offset: offset) let startLine = file.contents.lineAndCharacterForByteOffset(bodyOffset) let endLine = file.contents.lineAndCharacterForByteOffset(bodyOffset + bodyLength) - for parameter in reverse(parameters) { + for parameter in parameters.reverse() { if let startLine = startLine?.line, let endLine = endLine?.line where endLine - startLine > parameter.value { return [StyleViolation(type: .Length, diff --git a/Source/SwiftLintFramework/Rules/TypeNameRule.swift b/Source/SwiftLintFramework/Rules/TypeNameRule.swift index 510452101..a3af178b3 100644 --- a/Source/SwiftLintFramework/Rules/TypeNameRule.swift +++ b/Source/SwiftLintFramework/Rules/TypeNameRule.swift @@ -19,13 +19,16 @@ public struct TypeNameRule: ASTRule { } public func validateFile(file: File, dictionary: XPCDictionary) -> [StyleViolation] { - return (dictionary["key.substructure"] as? XPCArray ?? []).flatMap { subItem in + let substructure = dictionary["key.substructure"] as? XPCArray ?? [] + return substructure.flatMap { subItem -> [StyleViolation] in var violations = [StyleViolation]() if let subDict = subItem as? XPCDictionary, let kindString = subDict["key.kind"] as? String, - let kind = flatMap(kindString, { SwiftDeclarationKind(rawValue: $0) }) { - violations.extend(validateFile(file, dictionary: subDict)) - violations.extend(validateFile(file, kind: kind, dictionary: subDict)) + let kind = SwiftDeclarationKind(rawValue: kindString) { + violations.appendContentsOf( + self.validateFile(file, dictionary: subDict) + + self.validateFile(file, kind: kind, dictionary: subDict) + ) } return violations } @@ -41,12 +44,12 @@ public struct TypeNameRule: ASTRule { .Enum, .Enumelement ] - if !contains(typeKinds, kind) { + if !typeKinds.contains(kind) { return [] } var violations = [StyleViolation]() if let name = dictionary["key.name"] as? String, - let offset = flatMap(dictionary["key.offset"] as? Int64, { Int($0) }) { + let offset = (dictionary["key.offset"] as? Int64).flatMap({ Int($0) }) { let location = Location(file: file, offset: offset) let nameCharacterSet = NSCharacterSet(charactersInString: name) if !NSCharacterSet.alphanumericCharacterSet().isSupersetOfSet(nameCharacterSet) { @@ -59,7 +62,7 @@ public struct TypeNameRule: ASTRule { location: location, severity: .High, reason: "Type name should start with an uppercase character: '\(name)'")) - } else if count(name) < 3 || count(name) > 40 { + } else if name.characters.count < 3 || name.characters.count > 40 { violations.append(StyleViolation(type: .NameFormat, location: location, severity: .Medium, diff --git a/Source/SwiftLintFramework/Rules/VariableNameRule.swift b/Source/SwiftLintFramework/Rules/VariableNameRule.swift index 9e5a9a4d1..5ebea50ac 100644 --- a/Source/SwiftLintFramework/Rules/VariableNameRule.swift +++ b/Source/SwiftLintFramework/Rules/VariableNameRule.swift @@ -19,13 +19,16 @@ public struct VariableNameRule: ASTRule { } public func validateFile(file: File, dictionary: XPCDictionary) -> [StyleViolation] { - return (dictionary["key.substructure"] as? XPCArray ?? []).flatMap { subItem in + let substructure = dictionary["key.substructure"] as? XPCArray ?? [] + return substructure.flatMap { subItem -> [StyleViolation] in var violations = [StyleViolation]() if let subDict = subItem as? XPCDictionary, let kindString = subDict["key.kind"] as? String, - let kind = flatMap(kindString, { SwiftDeclarationKind(rawValue: $0) }) { - violations.extend(validateFile(file, dictionary: subDict)) - violations.extend(validateFile(file, kind: kind, dictionary: subDict)) + let kind = SwiftDeclarationKind(rawValue: kindString) { + violations.appendContentsOf( + self.validateFile(file, dictionary: subDict) + + self.validateFile(file, kind: kind, dictionary: subDict) + ) } return violations } @@ -42,12 +45,12 @@ public struct VariableNameRule: ASTRule { .VarParameter, .VarStatic ] - if !contains(variableKinds, kind) { + if !variableKinds.contains(kind) { return [] } var violations = [StyleViolation]() if let name = dictionary["key.name"] as? String, - let offset = flatMap(dictionary["key.offset"] as? Int64, { Int($0) }) { + let offset = (dictionary["key.offset"] as? Int64).flatMap({ Int($0) }) { let location = Location(file: file, offset: offset) let nameCharacterSet = NSCharacterSet(charactersInString: name) if !NSCharacterSet.alphanumericCharacterSet().isSupersetOfSet(nameCharacterSet) { @@ -60,7 +63,7 @@ public struct VariableNameRule: ASTRule { location: location, severity: .High, reason: "Variable name should start with a lowercase character: '\(name)'")) - } else if count(name) < 3 || count(name) > 40 { + } else if name.characters.count < 3 || name.characters.count > 40 { violations.append(StyleViolation(type: .NameFormat, location: location, severity: .Medium, diff --git a/Source/SwiftLintFramework/String+SwiftLint.swift b/Source/SwiftLintFramework/String+SwiftLint.swift index 4bf232773..7ce54bd76 100644 --- a/Source/SwiftLintFramework/String+SwiftLint.swift +++ b/Source/SwiftLintFramework/String+SwiftLint.swift @@ -24,7 +24,7 @@ extension String { } func countOfTailingCharactersInSet(characterSet: NSCharacterSet) -> Int { - return String(reverse(self)).countOfLeadingCharactersInSet(characterSet) + return String(characters.reverse()).countOfLeadingCharactersInSet(characterSet) } public var chomped: String { @@ -34,20 +34,16 @@ extension String { extension NSString { public func lineAndCharacterForByteOffset(offset: Int) -> (line: Int, character: Int)? { - return flatMap(byteRangeToNSRange(start: offset, length: 0)) { range in - var numberOfLines = 0 - var index = 0 - var lineRangeStart = 0 - var previousIndex = 0 + return byteRangeToNSRange(start: offset, length: 0).flatMap { range in + var numberOfLines = 0, index = 0, lineRangeStart = 0, previousIndex = 0 while index < length { numberOfLines++ - if index <= range.location { - lineRangeStart = numberOfLines - previousIndex = index - index = NSMaxRange(self.lineRangeForRange(NSRange(location: index, length: 1))) - } else { + if index > range.location { break } + lineRangeStart = numberOfLines + previousIndex = index + index = NSMaxRange(lineRangeForRange(NSRange(location: index, length: 1))) } return (lineRangeStart, range.location - previousIndex + 1) } diff --git a/Source/SwiftLintFramework/StyleViolation.swift b/Source/SwiftLintFramework/StyleViolation.swift index 1fe1dfb08..8a1795f17 100644 --- a/Source/SwiftLintFramework/StyleViolation.swift +++ b/Source/SwiftLintFramework/StyleViolation.swift @@ -6,7 +6,7 @@ // Copyright (c) 2015 Realm. All rights reserved. // -public struct StyleViolation: Printable, Equatable { +public struct StyleViolation: CustomStringConvertible, Equatable { public let type: StyleViolationType public let severity: ViolationSeverity public let location: Location diff --git a/Source/SwiftLintFramework/StyleViolationType.swift b/Source/SwiftLintFramework/StyleViolationType.swift index 0d7036e8e..6dd2a5445 100644 --- a/Source/SwiftLintFramework/StyleViolationType.swift +++ b/Source/SwiftLintFramework/StyleViolationType.swift @@ -6,7 +6,7 @@ // Copyright (c) 2015 Realm. All rights reserved. // -public enum StyleViolationType: String, Printable { +public enum StyleViolationType: String, CustomStringConvertible { case NameFormat = "Name Format" case Length = "Length" case TrailingNewline = "Trailing Newline" diff --git a/Source/SwiftLintFramework/ViolationSeverity.swift b/Source/SwiftLintFramework/ViolationSeverity.swift index 823e21f45..6cb15a0ee 100644 --- a/Source/SwiftLintFramework/ViolationSeverity.swift +++ b/Source/SwiftLintFramework/ViolationSeverity.swift @@ -6,7 +6,7 @@ // Copyright (c) 2015 Realm. All rights reserved. // -public enum ViolationSeverity: Int, Printable, Comparable { +public enum ViolationSeverity: Int, CustomStringConvertible, Comparable { case VeryLow case Low case Medium diff --git a/Source/SwiftLintFrameworkTests/ASTRuleTests.swift b/Source/SwiftLintFrameworkTests/ASTRuleTests.swift index 3c6eb9f15..82000f13d 100644 --- a/Source/SwiftLintFrameworkTests/ASTRuleTests.swift +++ b/Source/SwiftLintFrameworkTests/ASTRuleTests.swift @@ -29,7 +29,7 @@ class ASTRuleTests: XCTestCase { severity: .Medium, reason: "Type name should be between 3 and 40 characters in length: 'Ab'")]) - let longName = join("", Array(count: 40, repeatedValue: "A")) + let longName = Repeat(count: 40, repeatedValue: "A").joinWithSeparator("") XCTAssertEqual(violations("\(kind) \(longName) {}\n"), []) let longerName = longName + "A" XCTAssertEqual(violations("\(kind) \(longerName) {}\n"), [ @@ -57,7 +57,7 @@ class ASTRuleTests: XCTestCase { func testVariableNames() { for kind in ["class", "struct"] { for varType in ["var", "let"] { - let characterOffset = 8 + count(kind) + let characterOffset = 8 + kind.characters.count XCTAssertEqual(violations("\(kind) Abc { \(varType) def: Void }\n"), []) XCTAssertEqual(violations("\(kind) Abc { \(varType) de_: Void }\n"), [ @@ -82,7 +82,7 @@ class ASTRuleTests: XCTestCase { "'de'") ]) - let longName = join("", Array(count: 40, repeatedValue: "d")) + let longName = Repeat(count: 40, repeatedValue: "d").joinWithSeparator("") XCTAssertEqual(violations("\(kind) Abc { \(varType) \(longName): Void }\n"), []) let longerName = longName + "d" XCTAssertEqual(violations("\(kind) Abc { \(varType) \(longerName): Void }\n"), [ @@ -98,11 +98,11 @@ class ASTRuleTests: XCTestCase { func testFunctionBodyLengths() { let longFunctionBody = "func abc() {" + - join("", Array(count: 40, repeatedValue: "\n")) + + Repeat(count: 40, repeatedValue: "\n").joinWithSeparator("") + "}\n" XCTAssertEqual(violations(longFunctionBody), []) let longerFunctionBody = "func abc() {" + - join("", Array(count: 41, repeatedValue: "\n")) + + Repeat(count: 41, repeatedValue: "\n").joinWithSeparator("") + "}\n" XCTAssertEqual(violations(longerFunctionBody), [StyleViolation(type: .Length, location: Location(file: nil, line: 1, character: 1), @@ -113,11 +113,11 @@ class ASTRuleTests: XCTestCase { func testTypeBodyLengths() { for kind in ["class", "struct", "enum"] { let longTypeBody = "\(kind) Abc {" + - join("", Array(count: 200, repeatedValue: "\n")) + + Repeat(count: 200, repeatedValue: "\n").joinWithSeparator("") + "}\n" XCTAssertEqual(violations(longTypeBody), []) let longerTypeBody = "\(kind) Abc {" + - join("", Array(count: 201, repeatedValue: "\n")) + + Repeat(count: 201, repeatedValue: "\n").joinWithSeparator("") + "}\n" XCTAssertEqual(violations(longerTypeBody), [StyleViolation(type: .Length, location: Location(file: nil, line: 1, character: 1), diff --git a/Source/SwiftLintFrameworkTests/ConfigurationTests.swift b/Source/SwiftLintFrameworkTests/ConfigurationTests.swift new file mode 100644 index 000000000..0af7e51e0 --- /dev/null +++ b/Source/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -0,0 +1,50 @@ +// +// ConfigurationTests.swift +// SwiftLint +// +// Created by JP Simard on 8/23/15. +// Copyright © 2015 Realm. All rights reserved. +// + +import SwiftLintFramework +import XCTest + +class ConfigurationTests: XCTestCase { + func testInit() { + XCTAssert(Configuration(yaml: "") != nil, + "initializing Configuration with empty YAML string should succeed") + XCTAssert(Configuration(yaml: "a: 1\nb: 2") != nil, + "initializing Configuration with valid YAML string should succeed") + XCTAssert(Configuration(yaml: "|\na") == nil, + "initializing Configuration with invalid YAML string should fail") + } + + func testEmptyConfiguration() { + guard let config = Configuration(yaml: "") else { + XCTFail("empty YAML string should yield non-nil Configuration") + return + } + XCTAssertEqual(config.disabledRules, []) + XCTAssertEqual(config.included, []) + XCTAssertEqual(config.excluded, []) + } + + func testDisabledRules() { + XCTAssert(Configuration(yaml: "disabled_rules:\n - a") == nil, + "initializing Configuration with invalid rules in YAML string should fail") + let disabledConfig = Configuration(yaml: "disabled_rules:\n - nesting\n - todo")! + XCTAssertEqual(disabledConfig.disabledRules, + ["nesting", "todo"], + "initializing Configuration with valid rules in YAML string should succeed") + let expectedIdentifiers = allRules + .map({ $0.identifier }) + .filter({ !["nesting", "todo"].contains($0) }) + let configuredIdentifiers = disabledConfig.rules.map({ $0.identifier }) + XCTAssertEqual(expectedIdentifiers, configuredIdentifiers) + + // Duplicate + let duplicateConfig = Configuration( yaml: "disabled_rules:\n - todo\n - todo") + XCTAssert(duplicateConfig == nil, "initializing Configuration with duplicate rules in " + + " YAML string should fail") + } +} diff --git a/Source/SwiftLintFrameworkTests/Info.plist b/Source/SwiftLintFrameworkTests/Info.plist index 3e5a88fb0..e90c12e6a 100644 --- a/Source/SwiftLintFrameworkTests/Info.plist +++ b/Source/SwiftLintFrameworkTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - io.realm.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Source/SwiftLintFrameworkTests/IntegrationTests.swift b/Source/SwiftLintFrameworkTests/IntegrationTests.swift index 704f1c7c6..c66c9e90c 100644 --- a/Source/SwiftLintFrameworkTests/IntegrationTests.swift +++ b/Source/SwiftLintFrameworkTests/IntegrationTests.swift @@ -15,12 +15,14 @@ class IntegrationTests: XCTestCase { func testSwiftLintLints() { // This is as close as we're ever going to get to a self-hosting linter. let fileManager = NSFileManager.defaultManager() - let directory = fileManager.currentDirectoryPath.stringByAppendingPathComponent("Source") + let directory = ((((__FILE__ as NSString) + .stringByDeletingLastPathComponent as NSString) + .stringByDeletingLastPathComponent as NSString) + .stringByDeletingLastPathComponent as NSString) + .stringByAppendingPathComponent("Source") let allFiles = fileManager.allFilesRecursively(directory: directory) - let swiftFiles = allFiles.filter { - $0.isSwiftFile() - } - XCTAssert(contains(swiftFiles, __FILE__), "current file should be included") + let swiftFiles = allFiles.filter { $0.isSwiftFile() } + XCTAssert(swiftFiles.contains(__FILE__), "current file should be included") XCTAssertEqual(swiftFiles.flatMap({Linter(file: File(path: $0)!).styleViolations}), []) } } diff --git a/Source/SwiftLintFrameworkTests/StringRuleTests.swift b/Source/SwiftLintFrameworkTests/StringRuleTests.swift index eac23b0db..20476fbdc 100644 --- a/Source/SwiftLintFrameworkTests/StringRuleTests.swift +++ b/Source/SwiftLintFrameworkTests/StringRuleTests.swift @@ -11,14 +11,14 @@ import XCTest class StringRuleTests: XCTestCase { func testLineLengths() { - let longLine = join("", Array(count: 100, repeatedValue: "/")) + "\n" + let longLine = Repeat(count: 100, repeatedValue: "/").joinWithSeparator("") + "\n" XCTAssertEqual(violations(longLine), []) let testCases: [(String, Int, ViolationSeverity)] = [ ("/", 101, .VeryLow), - (join("", Array(count: 21, repeatedValue: "/")), 121, .Low), - (join("", Array(count: 51, repeatedValue: "/")), 151, .Medium), - (join("", Array(count: 101, repeatedValue: "/")), 201, .High), - (join("", Array(count: 151, repeatedValue: "/")), 251, .VeryHigh) + (Repeat(count: 21, repeatedValue: "/").joinWithSeparator(""), 121, .Low), + (Repeat(count: 51, repeatedValue: "/").joinWithSeparator(""), 151, .Medium), + (Repeat(count: 101, repeatedValue: "/").joinWithSeparator(""), 201, .High), + (Repeat(count: 151, repeatedValue: "/").joinWithSeparator(""), 251, .VeryHigh) ] for testCase in testCases { XCTAssertEqual(violations(testCase.0 + longLine), [StyleViolation(type: .Length, @@ -42,13 +42,16 @@ class StringRuleTests: XCTestCase { } func testFileLengths() { - XCTAssertEqual(violations(join("", Array(count: 400, repeatedValue: "//\n"))), []) + XCTAssertEqual( + violations(Repeat(count: 400, repeatedValue: "//\n").joinWithSeparator("")), + [] + ) let testCases: [(String, Int, ViolationSeverity)] = [ - (join("", Array(count: 401, repeatedValue: "//\n")), 401, .VeryLow), - (join("", Array(count: 501, repeatedValue: "//\n")), 501, .Low), - (join("", Array(count: 751, repeatedValue: "//\n")), 751, .Medium), - (join("", Array(count: 1001, repeatedValue: "//\n")), 1001, .High), - (join("", Array(count: 2001, repeatedValue: "//\n")), 2001, .VeryHigh) + (Repeat(count: 401, repeatedValue: "//\n").joinWithSeparator(""), 401, .VeryLow), + (Repeat(count: 501, repeatedValue: "//\n").joinWithSeparator(""), 501, .Low), + (Repeat(count: 751, repeatedValue: "//\n").joinWithSeparator(""), 751, .Medium), + (Repeat(count: 1001, repeatedValue: "//\n").joinWithSeparator(""), 1001, .High), + (Repeat(count: 2001, repeatedValue: "//\n").joinWithSeparator(""), 2001, .VeryHigh) ] for testCase in testCases { XCTAssertEqual(violations(testCase.0), [StyleViolation(type: .Length, diff --git a/Source/SwiftLintFrameworkTests/TestHelpers.swift b/Source/SwiftLintFrameworkTests/TestHelpers.swift index fdd1182bd..837524da5 100644 --- a/Source/SwiftLintFrameworkTests/TestHelpers.swift +++ b/Source/SwiftLintFrameworkTests/TestHelpers.swift @@ -14,7 +14,7 @@ func violations(string: String) -> [StyleViolation] { return Linter(file: File(contents: string)).styleViolations } -private func violations(string: String, type: StyleViolationType) -> [StyleViolation] { +private func violations(string: String, _ type: StyleViolationType) -> [StyleViolation] { return violations(string).filter { $0.type == type } } diff --git a/Source/swiftlint/Components.plist b/Source/swiftlint/Components.plist index 6c7141e76..8d3a3a1b0 100644 --- a/Source/swiftlint/Components.plist +++ b/Source/swiftlint/Components.plist @@ -7,27 +7,6 @@ BundleOverwriteAction upgrade - ChildBundles - - - BundleOverwriteAction - - RootRelativeBundlePath - Library/Frameworks/SwiftLintFramework.framework/Versions/A/Frameworks/SourceKittenFramework.framework - - - BundleOverwriteAction - - RootRelativeBundlePath - Library/Frameworks/SwiftLintFramework.framework/Versions/A/Frameworks/LlamaKit.framework - - - BundleOverwriteAction - - RootRelativeBundlePath - Library/Frameworks/SwiftLintFramework.framework/Versions/A/Frameworks/Commandant.framework - - RootRelativeBundlePath Library/Frameworks/SwiftLintFramework.framework diff --git a/Source/swiftlint/Info.plist b/Source/swiftlint/Info.plist index 52ede2e8a..afdd63f3c 100644 --- a/Source/swiftlint/Info.plist +++ b/Source/swiftlint/Info.plist @@ -9,7 +9,7 @@ CFBundleIconFile CFBundleIdentifier - io.realm.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Source/swiftlint/LintCommand.swift b/Source/swiftlint/LintCommand.swift index 34820d349..63ea59ec1 100644 --- a/Source/swiftlint/LintCommand.swift +++ b/Source/swiftlint/LintCommand.swift @@ -8,7 +8,7 @@ import Commandant import Foundation -import LlamaKit +import Result import SourceKittenFramework import SwiftLintFramework @@ -21,38 +21,44 @@ struct LintCommand: CommandType { func run(mode: CommandMode) -> Result<(), CommandantError<()>> { return LintOptions.evaluate(mode).flatMap { options in + let configuration = Configuration(path: options.configurationFile, + optional: !Process.arguments.contains("--config")) if options.useSTDIN { let standardInput = NSFileHandle.fileHandleWithStandardInput() let stdinData = standardInput.readDataToEndOfFile() let stdinNSString = NSString(data: stdinData, encoding: NSUTF8StringEncoding) if let stdinString = stdinNSString as? String { - let violations = Linter(file: File(contents: stdinString)).styleViolations - println(join("\n", violations.map { $0.description })) - return success() + let file = File(contents: stdinString) + let linter = Linter(file: file, configuration: configuration) + print(linter.styleViolations.map({ $0.description }).joinWithSeparator("\n")) + return .Success() } - return failure(CommandantError<()>.CommandError(Box())) + return .Failure(CommandantError<()>.CommandError()) } // Otherwise parse path. - return self.lint(options.path) + return lint(options.path, configuration: configuration) } } - private func lint(path: String) -> Result<(), CommandantError<()>> { - let filesToLint = filesToLintAtPath(path) + private func lint(path: String, + configuration: Configuration) -> Result<(), CommandantError<()>> { + let filesToLint = (configuration.included.count == 0 ? filesToLintAtPath(path) : []) + .filter({ !configuration.excluded.flatMap(filesToLintAtPath).contains($0) }) + + configuration.included.flatMap(filesToLintAtPath) if filesToLint.count > 0 { - - if path == "" { - println("Linting Swift files in current working directory") + if path.isEmpty { + print("Linting Swift files in current working directory") } else { - println("Linting Swift files at path \(path)") + print("Linting Swift files at path \(path)") } - var numberOfViolations = 0, numberOfSeriousViolations = 0 - for (index, file) in enumerate(filesToLint) { - println("Linting '\(file.lastPathComponent)' (\(index + 1)/\(filesToLint.count))") - for violation in Linter(file: File(path: file)!).styleViolations { - println(violation) + for (index, path) in filesToLint.enumerate() { + let filename = (path as NSString).lastPathComponent + print("Linting '\(filename)' (\(index + 1)/\(filesToLint.count))") + let file = File(path: path)! + for violation in Linter(file: file, configuration: configuration).styleViolations { + print(violation) numberOfViolations++ if violation.severity.isError { numberOfSeriousViolations++ @@ -61,27 +67,23 @@ struct LintCommand: CommandType { } let violationSuffix = (numberOfViolations != 1 ? "s" : "") let filesSuffix = (filesToLint.count != 1 ? "s." : ".") - println( + print( "Done linting!" + " Found \(numberOfViolations) violation\(violationSuffix)," + " \(numberOfSeriousViolations) serious" + " in \(filesToLint.count) file\(filesSuffix)" ) if numberOfSeriousViolations <= 0 { - return success() - } else { - // This represents failure of the content (i.e. violations in the files linted) - // and not failure of the scanning process itself. The current command architecture - // doesn't discriminate between these types. - return failure(CommandantError<()>.CommandError(Box())) + return .Success() } + return .Failure(CommandantError<()>.CommandError()) } - return failure(CommandantError<()>.UsageError(description: "No lintable files found at" + + return .Failure(CommandantError<()>.UsageError(description: "No lintable files found at" + " path \(path)")) } private func filesToLintAtPath(path: String) -> [String] { - let absolutePath = path.absolutePathRepresentation() + let absolutePath = (path.absolutePathRepresentation() as NSString).stringByStandardizingPath var isDirectory: ObjCBool = false if fileManager.fileExistsAtPath(absolutePath, isDirectory: &isDirectory) { if isDirectory { @@ -99,15 +101,22 @@ struct LintCommand: CommandType { struct LintOptions: OptionsType { let path: String let useSTDIN: Bool + let configurationFile: String - static func create(path: String)(useSTDIN: Bool) -> LintOptions { - return LintOptions(path: path, useSTDIN: useSTDIN) + static func create(path: String)(useSTDIN: Bool)(configurationFile: String) -> LintOptions { + return LintOptions(path: path, useSTDIN: useSTDIN, configurationFile: configurationFile) } static func evaluate(m: CommandMode) -> Result> { return create - <*> m <| Option(key: "path", defaultValue: "", usage: "the path to the file or" + - " directory to lint") - <*> m <| Option(key: "use-stdin", defaultValue: false, usage: "lint standard input") + <*> m <| Option(key: "path", + defaultValue: "", + usage: "the path to the file or directory to lint") + <*> m <| Option(key: "use-stdin", + defaultValue: false, + usage: "lint standard input") + <*> m <| Option(key: "config", + defaultValue: ".swiftlint.yml", + usage: "the path to SwiftLint's configuration file") } } diff --git a/Source/swiftlint/RulesCommand.swift b/Source/swiftlint/RulesCommand.swift index f9323061a..ff46a2373 100644 --- a/Source/swiftlint/RulesCommand.swift +++ b/Source/swiftlint/RulesCommand.swift @@ -8,7 +8,7 @@ import Foundation import Commandant -import LlamaKit +import Result import SwiftLintFramework import SourceKittenFramework @@ -34,15 +34,15 @@ struct RulesCommand: CommandType { func run(mode: CommandMode) -> Result<(), CommandantError<()>> { switch mode { - case let .Arguments: + case .Arguments: let ruleExamples = Linter(file: File(contents: "")).ruleExamples let text = StructuredText.Joined(ruleExamples.map(describeExample)) - println(text.ansi) + print(text.ansi) default: break } - return success() + return .Success() } } diff --git a/Source/swiftlint/StructuredText.swift b/Source/swiftlint/StructuredText.swift index c3dcb15ac..7423f3740 100644 --- a/Source/swiftlint/StructuredText.swift +++ b/Source/swiftlint/StructuredText.swift @@ -19,23 +19,23 @@ enum StructuredText { var markdown: String { switch self { case let .Header(level, t): - return join("", Array(count: level, repeatedValue: "#")) + " \(t)" + return String(Repeat(count: level, repeatedValue: "#")) + " \(t)" case .Paragraph(let t): return t case .List(let items): - return "\n".join(items.map { "* " + $0.markdown }) + return items.map({ "* " + $0.markdown }).joinWithSeparator("\n") case .Joined(let items): - return "\n\n".join(items.map { $0.markdown } ) + return items.map({ $0.markdown }).joinWithSeparator("\n\n") } } var ansi: String { switch self { case .Header(1, let t): return t.uppercaseString - case let .Header(other, t): return t + case .Header(_, let t): return t case .Paragraph(let t): return t - case .List(let items): return "\n".join(items.map { "* " + $0.ansi }) - case .Joined(let items): return "\n\n".join(items.map { $0.ansi } ) + case .List(let items): return items.map({ "* " + $0.ansi }).joinWithSeparator("\n") + case .Joined(let items): return items.map({ $0.ansi }).joinWithSeparator("\n\n") } } } diff --git a/Source/swiftlint/VersionCommand.swift b/Source/swiftlint/VersionCommand.swift index 5a5df025d..21bdf2333 100644 --- a/Source/swiftlint/VersionCommand.swift +++ b/Source/swiftlint/VersionCommand.swift @@ -7,7 +7,7 @@ // import Commandant -import LlamaKit +import Result private let version = "0.1.2" @@ -17,12 +17,12 @@ struct VersionCommand: CommandType { func run(mode: CommandMode) -> Result<(), CommandantError<()>> { switch mode { - case let .Arguments: - println(version) + case .Arguments: + print(version) default: break } - return success() + return .Success() } } diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index 1d1605e6a..15dd91249 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -19,6 +19,8 @@ D0E7B65619E9C76900EDBA4D /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D1211B19E87861005E4BAA /* main.swift */; }; E57B23C11B1D8BF000DEA512 /* ReturnArrowWhitespaceRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E57B23C01B1D8BF000DEA512 /* ReturnArrowWhitespaceRule.swift */; }; E5A167C91B25A0B000CF2D03 /* OperatorFunctionWhitespaceRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5A167C81B25A0B000CF2D03 /* OperatorFunctionWhitespaceRule.swift */; }; + E809EDA11B8A71DF00399043 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E809EDA01B8A71DF00399043 /* Configuration.swift */; }; + E809EDA31B8A73FB00399043 /* ConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E809EDA21B8A73FB00399043 /* ConfigurationTests.swift */; }; E812249A1B04F85B001783D2 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81224991B04F85B001783D2 /* TestHelpers.swift */; }; E812249C1B04FADC001783D2 /* Linter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E812249B1B04FADC001783D2 /* Linter.swift */; }; E832F10B1B17E2F5003F265F /* NSFileManager+SwiftLint.swift in Sources */ = {isa = PBXBuildFile; fileRef = E832F10A1B17E2F5003F265F /* NSFileManager+SwiftLint.swift */; }; @@ -52,10 +54,12 @@ E88DEA921B099B1F00A66CB0 /* TypeNameRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E88DEA911B099B1F00A66CB0 /* TypeNameRule.swift */; }; E88DEA941B099C0900A66CB0 /* VariableNameRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E88DEA931B099C0900A66CB0 /* VariableNameRule.swift */; }; E88DEA961B099CF200A66CB0 /* NestingRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E88DEA951B099CF200A66CB0 /* NestingRule.swift */; }; + E89376AD1B8A701E0025708E /* Yaml.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E89376AC1B8A701E0025708E /* Yaml.framework */; }; + E89376AE1B8A70400025708E /* Yaml.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = E89376AC1B8A701E0025708E /* Yaml.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E8AB1A2E1A649F2100452012 /* libclang.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E8AB1A2D1A649F2100452012 /* libclang.dylib */; }; E8BA7E111B07A3EC003E02D0 /* Commandant.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8BA7E101B07A3EC003E02D0 /* Commandant.framework */; }; - E8BA7E131B07A3F3003E02D0 /* LlamaKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8BA7E121B07A3F3003E02D0 /* LlamaKit.framework */; }; - E8BA7E141B07A400003E02D0 /* LlamaKit.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = E8BA7E121B07A3F3003E02D0 /* LlamaKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E8BA7E131B07A3F3003E02D0 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8BA7E121B07A3F3003E02D0 /* Result.framework */; }; + E8BA7E141B07A400003E02D0 /* Result.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = E8BA7E121B07A3F3003E02D0 /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E8BA7E151B07A400003E02D0 /* Commandant.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = E8BA7E101B07A3EC003E02D0 /* Commandant.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E8BB8F9A1B17DDB200199606 /* ASTRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8BB8F991B17DDB200199606 /* ASTRuleTests.swift */; }; E8BB8F9C1B17DE3B00199606 /* StringRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8BB8F9B1B17DE3B00199606 /* StringRuleTests.swift */; }; @@ -87,7 +91,8 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - E8BA7E141B07A400003E02D0 /* LlamaKit.framework in Copy Frameworks */, + E89376AE1B8A70400025708E /* Yaml.framework in Copy Frameworks */, + E8BA7E141B07A400003E02D0 /* Result.framework in Copy Frameworks */, E8BA7E151B07A400003E02D0 /* Commandant.framework in Copy Frameworks */, E876BFBF1B0782AA00114ED5 /* SourceKittenFramework.framework in Copy Frameworks */, E8C0DFCE1AD349E5007EE3D4 /* SWXMLHash.framework in Copy Frameworks */, @@ -142,9 +147,10 @@ D0D1217719E87B05005E4BAA /* SwiftLintFrameworkTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftLintFrameworkTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D0D1217D19E87B05005E4BAA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D0E7B63219E9C64500EDBA4D /* swiftlint.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = swiftlint.app; sourceTree = BUILT_PRODUCTS_DIR; }; - D0E7B65819E9CA0800EDBA4D /* swiftlint */ = {isa = PBXFileReference; lastKnownFileType = text; path = swiftlint; sourceTree = BUILT_PRODUCTS_DIR; }; E57B23C01B1D8BF000DEA512 /* ReturnArrowWhitespaceRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReturnArrowWhitespaceRule.swift; sourceTree = ""; }; E5A167C81B25A0B000CF2D03 /* OperatorFunctionWhitespaceRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperatorFunctionWhitespaceRule.swift; sourceTree = ""; }; + E809EDA01B8A71DF00399043 /* Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; + E809EDA21B8A73FB00399043 /* ConfigurationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurationTests.swift; sourceTree = ""; }; E81224991B04F85B001783D2 /* TestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = ""; }; E812249B1B04FADC001783D2 /* Linter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Linter.swift; sourceTree = ""; }; E832F10A1B17E2F5003F265F /* NSFileManager+SwiftLint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFileManager+SwiftLint.swift"; sourceTree = ""; }; @@ -176,9 +182,10 @@ E88DEA911B099B1F00A66CB0 /* TypeNameRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeNameRule.swift; sourceTree = ""; }; E88DEA931B099C0900A66CB0 /* VariableNameRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VariableNameRule.swift; sourceTree = ""; }; E88DEA951B099CF200A66CB0 /* NestingRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NestingRule.swift; sourceTree = ""; }; + E89376AC1B8A701E0025708E /* Yaml.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Yaml.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E8AB1A2D1A649F2100452012 /* libclang.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libclang.dylib; path = Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib; sourceTree = DEVELOPER_DIR; }; E8BA7E101B07A3EC003E02D0 /* Commandant.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Commandant.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - E8BA7E121B07A3F3003E02D0 /* LlamaKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = LlamaKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E8BA7E121B07A3F3003E02D0 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E8BB8F991B17DDB200199606 /* ASTRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASTRuleTests.swift; sourceTree = ""; }; E8BB8F9B1B17DE3B00199606 /* StringRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringRuleTests.swift; sourceTree = ""; }; E8C0DFCC1AD349DB007EE3D4 /* SWXMLHash.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SWXMLHash.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -189,7 +196,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E8BA7E131B07A3F3003E02D0 /* LlamaKit.framework in Frameworks */, + E89376AD1B8A701E0025708E /* Yaml.framework in Frameworks */, + E8BA7E131B07A3F3003E02D0 /* Result.framework in Frameworks */, E8BA7E111B07A3EC003E02D0 /* Commandant.framework in Frameworks */, E876BFBE1B07828500114ED5 /* SourceKittenFramework.framework in Frameworks */, E8AB1A2E1A649F2100452012 /* libclang.dylib in Frameworks */, @@ -244,7 +252,6 @@ D0D1216E19E87B05005E4BAA /* SwiftLintFramework */, D0D1217B19E87B05005E4BAA /* SwiftLintFrameworkTests */, D0D1211919E87861005E4BAA /* Products */, - D0E7B65819E9CA0800EDBA4D /* swiftlint */, ); sourceTree = ""; usesTabs = 0; @@ -343,6 +350,7 @@ isa = PBXGroup; children = ( E88DEA8B1B0999A000A66CB0 /* ASTRule.swift */, + E809EDA01B8A71DF00399043 /* Configuration.swift */, 24E17F701B1481FF008195BE /* File+Cache.swift */, E88DEA741B09852000A66CB0 /* File+SwiftLint.swift */, E812249B1B04FADC001783D2 /* Linter.swift */, @@ -365,7 +373,8 @@ D0D1216F19E87B05005E4BAA /* Supporting Files */ = { isa = PBXGroup; children = ( - E8BA7E121B07A3F3003E02D0 /* LlamaKit.framework */, + E89376AC1B8A701E0025708E /* Yaml.framework */, + E8BA7E121B07A3F3003E02D0 /* Result.framework */, E8BA7E101B07A3EC003E02D0 /* Commandant.framework */, E876BFBD1B07828500114ED5 /* SourceKittenFramework.framework */, E8AB1A2D1A649F2100452012 /* libclang.dylib */, @@ -381,6 +390,7 @@ isa = PBXGroup; children = ( E8BB8F991B17DDB200199606 /* ASTRuleTests.swift */, + E809EDA21B8A73FB00399043 /* ConfigurationTests.swift */, E832F10C1B17E725003F265F /* IntegrationTests.swift */, E8BB8F9B1B17DE3B00199606 /* StringRuleTests.swift */, E81224991B04F85B001783D2 /* TestHelpers.swift */, @@ -497,7 +507,8 @@ D0D1211019E87861005E4BAA /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0630; + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 0700; ORGANIZATIONNAME = Realm; TargetAttributes = { D0D1216C19E87B05005E4BAA = { @@ -574,7 +585,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if which swiftlint >/dev/null; then\n cd Source && swiftlint\nelse\n echo \"SwiftLint not installed. Skipping lint.\"\nfi"; + shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"SwiftLint not installed. Skipping lint.\"\nfi"; }; /* End PBXShellScriptBuildPhase section */ @@ -589,6 +600,7 @@ E57B23C11B1D8BF000DEA512 /* ReturnArrowWhitespaceRule.swift in Sources */, E88DEA841B0990F500A66CB0 /* ColonRule.swift in Sources */, E88DEA791B098D4400A66CB0 /* RuleParameter.swift in Sources */, + E809EDA11B8A71DF00399043 /* Configuration.swift in Sources */, E88DEA731B0984C400A66CB0 /* String+SwiftLint.swift in Sources */, 24E17F721B14BB3F008195BE /* File+Cache.swift in Sources */, E88DEA6D1B09842200A66CB0 /* StyleViolationType.swift in Sources */, @@ -623,6 +635,7 @@ E812249A1B04F85B001783D2 /* TestHelpers.swift in Sources */, E8BB8F9C1B17DE3B00199606 /* StringRuleTests.swift in Sources */, E8BB8F9A1B17DDB200199606 /* ASTRuleTests.swift in Sources */, + E809EDA31B8A73FB00399043 /* ConfigurationTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -659,6 +672,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = D0D1212619E878CC005E4BAA /* Debug.xcconfig */; buildSettings = { + ENABLE_TESTABILITY = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; @@ -688,15 +702,15 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib", - "$(PROJECT_DIR)/build/DerivedData/SwiftLint/Build/Products/Debug", ); FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/Source/SwiftLintFramework/Info.plist"; + INFOPLIST_FILE = "Source/SwiftLintFramework/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib", ); + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftLintFramework; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -720,15 +734,15 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib", - "$(PROJECT_DIR)/build/DerivedData/SwiftLint/Build/Products/Debug", ); FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/Source/SwiftLintFramework/Info.plist"; + INFOPLIST_FILE = "Source/SwiftLintFramework/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib", ); + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftLintFramework; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -749,6 +763,7 @@ "$(inherited)", ); INFOPLIST_FILE = Source/SwiftLintFrameworkTests/Info.plist; + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftLintFrameworkTests; }; name = Debug; @@ -762,6 +777,7 @@ "$(inherited)", ); INFOPLIST_FILE = Source/SwiftLintFrameworkTests/Info.plist; + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftLintFrameworkTests; }; name = Release; @@ -788,15 +804,15 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib", - "$(PROJECT_DIR)/build/DerivedData/SwiftLint/Build/Products/Debug", ); FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/Source/SwiftLintFramework/Info.plist"; + INFOPLIST_FILE = "Source/SwiftLintFramework/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib", ); + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftLintFramework; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -817,6 +833,7 @@ "$(inherited)", ); INFOPLIST_FILE = Source/SwiftLintFrameworkTests/Info.plist; + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftLintFrameworkTests; }; name = Profile; @@ -843,15 +860,15 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib", - "$(PROJECT_DIR)/build/DerivedData/SwiftLint/Build/Products/Debug", ); FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/Source/SwiftLintFramework/Info.plist"; + INFOPLIST_FILE = "Source/SwiftLintFramework/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(DEVELOPER_DIR)/Toolchains/XcodeDefault.xctoolchain/usr/lib", ); + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftLintFramework; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -872,6 +889,7 @@ "$(inherited)", ); INFOPLIST_FILE = Source/SwiftLintFrameworkTests/Info.plist; + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftLintFrameworkTests; }; name = Test; @@ -881,8 +899,9 @@ baseConfigurationReference = D0D1213419E878CC005E4BAA /* Mac-Application.xcconfig */; buildSettings = { FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = "$(SRCROOT)/Source/swiftlint/Info.plist"; + INFOPLIST_FILE = "Source/swiftlint/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/. @executable_path/../Frameworks @executable_path/SwiftLintFramework.framework/Versions/Current/Frameworks @executable_path/SwiftLintFramework.framework/Versions/Current/Frameworks/SourceKittenFramework.framework/Versions/Current/Frameworks /Library/Frameworks /Library/Frameworks/SwiftLintFramework.framework/Versions/Current/Frameworks /Library/Frameworks/SwiftLintFramework.framework/Versions/Current/Frameworks/SourceKittenFramework.framework/Versions/Current/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -892,8 +911,9 @@ baseConfigurationReference = D0D1213419E878CC005E4BAA /* Mac-Application.xcconfig */; buildSettings = { FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = "$(SRCROOT)/Source/swiftlint/Info.plist"; + INFOPLIST_FILE = "Source/swiftlint/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/. @executable_path/../Frameworks @executable_path/SwiftLintFramework.framework/Versions/Current/Frameworks @executable_path/SwiftLintFramework.framework/Versions/Current/Frameworks/SourceKittenFramework.framework/Versions/Current/Frameworks /Library/Frameworks /Library/Frameworks/SwiftLintFramework.framework/Versions/Current/Frameworks /Library/Frameworks/SwiftLintFramework.framework/Versions/Current/Frameworks/SourceKittenFramework.framework/Versions/Current/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Test; @@ -903,8 +923,9 @@ baseConfigurationReference = D0D1213419E878CC005E4BAA /* Mac-Application.xcconfig */; buildSettings = { FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = "$(SRCROOT)/Source/swiftlint/Info.plist"; + INFOPLIST_FILE = "Source/swiftlint/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/. @executable_path/../Frameworks @executable_path/SwiftLintFramework.framework/Versions/Current/Frameworks @executable_path/SwiftLintFramework.framework/Versions/Current/Frameworks/SourceKittenFramework.framework/Versions/Current/Frameworks /Library/Frameworks /Library/Frameworks/SwiftLintFramework.framework/Versions/Current/Frameworks /Library/Frameworks/SwiftLintFramework.framework/Versions/Current/Frameworks/SourceKittenFramework.framework/Versions/Current/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -914,8 +935,9 @@ baseConfigurationReference = D0D1213419E878CC005E4BAA /* Mac-Application.xcconfig */; buildSettings = { FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = "$(SRCROOT)/Source/swiftlint/Info.plist"; + INFOPLIST_FILE = "Source/swiftlint/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/. @executable_path/../Frameworks @executable_path/SwiftLintFramework.framework/Versions/Current/Frameworks @executable_path/SwiftLintFramework.framework/Versions/Current/Frameworks/SourceKittenFramework.framework/Versions/Current/Frameworks /Library/Frameworks /Library/Frameworks/SwiftLintFramework.framework/Versions/Current/Frameworks /Library/Frameworks/SwiftLintFramework.framework/Versions/Current/Frameworks/SourceKittenFramework.framework/Versions/Current/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Profile; diff --git a/SwiftLint.xcodeproj/xcshareddata/xcschemes/SwiftLintFramework.xcscheme b/SwiftLint.xcodeproj/xcshareddata/xcschemes/SwiftLintFramework.xcscheme index b1868e335..8a181e818 100644 --- a/SwiftLint.xcodeproj/xcshareddata/xcschemes/SwiftLintFramework.xcscheme +++ b/SwiftLint.xcodeproj/xcshareddata/xcschemes/SwiftLintFramework.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -62,15 +62,18 @@ ReferencedContainer = "container:SwiftLint.xcodeproj"> + + + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -48,16 +48,19 @@ ReferencedContainer = "container:SwiftLint.xcodeproj"> + + diff --git a/SwiftLint.xcworkspace/contents.xcworkspacedata b/SwiftLint.xcworkspace/contents.xcworkspacedata index 36f152236..84b11a5ed 100644 --- a/SwiftLint.xcworkspace/contents.xcworkspacedata +++ b/SwiftLint.xcworkspace/contents.xcworkspacedata @@ -14,9 +14,12 @@ location = "group:Carthage/Checkouts/Commandant/Commandant.xcodeproj"> + location = "group:Carthage/Checkouts/Commandant/Carthage/Checkouts/Result/Result.xcodeproj"> + +