├── .gitignore ├── .swift-version ├── GitDiffSwift.podspec ├── LICENSE.md ├── Package.swift ├── README.md ├── Sources ├── Extensions │ ├── Collection+Extensions.swift │ └── String+Extensions.swift ├── Models │ ├── GitDiff.swift │ ├── GitDiffLine.swift │ ├── GitHunk.swift │ └── GitIndex.swift └── Parser │ ├── DiffParser.swift │ └── LineState.swift └── Tests └── Resources ├── deleted_file_mode.diff ├── multi_file_change.diff ├── new_file_mode.diff ├── no_new_line.diff └── renamed_file_mode.diff /.gitignore: -------------------------------------------------------------------------------- 1 | .build 2 | /.previous-build 3 | xcuserdata 4 | .DS_Store 5 | *~ 6 | \#* 7 | .\#* 8 | *.xcscmblueprint 9 | /default.profraw 10 | *.xcodeproj 11 | Utilities/Docker/*.tar.gz 12 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /GitDiffSwift.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'GitDiffSwift' 3 | s.version = '0.0.1' 4 | s.summary = 'A git diff parser written in Swift.' 5 | s.homepage = 'https://github.com/SD10/GitDiffSwift' 6 | s.license = { :type => 'MIT', :file => 'LICENSE.md' } 7 | s.author = { 'Steven Deutsch' => 'stevensdeutsch@yahoo.com' } 8 | s.social_media_url = 'https://twitter.com/_SD10_' 9 | s.source = { :git => "https://github.com/SD10/GitDiffSwift.git", :tag => s.version } 10 | s.source_files = 'Sources/**/*.swift' 11 | s.platform = :osx, '10.9' 12 | end 13 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Steven Deutsch 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "GitDiffSwift", 8 | products: [ 9 | .library(name: "GitDiffSwift", targets: ["GitDiffSwift"]) 10 | ], 11 | dependencies: [ ], 12 | targets: [ 13 | .target(name: "GitDiffSwift", dependencies: [], path: "Sources") 14 | ] 15 | ) 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitDiffSwift 2 | 3 | GitDiffSwift is a git diff parser written in Swift. 4 | 5 | ## Features 6 | - [ ] Diff parsing 7 | - [ ] Apply a diff to a file 8 | - [ ] Outputs diff as JSON 9 | - [ ] Outputs original diff from Swift model 10 | 11 | ## Installation 12 | 13 | ### [CocoaPods](https://cocoapods.org/) 14 | ````Ruby 15 | pod 'GitDiffSwift' 16 | ```` 17 | 18 | ### Carthage 19 | Make the following entry in your Cartfile: 20 | ```` 21 | github "SD10/GitDiffSwift" 22 | ```` 23 | 24 | ### Swift Package Manager 25 | To integrate using Apple's Swift package manager, add the following as a dependency to your `Package.swift`: 26 | ````swift 27 | .package(url: "https://github.com/SD10/GitDiffSwift.git", .upToNextMajor(from: "0.0.1")) 28 | ```` 29 | 30 | ## Contributing 31 | Pull requests welcomed. This repo is being developed at the speed of snail. 32 | 33 | ## License 34 | GitDiffSwift is released under the [MIT License](https://github.com/sd10/GitDiffSwift/blob/master/LICENSE.md) 35 | -------------------------------------------------------------------------------- /Sources/Extensions/Collection+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Collection+Extensions.swift 3 | // GitDiffSwiftPackageDescription 4 | // 5 | // Created by Steven Deutsch on 4/2/18. 6 | // 7 | 8 | import Foundation 9 | 10 | extension Collection { 11 | 12 | internal func indices(where condition: (Element) throws -> Bool) rethrows -> [Int] { 13 | var indices: [Int] = [] 14 | for (index, value) in enumerated() { 15 | if try condition(value) { indices.append(index) } 16 | } 17 | return indices 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Extensions/String+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Extensions.swift 3 | // GitDiffSwiftPackageDescription 4 | // 5 | // Created by Steven Deutsch on 4/2/18. 6 | // 7 | 8 | import Foundation 9 | 10 | extension String { 11 | 12 | internal func removingPrefix(_ prefix: String) -> String { 13 | guard hasPrefix(prefix) else { return self } 14 | return String(dropFirst(prefix.count)) 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Models/GitDiff.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GitDiff.swift 3 | // GitDiffSwift 4 | // 5 | // Created by Steven Deutsch on 4/1/18. 6 | // Copyright © 2018 GitDiffSwift. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct GitDiff: Codable { 12 | 13 | public var previousFilePath: String 14 | 15 | public var updatedFilePath: String 16 | 17 | public var index: GitIndex 18 | 19 | public var hunks: [GitHunk] 20 | 21 | internal var description: String { 22 | let prefix = "diff --git" 23 | let fileA = "a/" + previousFilePath 24 | let fileB = "b/" + updatedFilePath 25 | let diffHeader = prefix + " " + fileA + " " + fileB 26 | let old = "--- " + fileA 27 | let new = "+++ " + fileB 28 | let headerContent = diffHeader + "\n" + index.description + "\n" + old + "\n" + new 29 | var body = headerContent 30 | for hunk in hunks { 31 | body += "\n" 32 | body += hunk.description 33 | } 34 | return body 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/Models/GitDiffLine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GitDiffLine.swift 3 | // GitDiffSwift 4 | // 5 | // Created by Steven Deutsch on 4/1/18. 6 | // Copyright © 2018 GitDiffSwift. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum LineType: String, Codable { 12 | case unchanged 13 | case addition 14 | case deletion 15 | } 16 | 17 | public struct GitDiffLine: Codable { 18 | 19 | public var type: String 20 | 21 | public var text: String 22 | 23 | public var oldLine: Int 24 | 25 | public var newLine: Int 26 | 27 | public var noNewLine = false 28 | 29 | internal var description: String { 30 | if noNewLine { 31 | return text + "\n" + "\\ No newline at end of file" 32 | } 33 | return text 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Sources/Models/GitHunk.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GitHunk.swift 3 | // GitDiffSwift 4 | // 5 | // Created by Steven Deutsch on 4/1/18. 6 | // Copyright © 2018 GitDiffSwift. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct GitHunk: Codable { 12 | 13 | private var text: String 14 | 15 | public var oldLineStart = 0 16 | 17 | public var oldLineSpan = 0 18 | 19 | public var newLineStart = 0 20 | 21 | public var newLineSpan = 0 22 | 23 | public var changes: [GitDiffLine] = [] 24 | 25 | internal var description: String { 26 | let header = "@@ -\(oldLineStart),\(oldLineSpan) +\(newLineStart),\(newLineSpan) @@\(text)\n" 27 | return changes.reduce(into: header) { 28 | $0 += ($1.description + "\n") 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Models/GitIndex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GitIndex.swift 3 | // GitDiffSwift 4 | // 5 | // Created by Steven Deutsch on 4/1/18. 6 | // Copyright © 2018 GitDiffSwift. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct GitIndex: Codable { 12 | 13 | public let id: String 14 | 15 | public let commitHead: String 16 | 17 | public let commitTail: String 18 | 19 | internal var description: String { 20 | return "index " + commitHead + ".." + commitTail + " " + id 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Parser/DiffParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DiffParser.swift 3 | // GitDiffSwift 4 | // 5 | // Created by Steven Deutsch on 2/7/18. 6 | // Copyright © 2018 GitDiffSwift. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class DiffParser { 12 | 13 | internal enum GitPrefix { 14 | internal static let diffHeader = "diff --git" 15 | internal static let deletedFile = "+++ /dev/null" 16 | internal static let addedFile = "--- /dev/null" 17 | internal static let previousFile = "--- a/" 18 | internal static let updatedFile = "+++ b/" 19 | internal static let hunk = "@@" 20 | internal static let newLine = "\\ No newline at end of file" 21 | } 22 | 23 | internal let input: String 24 | internal var state: LineState 25 | 26 | public init(input: String) { 27 | self.input = input 28 | self.state = LineState() 29 | } 30 | 31 | public func parseDiffedFiles() -> [GitDiff] { 32 | 33 | let inputLines = input.split(separator: "\n", maxSplits: .max, omittingEmptySubsequences: false) 34 | 35 | var diffs: [GitDiff] = [] 36 | 37 | var diffInfo: [String: Any?] = [:] 38 | var hunks: [[String: Any?]] = [] 39 | var changes: [[String: Any]] = [] 40 | 41 | let createDiff = { 42 | diffInfo["hunks"] = hunks 43 | 44 | let data = try! JSONSerialization.data(withJSONObject: diffInfo, options: []) 45 | let decoder = JSONDecoder() 46 | 47 | do { 48 | let diff = try decoder.decode(GitDiff.self, from: data) 49 | diffs.append(diff) 50 | hunks.removeAll() 51 | changes.removeAll() 52 | diffInfo.removeAll() 53 | } catch { 54 | print(error.localizedDescription) 55 | } 56 | } 57 | 58 | let createHunk = { 59 | var lastHunk = hunks.removeLast() 60 | lastHunk["changes"] = changes 61 | hunks.append(lastHunk) 62 | changes.removeAll() 63 | } 64 | 65 | for line in inputLines { 66 | let line = String(line) 67 | switch true { 68 | case line.hasPrefix(GitPrefix.diffHeader): 69 | if !diffInfo.isEmpty { 70 | if !hunks.isEmpty { 71 | createHunk() 72 | } 73 | createDiff() 74 | } 75 | case line.hasPrefix(GitPrefix.previousFile): 76 | let previousFilePath = line.removingPrefix(GitPrefix.previousFile) 77 | diffInfo["previousFilePath"] = previousFilePath 78 | case line.hasPrefix(GitPrefix.updatedFile): 79 | let updatedFilePath = line.removingPrefix(GitPrefix.updatedFile) 80 | diffInfo["updatedFilePath"] = updatedFilePath 81 | case line.hasPrefix(GitPrefix.hunk): 82 | if !hunks.isEmpty { 83 | createHunk() 84 | } 85 | let hunkHeader = parseHunkHeader(line) 86 | hunks.append(hunkHeader) 87 | case line.hasPrefix("index"): 88 | let indexInfo = parseIndexInfo(line) 89 | diffInfo["index"] = indexInfo 90 | case line.hasPrefix(GitPrefix.newLine): 91 | if !changes.isEmpty { 92 | var lastChange = changes.removeLast() 93 | lastChange["noNewLine"] = true 94 | changes.append(lastChange) 95 | } 96 | default: 97 | let diffLine = parseDiffLine(line) 98 | changes.append(diffLine) 99 | } 100 | } 101 | 102 | createHunk() 103 | 104 | createDiff() 105 | 106 | return diffs 107 | } 108 | 109 | // MARK: - Helpers 110 | 111 | internal func diffType(for line: String) -> LineType { 112 | switch true { 113 | case line.hasPrefix("+"): 114 | return .addition 115 | case line.hasPrefix("-"): 116 | return .deletion 117 | default: 118 | return .unchanged 119 | } 120 | } 121 | 122 | internal func parseIndexInfo(_ input: String) -> [String: String] { 123 | let trimmed = input.removingPrefix("index ") 124 | let components = trimmed.components(separatedBy: " ") 125 | let id = components.last! 126 | let commits = components.first!.components(separatedBy: "..") 127 | var indexInfo: [String: String] = [:] 128 | indexInfo["id"] = id 129 | indexInfo["commitHead"] = commits[0] 130 | indexInfo["commitTail"] = commits[1] 131 | return indexInfo 132 | } 133 | 134 | internal func parseHunkHeader(_ input: String) -> [String: Any] { 135 | 136 | let indices = input.indices(where: { $0 == "@" }) 137 | let hunkEndIndex = input.index(input.startIndex, offsetBy: indices[3] + 1) 138 | let hunkData = input[input.startIndex...hunkEndIndex] 139 | let remainingText = String(input[hunkEndIndex.. [String: Any] { 158 | let type = diffType(for: line) 159 | 160 | state.updateForLine(type: type) 161 | 162 | let oldLine = state.currentOldLine 163 | let newLine = state.currentNewLine 164 | 165 | var lineInfo: [String: Any] = [:] 166 | lineInfo["type"] = type.rawValue 167 | lineInfo["text"] = line 168 | lineInfo["newLine"] = newLine 169 | lineInfo["oldLine"] = oldLine 170 | 171 | return lineInfo 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /Sources/Parser/LineState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LineState.swift 3 | // GitDiffSwift 4 | // 5 | // Created by Steven Deutsch on 4/2/18. 6 | // 7 | 8 | import Foundation 9 | 10 | internal struct LineState { 11 | internal var isFirstLine = true 12 | internal var currentOldLine = 0 13 | internal var currentNewLine = 0 14 | 15 | internal mutating func updateForLine(type: LineType) { 16 | guard !isFirstLine else { 17 | isFirstLine = false 18 | return 19 | } 20 | switch type { 21 | case .unchanged: 22 | currentOldLine += 1 23 | currentNewLine += 1 24 | case .addition: 25 | currentNewLine += 1 26 | case .deletion: 27 | currentOldLine += 1 28 | } 29 | } 30 | 31 | internal mutating func reset(newLineStart: Int, oldLineStart: Int) { 32 | self.isFirstLine = true 33 | self.currentNewLine = newLineStart 34 | self.currentOldLine = oldLineStart 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/Resources/deleted_file_mode.diff: -------------------------------------------------------------------------------- 1 | diff --git a/Sources/Layout/MessagesCollectionViewFlowLayout+Avatar.swift b/Sources/Layout/MessagesCollectionViewFlowLayout+Avatar.swift 2 | deleted file mode 100644 3 | index c9299456..00000000 4 | --- a/Sources/Layout/MessagesCollectionViewFlowLayout+Avatar.swift 5 | +++ /dev/null 6 | @@ -1,85 +0,0 @@ 7 | -/* 8 | - MIT License 9 | - 10 | - Copyright (c) 2017-2018 MessageKit 11 | - 12 | - Permission is hereby granted, free of charge, to any person obtaining a copy 13 | - of this software and associated documentation files (the "Software"), to deal 14 | - in the Software without restriction, including without limitation the rights 15 | - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | - copies of the Software, and to permit persons to whom the Software is 17 | - furnished to do so, subject to the following conditions: 18 | - 19 | - The above copyright notice and this permission notice shall be included in all 20 | - copies or substantial portions of the Software. 21 | - 22 | - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | - SOFTWARE. 29 | - */ 30 | - 31 | -import Foundation 32 | - 33 | -// MARK: - Open 34 | - 35 | -extension MessagesCollectionViewFlowLayout { 36 | - 37 | - /// Returns the `AvatarPosition` for the `MessageType` at a given `IndexPath`. 38 | - /// 39 | - /// - Parameters: 40 | - /// - message: The `MessageType` for the given `IndexPath`. 41 | - /// - indexPath: The `IndexPath` for the given `MessageType`. 42 | - /// 43 | - /// - Note: The default implementation of this method retrieves its value from 44 | - /// `avatarPosition(for:at:in)` in `MessagesLayoutDelegate`. 45 | - open func avatarPosition(for message: MessageType, at indexPath: IndexPath) -> AvatarPosition { 46 | - var position = messagesLayoutDelegate.avatarPosition(for: message, at: indexPath, in: messagesCollectionView) 47 | - 48 | - switch position.horizontal { 49 | - case .cellTrailing, .cellLeading: 50 | - break 51 | - case .natural: 52 | - position.horizontal = messagesDataSource.isFromCurrentSender(message: message) ? .cellTrailing : .cellLeading 53 | - } 54 | - return position 55 | - } 56 | - 57 | - /// Returns the `AvatarSize` for the `MessageType` at a given `IndexPath`. 58 | - /// 59 | - /// - Parameters: 60 | - /// - message: The `MessageType` for the given `IndexPath`. 61 | - /// - indexPath: The `IndexPath` for the given `MessageType`. 62 | - /// - Note: The default implementation of this method retrieves its value from 63 | - /// `avatarSize(for:at:in)` in `MessagesLayoutDelegate`. 64 | - open func avatarSize(for message: MessageType, at indexPath: IndexPath) -> CGSize { 65 | - return messagesLayoutDelegate.avatarSize(for: message, at: indexPath, in: messagesCollectionView) 66 | - } 67 | -} 68 | - 69 | -// MARK: - Internal 70 | - 71 | -extension MessagesCollectionViewFlowLayout { 72 | - 73 | - internal func _avatarPosition(for message: MessageType, at indexPath: IndexPath) -> AvatarPosition { 74 | - 75 | - guard let cachedPosition = currentLayoutContext.avatarPosition else { 76 | - let position = avatarPosition(for: message, at: indexPath) 77 | - currentLayoutContext.avatarPosition = position 78 | - return position 79 | - } 80 | - return cachedPosition 81 | - } 82 | - 83 | - internal func _avatarSize(for message: MessageType, at indexPath: IndexPath) -> CGSize { 84 | - guard let cachedSize = currentLayoutContext.avatarSize else { 85 | - let size = avatarSize(for: message, at: indexPath) 86 | - currentLayoutContext.avatarSize = size 87 | - return size 88 | - } 89 | - return cachedSize 90 | - } 91 | -} 92 | -------------------------------------------------------------------------------- /Tests/Resources/multi_file_change.diff: -------------------------------------------------------------------------------- 1 | diff --git a/Cartfile.resolved b/Cartfile.resolved 2 | index b46a8eb0..fb60c25e 100644 3 | --- a/Cartfile.resolved 4 | +++ b/Cartfile.resolved 5 | @@ -1,4 +1,4 @@ 6 | -github "Alamofire/Alamofire" "4.6.0" 7 | +github "Alamofire/Alamofire" "4.7.0" 8 | github "AliSoftware/OHHTTPStubs" "f90c2bb0fb882e43761ab963ca8869d349d2c6e3" 9 | github "Quick/Nimble" "v7.0.3" 10 | github "Quick/Quick" "v1.2.0" 11 | diff --git a/Moya.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Moya.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist 12 | new file mode 100644 13 | index 00000000..18d98100 14 | --- /dev/null 15 | +++ b/Moya.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist 16 | @@ -0,0 +1,8 @@ 17 | + 18 | + 19 | + 20 | + 21 | + IDEDidComputeMac32BitWarning 22 | + 23 | + 24 | + 25 | diff --git a/Package.resolved b/Package.resolved 26 | index 2af9ba29..3f38b502 100644 27 | --- a/Package.resolved 28 | +++ b/Package.resolved 29 | @@ -6,8 +6,26 @@ 30 | "repositoryURL": "https://github.com/Alamofire/Alamofire.git", 31 | "state": { 32 | "branch": null, 33 | - "revision": "7fe7b918b746fbb4b7a7c2146bef7a88c7ddc54e", 34 | - "version": "4.5.0" 35 | + "revision": "bfb9f132cdfa1033bea847e4cf9cfde4fee254e3", 36 | + "version": "4.7.0" 37 | + } 38 | + }, 39 | + { 40 | + "package": "Nimble", 41 | + "repositoryURL": "https://github.com/Quick/Nimble.git", 42 | + "state": { 43 | + "branch": null, 44 | + "revision": "22800b0954c89344bb8c87f8ab93378076716fb7", 45 | + "version": "7.0.3" 46 | + } 47 | + }, 48 | + { 49 | + "package": "Quick", 50 | + "repositoryURL": "https://github.com/Quick/Quick.git", 51 | + "state": { 52 | + "branch": null, 53 | + "revision": "0ff81f2c665b4381f526bd656f8708dd52a9ea2f", 54 | + "version": "1.2.0" 55 | } 56 | }, 57 | { 58 | @@ -15,8 +33,8 @@ 59 | "repositoryURL": "https://github.com/ReactiveCocoa/ReactiveSwift.git", 60 | "state": { 61 | "branch": null, 62 | - "revision": "2ec944c43ef9cf6b1380629e3ea483f62a7afaef", 63 | - "version": "3.0.0" 64 | + "revision": "46fb4d4a8285286e54929add1d12f384675895c6", 65 | + "version": "3.1.0" 66 | } 67 | }, 68 | { 69 | @@ -24,8 +42,8 @@ 70 | "repositoryURL": "https://github.com/antitypical/Result.git", 71 | "state": { 72 | "branch": null, 73 | - "revision": "c8446185238659a2b27c0261f64ff1254291d07d", 74 | - "version": "3.2.3" 75 | + "revision": "7477584259bfce2560a19e06ad9f71db441fff11", 76 | + "version": "3.2.4" 77 | } 78 | }, 79 | { 80 | @@ -33,8 +51,8 @@ 81 | "repositoryURL": "https://github.com/ReactiveX/RxSwift.git", 82 | "state": { 83 | "branch": null, 84 | - "revision": "49eba516f11dbd856f7856e293422f561c854433", 85 | - "version": "4.1.0" 86 | + "revision": "3e848781c7756accced855a6317a4c2ff5e8588b", 87 | + "version": "4.1.2" 88 | } 89 | } 90 | ] 91 | -------------------------------------------------------------------------------- /Tests/Resources/new_file_mode.diff: -------------------------------------------------------------------------------- 1 | diff --git a/GitDiffSwift/Models/GitDiffLine.swift b/GitDiffSwift/Models/GitDiffLine.swift 2 | new file mode 100644 3 | index 0000000..c6c7eb0 4 | --- /dev/null 5 | +++ b/GitDiffSwift/Models/GitDiffLine.swift 6 | @@ -0,0 +1,31 @@ 7 | +// 8 | +// GitDiffLine.swift 9 | +// GitDiffSwift 10 | +// 11 | +// Created by Steven Deutsch on 4/1/18. 12 | +// Copyright © 2018 GitDiffSwift. All rights reserved. 13 | +// 14 | + 15 | +import Foundation 16 | + 17 | +public enum LineType: String, Codable { 18 | + case unchanged 19 | + case addition 20 | + case deletion 21 | +} 22 | + 23 | +public struct GitDiffLine: Codable { 24 | + 25 | + public var type: String 26 | + 27 | + public var text: String 28 | + 29 | + public var oldLine: Int? 30 | + 31 | + public var newLine: Int? 32 | + 33 | + internal var description: String { 34 | + return text 35 | + } 36 | + 37 | +} 38 | -------------------------------------------------------------------------------- /Tests/Resources/no_new_line.diff: -------------------------------------------------------------------------------- 1 | diff --git a/.swiftlint.yml b/.swiftlint.yml 2 | index 0189737e..8bf8a3da 100644 3 | --- a/.swiftlint.yml 4 | +++ b/.swiftlint.yml 5 | @@ -11,6 +11,10 @@ custom_rules: 6 | regex: "override (open|public|private|internal|fileprivate)" # matching pattern 7 | message: "Use like open override or public override instead" # violation message. optional. 8 | severity: warning # violation severity. optional. 9 | +opt_in_rules: 10 | + - explicit_acl 11 | + - explicit_top_level_acl 12 | +explicit_acl: error 13 | +explicit_top_level_acl: error 14 | included: 15 | - - Sources 16 | - - Tests 17 | \ No newline at end of file 18 | + - Sources 19 | \ No newline at end of file 20 | -------------------------------------------------------------------------------- /Tests/Resources/renamed_file_mode.diff: -------------------------------------------------------------------------------- 1 | diff --git a/Sources/Layout/MessageCellLayoutContext.swift b/Sources/Protocols/MediaItem.swift 2 | similarity index 63% 3 | rename from Sources/Layout/MessageCellLayoutContext.swift 4 | rename to Sources/Protocols/MediaItem.swift 5 | index 693c976f..10acfe12 100644 6 | --- a/Sources/Layout/MessageCellLayoutContext.swift 7 | +++ b/Sources/Protocols/MediaItem.swift 8 | @@ -24,25 +24,19 @@ 9 | 10 | import Foundation 11 | 12 | -/// An internal type used to store the attributes used to calculate 13 | -/// the size of a `MessageCollectionViewCell`. 14 | -final class MessageCellLayoutContext { 15 | +/// A protocol used to represent the data for a media message. 16 | +public protocol MediaItem { 17 | 18 | - var itemHeight: CGFloat? 19 | + /// The url where the media is located. 20 | + var url: URL? { get set } 21 | 22 | - var avatarSize: CGSize? 23 | - var avatarPosition: AvatarPosition? 24 | + /// The image. 25 | + var image: UIImage? { get set } 26 | 27 | - var messageContainerSize: CGSize? 28 | - var messageContainerMaxWidth: CGFloat? 29 | - var messageContainerPadding: UIEdgeInsets? 30 | - var messageLabelInsets: UIEdgeInsets? 31 | + /// A placeholder image for when the image is obtained asychronously. 32 | + var placeholderImage: UIImage { get set } 33 | 34 | - var bottomLabelAlignment: LabelAlignment? 35 | - var bottomLabelSize: CGSize? 36 | - var bottomLabelMaxWidth: CGFloat? 37 | + /// The size of the media item. 38 | + var size: CGSize { get set } 39 | 40 | - var topLabelAlignment: LabelAlignment? 41 | - var topLabelSize: CGSize? 42 | - var topLabelMaxWidth: CGFloat? 43 | } 44 | --------------------------------------------------------------------------------