Add SwiftLint
This commit is contained in:
parent
7e8d9c64e7
commit
637b91471d
|
@ -0,0 +1,12 @@
|
|||
disabled_rules:
|
||||
- force_try
|
||||
- identifier_name
|
||||
- trailing_whitespace
|
||||
|
||||
line_length: 300
|
||||
|
||||
nesting:
|
||||
type_level: 3
|
||||
|
||||
trailing_comma:
|
||||
mandatory_comma: true
|
10
README.md
10
README.md
|
@ -8,22 +8,22 @@ Type-safe URL routing for Swift.
|
|||
|
||||
```swift
|
||||
// Define routes
|
||||
struct UserIndex : Route {
|
||||
struct UserIndex: Route {
|
||||
let path = "/users"
|
||||
|
||||
func map(to url: URL, parameters: [String : String], queries: [String : String]) -> UIViewController {
|
||||
func map(to url: URL, parameters: [String: String], queries: [String: String]) -> UIViewController {
|
||||
return UserIndexViewController()
|
||||
}
|
||||
}
|
||||
|
||||
struct UserDetail : Route {
|
||||
struct UserDetail: Route {
|
||||
let path = "/users/{id}"
|
||||
|
||||
struct Parameters : Decodable {
|
||||
struct Parameters: Decodable {
|
||||
let id: Int
|
||||
}
|
||||
|
||||
func map(to url: URL, parameters: Parameters, queries: [String : String]) -> UIViewController {
|
||||
func map(to url: URL, parameters: Parameters, queries: [String: String]) -> UIViewController {
|
||||
return UserDetailViewController(id: parameters.id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -219,6 +219,7 @@
|
|||
430EC1DD20598F7600F84EA2 /* Frameworks */,
|
||||
430EC1DE20598F7600F84EA2 /* Headers */,
|
||||
430EC1DF20598F7600F84EA2 /* Resources */,
|
||||
437785B820EBDD810067EC31 /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -255,6 +256,7 @@
|
|||
430EC2062059919F00F84EA2 /* Frameworks */,
|
||||
430EC2072059919F00F84EA2 /* Headers */,
|
||||
430EC2082059919F00F84EA2 /* Resources */,
|
||||
437785B920EBDD8D0067EC31 /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -290,7 +292,7 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0920;
|
||||
LastUpgradeCheck = 0920;
|
||||
LastUpgradeCheck = 0940;
|
||||
ORGANIZATIONNAME = woxtu;
|
||||
TargetAttributes = {
|
||||
430EC1E020598F7600F84EA2 = {
|
||||
|
@ -362,6 +364,35 @@
|
|||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
437785B820EBDD810067EC31 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
|
||||
};
|
||||
437785B920EBDD8D0067EC31 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
430EC1DC20598F7600F84EA2 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
|
@ -599,6 +630,7 @@
|
|||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
|
@ -606,6 +638,7 @@
|
|||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
|
@ -659,6 +692,7 @@
|
|||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
|
@ -666,6 +700,7 @@
|
|||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
LastUpgradeVersion = "0940"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -26,7 +26,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
|
@ -56,7 +55,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0920"
|
||||
LastUpgradeVersion = "0940"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -26,7 +26,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
|
@ -56,7 +55,6 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
|
|
@ -10,9 +10,9 @@ import Foundation
|
|||
|
||||
struct AnyRoute<T> {
|
||||
let pattern: Pattern
|
||||
let map: (URL, [String : String], [String : String]) -> T?
|
||||
let map: (URL, [String: String], [String: String]) -> T?
|
||||
|
||||
init<R>(_ route: R) where R : Route, R.Response == T {
|
||||
init<R>(_ route: R) where R: Route, R.Response == T {
|
||||
self.pattern = Pattern(string: route.path)
|
||||
|
||||
self.map = { url, parameters, queries in
|
||||
|
|
|
@ -10,6 +10,6 @@ import Foundation
|
|||
|
||||
extension NSRegularExpression {
|
||||
func stringByReplacingMatches(in string: String, options: NSRegularExpression.MatchingOptions = [], withTemplate templ: String) -> String {
|
||||
return self.stringByReplacingMatches(in: string, options: options, range: NSMakeRange(0, string.count), withTemplate: templ)
|
||||
return self.stringByReplacingMatches(in: string, options: options, range: NSRange(location: 0, length: string.count), withTemplate: templ)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ open class Navigator {
|
|||
return UIApplication.shared.keyWindow?.rootViewController
|
||||
}
|
||||
|
||||
open static func append<R>(route: R) where R : Route, R.Response == UIViewController {
|
||||
open static func append<R>(route: R) where R: Route, R.Response == UIViewController {
|
||||
self.router.append(route: route)
|
||||
}
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ struct Pattern {
|
|||
.map(Component.init)
|
||||
}
|
||||
|
||||
func match(url: URL) -> [String : String]? {
|
||||
let pathComponents = [url.host].flatMap { $0 } + url.pathComponents.dropFirst() // drop "/"
|
||||
func match(url: URL) -> [String: String]? {
|
||||
let pathComponents = [url.host].compactMap { $0 } + url.pathComponents.dropFirst() // drop "/"
|
||||
|
||||
if self.scheme == url.scheme && self.pathComponents == pathComponents.map(Component.init) {
|
||||
return zip(self.pathComponents, pathComponents).reduce(into: [:]) { result, component in
|
||||
|
@ -54,8 +54,8 @@ struct Pattern {
|
|||
}
|
||||
}
|
||||
|
||||
extension Pattern.Component : Equatable {
|
||||
static func ==(lhs: Pattern.Component, rhs: Pattern.Component) -> Bool {
|
||||
extension Pattern.Component: Equatable {
|
||||
static func == (lhs: Pattern.Component, rhs: Pattern.Component) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case let (.constant(lhs), .constant(rhs)): return lhs == rhs
|
||||
case let (.variable(lhs), .variable(rhs)): return lhs == rhs
|
||||
|
|
|
@ -9,20 +9,20 @@
|
|||
import Foundation
|
||||
|
||||
class PayloadDecoder {
|
||||
func decode<T>(_ type: T.Type = T.self, from data: [String : String]) throws -> T where T : Decodable {
|
||||
func decode<T>(_ type: T.Type = T.self, from data: [String: String]) throws -> T where T: Decodable {
|
||||
return try T(from: InnerDecoder(data: data))
|
||||
}
|
||||
|
||||
class InnerDecoder : Decoder {
|
||||
let data: [String : String]
|
||||
class InnerDecoder: Decoder {
|
||||
let data: [String: String]
|
||||
var codingPath = [CodingKey]()
|
||||
let userInfo = [CodingUserInfoKey : Any]()
|
||||
let userInfo = [CodingUserInfoKey: Any]()
|
||||
|
||||
init(data: [String : String]) {
|
||||
init(data: [String: String]) {
|
||||
self.data = data
|
||||
}
|
||||
|
||||
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey {
|
||||
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key: CodingKey {
|
||||
return KeyedDecodingContainer(InnerKeyedDecodingContainer(referencing: self))
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ class PayloadDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
class InnerKeyedDecodingContainer<Key> : KeyedDecodingContainerProtocol where Key : CodingKey {
|
||||
class InnerKeyedDecodingContainer<Key>: KeyedDecodingContainerProtocol where Key: CodingKey {
|
||||
let decoder: InnerDecoder
|
||||
|
||||
var codingPath: [CodingKey] {
|
||||
|
@ -43,7 +43,7 @@ class PayloadDecoder {
|
|||
}
|
||||
|
||||
var allKeys: [Key] {
|
||||
return self.decoder.data.keys.flatMap(Key.init)
|
||||
return self.decoder.data.keys.compactMap(Key.init)
|
||||
}
|
||||
|
||||
init(referencing decoder: InnerDecoder) {
|
||||
|
@ -58,7 +58,7 @@ class PayloadDecoder {
|
|||
return self.decoder.data[key.stringValue] == nil
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable & LosslessStringConvertible {
|
||||
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T: Decodable & LosslessStringConvertible {
|
||||
guard let rawValue = self.decoder.data[key.stringValue] else {
|
||||
throw DecodingError.valueNotFound(type, .init(codingPath: self.codingPath, debugDescription: "No value associated with key '\(key)'."))
|
||||
}
|
||||
|
@ -70,13 +70,13 @@ class PayloadDecoder {
|
|||
return value
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable {
|
||||
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T: Decodable {
|
||||
self.decoder.codingPath.append(key)
|
||||
defer { self.decoder.codingPath.removeLast() }
|
||||
return try T(from: self.decoder)
|
||||
}
|
||||
|
||||
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
|
||||
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey: CodingKey {
|
||||
fatalError("It should not be called")
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ class PayloadDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
class InnerSingleValueDecodingContainer : SingleValueDecodingContainer {
|
||||
class InnerSingleValueDecodingContainer: SingleValueDecodingContainer {
|
||||
let decoder: InnerDecoder
|
||||
|
||||
var codingPath: [CodingKey] {
|
||||
|
@ -112,7 +112,7 @@ class PayloadDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type) throws -> T where T : Decodable & LosslessStringConvertible {
|
||||
func decode<T>(_ type: T.Type) throws -> T where T: Decodable & LosslessStringConvertible {
|
||||
guard let key = self.codingPath.last else {
|
||||
fatalError("It should not be called")
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ class PayloadDecoder {
|
|||
return value
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
|
||||
func decode<T>(_ type: T.Type) throws -> T where T: Decodable {
|
||||
return try T(from: self.decoder)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ import Foundation
|
|||
|
||||
public protocol Route {
|
||||
associatedtype Response
|
||||
associatedtype Parameters : Decodable = [String : String]
|
||||
associatedtype Queries : Decodable = [String : String]
|
||||
associatedtype Parameters: Decodable = [String: String]
|
||||
associatedtype Queries: Decodable = [String: String]
|
||||
|
||||
var path: String { get }
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ open class Router<T> {
|
|||
|
||||
}
|
||||
|
||||
open func append<R>(route: R) where R : Route, R.Response == T {
|
||||
open func append<R>(route: R) where R: Route, R.Response == T {
|
||||
self.routes.append(AnyRoute(route))
|
||||
}
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@ class AnyRouteTests: XCTestCase {
|
|||
struct TestRoute: Route {
|
||||
let path = "/"
|
||||
|
||||
func map(to url: URL, parameters: [String : String], queries: [String : String]) -> TestResponse {
|
||||
func map(to url: URL, parameters: [String: String], queries: [String: String]) -> TestResponse {
|
||||
return TestResponse(x1: parameters["x", default: ""], x2: queries["x", default: ""])
|
||||
}
|
||||
}
|
||||
|
||||
let route = AnyRoute<TestResponse>(TestRoute())
|
||||
let response = route.map(URL(string: "/")!, ["x" : "foo"], ["x" : "bar"])
|
||||
let response = route.map(URL(string: "/")!, ["x": "foo"], ["x": "bar"])
|
||||
XCTAssertEqual(response?.x1, "foo")
|
||||
XCTAssertEqual(response?.x2, "bar")
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ class AnyRouteTests: XCTestCase {
|
|||
}
|
||||
|
||||
let route = AnyRoute<TestResponse>(TestRoute())
|
||||
let response = route.map(URL(string: "/")!, ["x" : "foo"], ["x" : "bar"])
|
||||
let response = route.map(URL(string: "/")!, ["x": "foo"], ["x": "bar"])
|
||||
XCTAssertEqual(response?.x1, "foo")
|
||||
XCTAssertEqual(response?.x2, "bar")
|
||||
}
|
||||
|
|
|
@ -24,6 +24,6 @@ class PatternTests: XCTestCase {
|
|||
|
||||
func testPatternMatch() {
|
||||
XCTAssertNil(Pattern(string: "/x1/{x2}").match(url: URL(string: "/")!))
|
||||
XCTAssertEqual(Pattern(string: "/x1/{x2}").match(url: URL(string: "/x1/x2")!)!, ["x2" : "x2"])
|
||||
XCTAssertEqual(Pattern(string: "/x1/{x2}").match(url: URL(string: "/x1/x2")!)!, ["x2": "x2"])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,45 +11,45 @@ import XCTest
|
|||
|
||||
class PayloadDecoderTests: XCTestCase {
|
||||
func testDecodeString() {
|
||||
struct TestStruct : Decodable {
|
||||
struct TestStruct: Decodable {
|
||||
let x: String
|
||||
}
|
||||
|
||||
let payload = ["x" : "x"]
|
||||
let payload = ["x": "x"]
|
||||
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
||||
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, "x")
|
||||
}
|
||||
|
||||
func testDecodeInt() {
|
||||
struct TestStruct : Decodable {
|
||||
struct TestStruct: Decodable {
|
||||
let x: Int
|
||||
}
|
||||
|
||||
let payload = ["x" : "42"]
|
||||
let payload = ["x": "42"]
|
||||
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
||||
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, 42)
|
||||
}
|
||||
|
||||
func testDecodeOptional() {
|
||||
struct TestStruct : Decodable {
|
||||
struct TestStruct: Decodable {
|
||||
let x: String?
|
||||
}
|
||||
|
||||
let payload = [String : String]()
|
||||
let payload = [String: String]()
|
||||
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
||||
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, nil)
|
||||
}
|
||||
|
||||
func testDecodeEnum() {
|
||||
enum TestEnum : String, Decodable {
|
||||
enum TestEnum: String, Decodable {
|
||||
case type
|
||||
}
|
||||
|
||||
struct TestStruct : Decodable {
|
||||
struct TestStruct: Decodable {
|
||||
let x: TestEnum
|
||||
}
|
||||
|
||||
let payload = ["x" : "type"]
|
||||
let payload = ["x": "type"]
|
||||
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
||||
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, .type)
|
||||
}
|
||||
|
|
|
@ -16,14 +16,14 @@ class RouterTests: XCTestCase {
|
|||
let q: String?
|
||||
}
|
||||
|
||||
struct TestRoute : Route {
|
||||
struct TestRoute: Route {
|
||||
let path = "/{p}"
|
||||
|
||||
struct Parameters : Decodable {
|
||||
struct Parameters: Decodable {
|
||||
let p: String
|
||||
}
|
||||
|
||||
struct Queries : Decodable {
|
||||
struct Queries: Decodable {
|
||||
let q: String?
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue