feature/http_status_codes_for_error_responses #5

Merged
ivan.smolin merged 7 commits from feature/http_status_codes_for_error_responses into master 2023-05-24 10:04:08 +03:00
57 changed files with 324 additions and 164 deletions

View File

@ -1,5 +1,10 @@
# Changelog
### 1.44.0
- **Added**: HTTP status codes to `EndpointErrorResult.apiError` responses
- **Added**: SwiftLint pre-build SPM step to TINetworking module
### 1.43.1
- **Fixed**: build scripts submodule url

View File

@ -1,4 +1,7 @@
// swift-tools-version:5.7
#if canImport(PackageDescription)
import PackageDescription
let package = Package(
@ -71,7 +74,12 @@ let package = Package(
.target(name: "TIDeveloperUtils", dependencies: ["TISwiftUtils", "TIUIKitCore", "TIUIElements"], path: "TIDeveloperUtils/Sources"),
// MARK: - Networking
.target(name: "TINetworking", dependencies: ["TIFoundationUtils", "Alamofire"], path: "TINetworking/Sources"),
.target(name: "TINetworking",
dependencies: ["TIFoundationUtils", "Alamofire"],
path: "TINetworking/Sources",
plugins: [.plugin(name: "TISwiftLintPlugin")]),
.target(name: "TIMoyaNetworking", dependencies: ["TINetworking", "TIFoundationUtils", "Moya"], path: "TIMoyaNetworking"),
.target(name: "TINetworkingCache", dependencies: ["TIFoundationUtils", "TINetworking", "Cache"], path: "TINetworkingCache/Sources"),
@ -89,7 +97,15 @@ let package = Package(
dependencies: [.product(name: "Antlr4", package: "antlr4")],
path: "TITextProcessing/Sources",
exclude: ["TITextProcessing.app"]),
.binaryTarget(name: "SwiftLintBinary",
url: "https://github.com/realm/SwiftLint/releases/download/0.52.2/SwiftLintBinary-macos.artifactbundle.zip",
checksum: "89651e1c87fb62faf076ef785a5b1af7f43570b2b74c6773526e0d5114e0578e"),
.plugin(name: "TISwiftLintPlugin",
capability: .buildTool(),
dependencies: ["SwiftLintBinary"]),
// MARK: - Tests
.testTarget(
@ -102,3 +118,5 @@ let package = Package(
path: "Tests/TITextProcessingTests")
]
)
#endif

View File

@ -0,0 +1,50 @@
//
// Copyright (c) 2023 Touch Instinct
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import PackagePlugin
@main
struct SwiftLintPlugin: BuildToolPlugin {
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
let swiftlintScriptPath = context.package.directory.appending(["build-scripts", "xcode", "build_phases", "swiftlint.sh"])
let swiftlintExecutablePath = try context.tool(named: "swiftlint").path
return [
.prebuildCommand(displayName: "SwiftLint linting...",
executable: swiftlintScriptPath,
arguments: [
swiftlintExecutablePath,
context.package.directory.appending(subpath: "swiftlint_base.yml")
],
environment: [
"SCRIPT_DIR": swiftlintScriptPath.removingLastComponent().string,
"SRCROOT": context.package.directory.string,
"SCRIPT_INPUT_FILE_COUNT": "1",
"SCRIPT_INPUT_FILE_0": target.directory.removingLastComponent().lastComponent,
// "FORCE_LINT": "1", // Lint all files in target (not only modified)
// "AUTOCORRECT": "1"
nikita.semenov marked this conversation as resolved Outdated

оставшиеся комменты - ок?

оставшиеся комменты - ок?

Да, предполагается, что тут как и в проектах будет инкрементальный линтинг, но если хочеться поправить всё - то просто расскоментировать.
Ну последний пустой коммент это артефакт конечно, но пофикшу если будут еще комменты

Да, предполагается, что тут как и в проектах будет инкрементальный линтинг, но если хочеться поправить всё - то просто расскоментировать. Ну последний пустой коммент это артефакт конечно, но пофикшу если будут еще комменты
],
outputFilesDirectory: context.package.directory)
]
}
}

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIAppleMapUtils'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Set of helpers for map objects clustering and interacting using Apple MapKit.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIAuth'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Login, registration, confirmation and other related actions'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '13.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIDeeplink'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Deeplink service API'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -9,7 +9,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
sources = '/Sources/**/*'
if ENV["DEVELOPMENT_INSTALL"] # installing using :path =>

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIDeveloperUtils'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Universal web view API'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -9,7 +9,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIEcommerce'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Cart, products, promocodes, bonuses and other related actions'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -40,8 +40,10 @@ public extension Operation {
leafDependency.addDependency(startOperation)
}
}
func add(to operationQueue: OperationQueue, waitUntilFinished: Bool = false) {
@discardableResult
func add(to operationQueue: OperationQueue, waitUntilFinished: Bool = false) -> Self {
operationQueue.addOperations(flattenDependencies + [self], waitUntilFinished: waitUntilFinished)
return self
}
}

View File

@ -23,6 +23,8 @@
open class BaseCancellable: Cancellable {
private(set) public var isCancelled = false
public init() {}
open func cancel() {
isCancelled = true
}

View File

@ -20,7 +20,7 @@
// THE SOFTWARE.
//
public struct Cancellables {
public enum Cancellables {
public static func nonCancellable() -> Cancellable {
NonCancellable()
}
@ -28,21 +28,27 @@ public struct Cancellables {
public static func scoped(scopeCancellableClosure: ScopeCancellable.ScopeCancellableClosure) -> Cancellable {
ScopeCancellable(scopeCancellableClosure: scopeCancellableClosure)
}
public static func weakTargetClosure<T: AnyObject>(target: T?,
cancelClosure: @escaping WeakTargetCancellable<T>.CancelClosure) -> Cancellable {
WeakTargetCancellable(target: target, cancelClosure: cancelClosure)
}
}
@available(iOS 13.0.0, *)
public func withTaskCancellableClosure<T>(closure: (@escaping (T) -> Void) -> Cancellable) async -> T {
let cancellableBag = BaseCancellableBag()
return await withTaskCancellationHandler(handler: {
cancellableBag.cancel()
}, operation: {
return await withTaskCancellationHandler(operation: {
await withCheckedContinuation { continuation in
closure {
continuation.resume(returning: $0)
}
.add(to: cancellableBag)
}
}, onCancel: {
cancellableBag.cancel()
})
}

View File

@ -1,14 +1,14 @@
Pod::Spec.new do |s|
s.name = 'TIFoundationUtils'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Set of helpers for Foundation framework classes.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '10.0'
s.swift_versions = ['5.3']
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.7']
sources = '**/Sources/**/*.swift'
if ENV["DEVELOPMENT_INSTALL"] # installing using :path =>

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIGoogleMapUtils'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Set of helpers for map objects clustering and interacting using Google Maps SDK.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '12.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIKeychainUtils'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Set of helpers for Keychain classes.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -1,14 +1,14 @@
Pod::Spec.new do |s|
s.name = 'TIMapUtils'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Set of helpers for map objects clustering and interacting.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '10.0'
s.swift_versions = ['5.3']
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -68,9 +68,9 @@ open class DefaultJsonNetworkService: ApiInteractor {
defaultServer: openApi.defaultServer)
}
open func process<B: Encodable, S: Decodable, F: Decodable, R>(request: EndpointRequest<B, S>,
open func process<B: Encodable, S: Decodable, AE: Decodable, R>(request: EndpointRequest<B, S>,
mapSuccess: @escaping Closure<S, R>,
mapFailure: @escaping Closure<F, R>,
mapFailure: @escaping Closure<FailureMappingInput<AE>, R>,
mapNetworkError: @escaping Closure<MoyaError, R>,
completion: @escaping ParameterClosure<R>) -> TIFoundationUtils.Cancellable {
@ -115,9 +115,9 @@ open class DefaultJsonNetworkService: ApiInteractor {
return cancellableBag
}
open func process<S: Decodable, F: Decodable, R>(request: SerializedRequest,
open func process<S: Decodable, AE: Decodable, R>(request: SerializedRequest,
mapSuccess: @escaping Closure<S, R>,
mapFailure: @escaping Closure<F, R>,
mapFailure: @escaping Closure<FailureMappingInput<AE>, R>,
mapNetworkError: @escaping Closure<MoyaError, R>,
completion: @escaping ParameterClosure<R>) -> TIFoundationUtils.Cancellable {
@ -152,8 +152,10 @@ open class DefaultJsonNetworkService: ApiInteractor {
}
let decodeResult = rawResponse.decode(mapping: [
((successStatusCodes, CommonMediaTypes.applicationJson.rawValue), jsonDecoder.decoding(to: mapSuccess)),
((failureStatusCodes, CommonMediaTypes.applicationJson.rawValue), jsonDecoder.decoding(to: mapFailure)),
KeyValueTuple(.json(with: successStatusCodes), jsonDecoder.decoding(to: mapSuccess)),
KeyValueTuple(.json(with: failureStatusCodes), jsonDecoder.decoding(to: {
mapFailure(FailureMappingInput($0, rawResponse.statusCode))
})),
])
let pluginResult: Result<Response, MoyaError>
@ -192,10 +194,10 @@ open class DefaultJsonNetworkService: ApiInteractor {
preprocessors.append(securityPreprocessor)
}
private static func preprocess<B,S,P: Collection>(request: EndpointRequest<B,S>,
private static func preprocess<B, S, P: Collection>(request: EndpointRequest<B, S>,
preprocessors: P,
cancellableBag: BaseCancellableBag,
completion: @escaping (Result<EndpointRequest<B,S>, Error>) -> Void)
completion: @escaping (Result<EndpointRequest<B, S>, Error>) -> Void)
where P.Element == EndpointRequestPreprocessor {
guard let preprocessor = preprocessors.first else {

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIMoyaNetworking'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Moya + Swagger network service.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/**/Sources/**/*'

View File

@ -41,8 +41,8 @@ open class FingerprintsTrustEvaluator: ServerTrustEvaluating {
guard SecTrustGetCertificateCount(trust) > 0,
let certificate = SecTrustGetCertificateAtIndex(trust, 0) else {
throw PinValidationFailed.unableToExtractPin(trust: trust)
}
throw PinValidationFailed.unableToExtractPin(trust: trust)
}
let certificateData = SecCertificateCopyData(certificate) as Data
@ -65,4 +65,3 @@ open class FingerprintsTrustEvaluator: ServerTrustEvaluating {
}
}
}

View File

@ -27,10 +27,11 @@ public protocol ApiInteractor {
associatedtype NetworkError
typealias RequestResult<S: Decodable, AE: Decodable> = EndpointRequestResult<S, AE, NetworkError>
typealias FailureMappingInput<AE> = (apiError: AE, statusCode: Int)
func process<B: Encodable, S: Decodable, AE: Decodable, R>(request: EndpointRequest<B, S>,
mapSuccess: @escaping Closure<S, R>,
mapFailure: @escaping Closure<AE, R>,
mapFailure: @escaping Closure<FailureMappingInput<AE>, R>,
mapNetworkError: @escaping Closure<NetworkError, R>,
completion: @escaping ParameterClosure<R>) -> Cancellable
}
@ -40,14 +41,14 @@ public extension ApiInteractor {
func process<B: Encodable, S, F>(request: EndpointRequest<B, S>) async -> RequestResult<S, F> {
await process(request: request,
mapSuccess: Result.success,
mapFailure: { .failure(.apiError($0)) },
mapFailure: { .failure(.apiError($0.apiError, $0.statusCode)) },
mapNetworkError: { .failure(.networkError($0)) })
}
func process<B: Encodable, S: Decodable, F: Decodable, R>(request: EndpointRequest<B, S>,
mapSuccess: @escaping Closure<S, R>,
mapFailure: @escaping Closure<F, R>,
mapNetworkError: @escaping Closure<NetworkError, R>) async -> R {
func process<B: Encodable, S: Decodable, AE: Decodable, R>(request: EndpointRequest<B, S>,
mapSuccess: @escaping Closure<S, R>,
mapFailure: @escaping Closure<FailureMappingInput<AE>, R>,
mapNetworkError: @escaping Closure<NetworkError, R>) async -> R {
await withTaskCancellableClosure { completion in
process(request: request,

View File

@ -21,6 +21,6 @@
//
public enum EndpointErrorResult<ApiError, NetworkError>: Error {
case apiError(ApiError)
case apiError(ApiError, Int)
case networkError(NetworkError)
}

View File

@ -20,4 +20,6 @@
// THE SOFTWARE.
//
public typealias EndpointRecoverableRequestResult<S: Decodable, AE: Decodable, NE> = Result<S, ErrorCollection<EndpointErrorResult<AE, NE>>>
public typealias EndpointRecoverableRequestResult<S: Decodable,
AE: Decodable,
NE> = Result<S, ErrorCollection<EndpointErrorResult<AE, NE>>>

View File

@ -32,12 +32,16 @@ public enum HTTPCodes {
switch self {
case .informational:
return Set(100...199)
case .success:
return Set(200...299)
case .redirection:
return Set(300...399)
case .clientError:
return Set(400...499)
case .serverError:
return Set(500...599)
}

View File

@ -32,7 +32,9 @@ public struct AnyEndpointRequestRetrier<ErrorResult: Error>: EndpointRequestRetr
self.validateAndRepairClosure = retrier.validateAndRepair
}
public func validateAndRepair(errorResults: [ErrorResult], completion: @escaping (EndpointRetryResult) -> Void) -> Cancellable {
public func validateAndRepair(errorResults: [ErrorResult],
completion: @escaping (EndpointRetryResult) -> Void) -> Cancellable {
validateAndRepairClosure(errorResults, completion)
}
}

View File

@ -72,7 +72,7 @@ open class DefaultTokenInterceptor<RefreshError: Error>: RequestInterceptor {
}
// MARK: - RequestRetrier
open func retry(_ request: Request,
for session: Session,
dueTo error: Error,
@ -85,6 +85,7 @@ open class DefaultTokenInterceptor<RefreshError: Error>: RequestInterceptor {
switch $0 {
case let .success(retryResult):
completion(retryResult)
case let .failure(refreshError):
completion(.doNotRetryWithError(refreshError))
}
@ -102,7 +103,7 @@ open class DefaultTokenInterceptor<RefreshError: Error>: RequestInterceptor {
defaultCompletionResult: T,
recoveredCompletionResult: T) -> Cancellable {
let operation = ClosureAsyncOperation<T, RefreshError>(cancellableTaskClosure: { [refreshTokenClosure] operationCompletion in
ClosureAsyncOperation<T, RefreshError>(cancellableTaskClosure: { [refreshTokenClosure] operationCompletion in
if validationClosure() {
return refreshTokenClosure {
if let error = $0 {
@ -119,9 +120,6 @@ open class DefaultTokenInterceptor<RefreshError: Error>: RequestInterceptor {
})
.observe(onResult: completion,
callbackQueue: .global())
operation.add(to: processingQueue)
return operation
.add(to: processingQueue)
}
}

View File

@ -23,7 +23,9 @@
import Alamofire
import TIFoundationUtils
open class EndpointResponseTokenInterceptor<AE, NE>: DefaultTokenInterceptor<EndpointErrorResult<AE, NE>>, EndpointRequestRetrier {
open class EndpointResponseTokenInterceptor<AE, NE>: DefaultTokenInterceptor<EndpointErrorResult<AE, NE>>,
EndpointRequestRetrier {
public typealias IsTokenInvalidErrorResultClosure = (EndpointErrorResult<AE, NE>) -> Bool
public typealias RepairResult = Result<RetryResult, EndpointErrorResult<AE, NE>>

View File

@ -41,7 +41,7 @@ public struct ApplicationJsonBodySerializer<Body>: BodySerializer {
public func serialize(body: Body?) throws -> ContentTypeData {
let mimeType = CommonMediaTypes.applicationJson.rawValue
guard let body = body else {
guard let body else {
nikita.semenov marked this conversation as resolved
Review

Как так получается, что в подфайлах у нас версия swift 5.3, а конструкции используем из 5.7?

Как так получается, что в подфайлах у нас версия swift 5.3, а конструкции используем из 5.7?
return (mimeType, Data())
}

View File

@ -23,7 +23,7 @@
import Foundation
public final class EmptyResponseContent: BaseContent, ResponseContent {
public func decodeResponse(data: Data) throws -> Void {
public func decodeResponse(data: Data) throws {
()
}
}

View File

@ -28,12 +28,14 @@ open class HeaderParameterEncoding: ParameterEncoding {
let key = $1.key
let nonEmptyValueComponents = pathComponents(fromKey: key, value: $1.value.value)
.filter { !$0.value.isEmpty || (parameters[key]?.allowEmptyValue ?? true) }
$0.merge(nonEmptyValueComponents) { _, last in last }
$0.merge(nonEmptyValueComponents) { _, last in
last
}
}
}
open func pathComponents(fromKey key: String, value: Any?) -> [String: String] {
guard let value = value else {
guard let value else {
return [:]
}
@ -42,10 +44,14 @@ open class HeaderParameterEncoding: ParameterEncoding {
switch value {
case let dictionary as [String: Any]:
for (nestedKey, value) in dictionary {
components.merge(pathComponents(fromKey: nestedKey, value: value)) { _, last in last }
components.merge(pathComponents(fromKey: nestedKey, value: value)) { _, last in
last
}
}
case let array as [Any]:
components.updateValue(array.map { "\($0)" }.joined(separator: ","), forKey: key)
default:
components.updateValue("\(value)", forKey: key)
}

View File

@ -29,7 +29,7 @@ open class PathParameterEncoding: BaseUrlParameterEncoding, ParameterEncoding {
// MARK: - ParameterEncoding
open func encode(parameters: [String: Parameter<LocationPath>]) -> String {
open func encode(parameters: [String: Parameter<LocationPath>]) -> String {
.render(template: templateUrl, using: encode(parameters: parameters))
}
}

View File

@ -25,7 +25,8 @@ import Foundation
public extension EndpointRequest {
func serialize<Serializer: BodySerializer>(using serializer: Serializer,
defaultServer: Server) throws -> SerializedRequest where Serializer.Body == Body {
defaultServer: Server)
throws -> SerializedRequest where Serializer.Body == Body {
let baseUrl = try (server ?? defaultServer).url(using: customServerVariables)
let path = PathParameterEncoding(templateUrl: templatePath).encode(parameters: pathParameters)
@ -47,7 +48,7 @@ public extension EndpointRequest {
if let domain = baseUrl.host {
cookies = cookieParameters.compactMap { key, value in
HTTPCookie(properties: [
.name : key,
.name: key,
.value: value,
.domain: domain,
.path: path
@ -67,4 +68,3 @@ public extension EndpointRequest {
acceptableStatusCodes: acceptableStatusCodes)
}
}

View File

@ -57,16 +57,16 @@ extension SerializedRequest: Hashable {
private var comparableQueryParameters: [String: String] {
queryParameters.mapValues(String.init(describing:))
}
public static func == (lhs: SerializedRequest, rhs: SerializedRequest) -> Bool {
lhs.baseURL == rhs.baseURL &&
lhs.path == rhs.path &&
lhs.method == rhs.method &&
lhs.bodyData == rhs.bodyData &&
lhs.comparableQueryParameters == rhs.comparableQueryParameters &&
lhs.headers == rhs.headers &&
lhs.cookies == rhs.cookies &&
lhs.acceptableStatusCodes == rhs.acceptableStatusCodes
lhs.path == rhs.path &&
vladimir.makarov marked this conversation as resolved
Review

Не очень красиво он здесь форматирует, конечно 🙂

Не очень красиво он здесь форматирует, конечно 🙂
Review

что поделать 🤷

что поделать 🤷
lhs.method == rhs.method &&
lhs.bodyData == rhs.bodyData &&
lhs.comparableQueryParameters == rhs.comparableQueryParameters &&
lhs.headers == rhs.headers &&
lhs.cookies == rhs.cookies &&
lhs.acceptableStatusCodes == rhs.acceptableStatusCodes
}
public func hash(into hasher: inout Hasher) {

View File

@ -42,9 +42,9 @@ open class DefaultSecuritySchemePreprocessor: SecuritySchemePreprocessor {
// MARK: - EndpointSecurityRequestPreprocessor
public func preprocess<B,S>(request: EndpointRequest<B,S>,
using security: SecurityScheme,
completion: @escaping (Result<EndpointRequest<B,S>, Error>) -> Void) -> Cancellable {
public func preprocess<B, S>(request: EndpointRequest<B, S>,
using security: SecurityScheme,
completion: @escaping (Result<EndpointRequest<B, S>, Error>) -> Void) -> Cancellable {
var modifiedRequest = request
@ -62,6 +62,7 @@ open class DefaultSecuritySchemePreprocessor: SecuritySchemePreprocessor {
forKey: "Authorization")
modifiedRequest.headerParameters = headerParameters
case let .apiKey(parameterLocation, parameterName):
switch parameterLocation {
case .header:
@ -70,9 +71,11 @@ open class DefaultSecuritySchemePreprocessor: SecuritySchemePreprocessor {
forKey: parameterName)
modifiedRequest.headerParameters = headerParameters
case .query:
modifiedRequest.queryParameters.updateValue(.init(value: value),
forKey: parameterName)
case .cookie:
modifiedRequest.cookieParameters.updateValue(.init(value: value),
forKey: parameterName)

View File

@ -38,8 +38,8 @@ open class DefaultEndpointSecurityPreprocessor: EndpointRequestPreprocessor {
self.schemePreprocessors = schemePreprocessors
}
public func preprocess<B,S>(request: EndpointRequest<B,S>,
completion: @escaping (Result<EndpointRequest<B,S>, Error>) -> Void) -> Cancellable {
public func preprocess<B, S>(request: EndpointRequest<B, S>,
completion: @escaping (Result<EndpointRequest<B, S>, Error>) -> Void) -> Cancellable {
guard !request.security.compactMap({ $0 }).isEmpty else {
completion(.success(request))
@ -60,13 +60,10 @@ open class DefaultEndpointSecurityPreprocessor: EndpointRequestPreprocessor {
return Self.preprocess(request: request,
using: endpointSchemes,
schemePreprocessors: schemePreprocessors) { [schemePreprocessors] in
switch $0 {
case let .success(modifiedRequest):
completion(.success(modifiedRequest))
case .failure:
completion(.failure(PreprocessError.unableToSatisfyRequirements(anyOfRequired: request.security,
registeredPreprocessors: schemePreprocessors)))
}
completion($0.mapError { _ in
PreprocessError.unableToSatisfyRequirements(anyOfRequired: request.security,
registeredPreprocessors: schemePreprocessors)
})
}
} catch {
completion(.failure(error))
@ -78,11 +75,11 @@ open class DefaultEndpointSecurityPreprocessor: EndpointRequestPreprocessor {
schemePreprocessors[scheme] = preprocessor
}
private static func preprocess<B,S,SC: Collection>(request: EndpointRequest<B,S>,
using schemes: SC,
schemePreprocessors: [String: SecuritySchemePreprocessor],
completion: @escaping (Result<EndpointRequest<B,S>, Error>) -> Void) -> Cancellable
where SC.Element == [KeyValueTuple<String, SecurityScheme>] {
private static func preprocess<B, S, SC: Collection>(request: EndpointRequest<B, S>,
using schemes: SC,
schemePreprocessors: [String: SecuritySchemePreprocessor],
completion: @escaping (Result<EndpointRequest<B, S>, Error>) -> Void)
-> Cancellable where SC.Element == [KeyValueTuple<String, SecurityScheme>] {
guard let schemeGroup = schemes.first else {
completion(.success(request))
@ -113,6 +110,7 @@ open class DefaultEndpointSecurityPreprocessor: EndpointRequestPreprocessor {
switch $0 {
case let .success(modifiedRequest):
completion(.success(modifiedRequest))
case let .failure(error):
guard !schemes.isEmpty else {
completion(.failure(error))
@ -129,10 +127,10 @@ open class DefaultEndpointSecurityPreprocessor: EndpointRequestPreprocessor {
}
}
private static func preprocess<B,S,G: Collection>(request: EndpointRequest<B,S>,
with groups: G,
completion: @escaping (Result<EndpointRequest<B,S>, Error>) -> Void) -> Cancellable
where G.Element == KeyValueTuple<SecurityScheme, SecuritySchemePreprocessor> {
private static func preprocess<B, S, G: Collection>(request: EndpointRequest<B, S>,
with groups: G,
completion: @escaping (Result<EndpointRequest<B, S>, Error>) -> Void)
-> Cancellable where G.Element == KeyValueTuple<SecurityScheme, SecuritySchemePreprocessor> {
guard let group = groups.first else {
completion(.success(request))
@ -148,6 +146,7 @@ open class DefaultEndpointSecurityPreprocessor: EndpointRequestPreprocessor {
with: groups.dropFirst(),
completion: completion)
.add(to: scope)
case let .failure(error):
completion(.failure(error))
}

View File

@ -23,13 +23,13 @@
import TIFoundationUtils
public protocol EndpointRequestPreprocessor {
func preprocess<B,S>(request: EndpointRequest<B,S>,
completion: @escaping (Result<EndpointRequest<B,S>, Error>) -> Void) -> Cancellable
func preprocess<B, S>(request: EndpointRequest<B, S>,
completion: @escaping (Result<EndpointRequest<B, S>, Error>) -> Void) -> Cancellable
}
@available(iOS 13.0.0, *)
public extension EndpointRequestPreprocessor {
func preprocess<B,S>(request: EndpointRequest<B,S>) async -> Result<EndpointRequest<B,S>, Error> {
func preprocess<B, S>(request: EndpointRequest<B, S>) async -> Result<EndpointRequest<B, S>, Error> {
await withTaskCancellableClosure { completion in
preprocess(request: request) {
completion($0)

View File

@ -23,14 +23,16 @@
import TIFoundationUtils
public protocol SecuritySchemePreprocessor {
func preprocess<B,S>(request: EndpointRequest<B,S>,
using security: SecurityScheme,
completion: @escaping (Result<EndpointRequest<B,S>, Error>) -> Void) -> Cancellable
func preprocess<B, S>(request: EndpointRequest<B, S>,
using security: SecurityScheme,
completion: @escaping (Result<EndpointRequest<B, S>, Error>) -> Void) -> Cancellable
}
@available(iOS 13.0.0, *)
public extension SecuritySchemePreprocessor {
func preprocess<B,S>(request: EndpointRequest<B,S>, using security: SecurityScheme) async -> Result<EndpointRequest<B,S>, Error> {
func preprocess<B, S>(request: EndpointRequest<B, S>, using security: SecurityScheme)
async -> Result<EndpointRequest<B, S>, Error> {
await withTaskCancellableClosure { completion in
preprocess(request: request, using: security) {
completion($0)

View File

@ -23,15 +23,12 @@
import Foundation
import TISwiftUtils
public typealias StatusCodeMimeType = (statusCode: Int, mimeType: String?)
public typealias StatusCodesMimeType = (statusCodes: Set<Int>, mimeType: String?)
public typealias DecodingClosure<R> = ThrowableClosure<Data, R>
public extension ResponseType {
typealias DecodingClosure<R> = ThrowableClosure<Data, R>
func decode<R>(mapping: [KeyValueTuple<StatusCodeMimeType, DecodingClosure<R>>]) -> Result<R, ErrorType> {
for ((mappingStatusCode, mappingMimeType), decodeClosure) in mapping
where mappingStatusCode == statusCode && mappingMimeType == mimeType {
for (statusCodesMimeType, decodeClosure) in mapping
where statusCodesMimeType.statusCode == statusCode && statusCodesMimeType.mimeType == mimeType {
do {
return .success(try decodeClosure(data))
} catch {
@ -52,7 +49,8 @@ public extension ResponseType {
func decode<R>(mapping: [KeyValueTuple<StatusCodesMimeType, DecodingClosure<R>>]) -> Result<R, ErrorType> {
decode(mapping: mapping.map { key, value in
key.statusCodes.map { KeyValueTuple(StatusCodeMimeType($0, key.mimeType), value) }
}.flatMap { $0 })
key.statusCodes.map { KeyValueTuple(StatusCodeMimeType(statusCode: $0, mimeType: key.mimeType), value) }
}
.flatMap { $0 })
}
}

View File

@ -0,0 +1,35 @@
//
// Copyright (c) 2023 Touch Instinct
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
public struct StatusCodeMimeType {
public let statusCode: Int
public let mimeType: String?
public init(statusCode: Int, mimeType: String?) {
self.statusCode = statusCode
self.mimeType = mimeType
}
public static func json(with statusCode: Int) -> Self {
.init(statusCode: statusCode, mimeType: CommonMediaTypes.applicationJson.rawValue)
}
}

View File

@ -0,0 +1,35 @@
//
// Copyright (c) 2023 Touch Instinct
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
public struct StatusCodesMimeType {
public let statusCodes: Set<Int>
public let mimeType: String?
public init(statusCodes: Set<Int>, mimeType: String?) {
self.statusCodes = statusCodes
self.mimeType = mimeType
}
public static func json(with statusCodes: Set<Int>) -> Self {
.init(statusCodes: statusCodes, mimeType: CommonMediaTypes.applicationJson.rawValue)
}
}

View File

@ -21,8 +21,8 @@
//
public struct HTTPAuthenticationScheme: RawRepresentable, Equatable, Hashable {
public static let basic = HTTPAuthenticationScheme(rawValue: "Basic")
public static let bearer = HTTPAuthenticationScheme(rawValue: "Bearer")
public static let basic = Self(rawValue: "Basic")
public static let bearer = Self(rawValue: "Bearer")
public let rawValue: String

View File

@ -65,7 +65,9 @@ public struct Server {
}
let defaultVariablesToApply = self.defaultVariables
.filter { (key, _) in variables.contains { $0.key == key } }
.filter { key, _ in
variables.contains { $0.key == key }
}
let defaultParametersTemplate = String.render(template: urlTemplate,
using: defaultVariablesToApply)

View File

@ -24,7 +24,7 @@ import Foundation
public extension String {
var urlEscaped: String {
return addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? self
addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? self
}
var urlHost: String {

View File

@ -1,14 +1,14 @@
Pod::Spec.new do |s|
s.name = 'TINetworking'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Swagger-frendly networking layer helpers.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '10.0'
s.swift_versions = ['5.3']
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TINetworkingCache'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Caching results of EndpointRequests.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -1,14 +1,14 @@
Pod::Spec.new do |s|
s.name = 'TIPagination'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Generic pagination component.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '10.0'
s.swift_versions = ['5.3']
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TISwiftUICore'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Core UI elements: protocols, views and helpers.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '13.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -1,14 +1,14 @@
Pod::Spec.new do |s|
s.name = 'TISwiftUtils'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Bunch of useful helpers for Swift development.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '9.0'
s.swift_versions = ['5.3']
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.7']
sources = 'Sources/**/*.swift'
if ENV["DEVELOPMENT_INSTALL"] # installing using :path =>

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TITableKitUtils'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Set of helpers for TableKit classes.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -1,14 +1,14 @@
Pod::Spec.new do |s|
s.name = 'TITextProcessing'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'A text processing service helping to get a text mask and a placeholder from incoming regex.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '10.0'
s.swift_versions = ['5.3']
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.7']
sources = '/Sources/**/*'

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIUIElements'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Bunch of useful protocols and views.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -9,7 +9,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
sources = '/Sources/**/*'
if ENV["DEVELOPMENT_INSTALL"] # installing using :path =>

View File

@ -29,13 +29,13 @@ public struct AlertAction {
public let id = UUID()
/// Alert button title
public let title: String
public var title: String
/// Alert button style
public let style: UIAlertAction.Style
public var style: UIAlertAction.Style
/// Alert button action
public let action: VoidClosure?
public var action: VoidClosure?
public init(title: String, style: UIAlertAction.Style = .default, action: VoidClosure? = nil) {
self.title = title

View File

@ -26,19 +26,19 @@ import UIKit
public struct AlertDescriptor {
/// Alert title
public let title: String?
public var title: String?
/// Alert message
public let message: String?
public var message: String?
/// Alert style
public let style: UIAlertController.Style
public var style: UIAlertController.Style
/// Alert tint color
public let tintColor: UIColor
public var tintColor: UIColor
/// Alert actions
public let actions: [AlertAction]
public var actions: [AlertAction]
public init(title: String? = nil,
message: String? = nil,

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIUIKitCore'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Core UI elements: protocols, views and helpers.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -9,7 +9,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'
s.framework = 'UIKit'

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIWebView'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Universal web view API'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -9,7 +9,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '11.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIYandexMapUtils'
s.version = '1.43.1'
s.version = '1.44.0'
s.summary = 'Set of helpers for map objects clustering and interacting using Yandex Maps SDK.'
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
s.ios.deployment_target = '12.0'
s.swift_versions = ['5.3']
s.swift_versions = ['5.7']
s.source_files = s.name + '/Sources/**/*'

@ -1 +1 @@
Subproject commit 1f83bf5d08bbc2c2346141621a42b2d2e0dd6517
Subproject commit 39109c6e6032b2a59f4cdd7b80ac06c4dc8b33c0

View File

@ -1,14 +0,0 @@
#!/bin/sh
readonly CONFIG_PATH=${PROJECT_DIR}/build-scripts/xcode/.swiftlint.yml
readonly SWIFTLINT_VERSION=0.39.1
readonly SWIFTLINT_PORTABLE_FILENAME=portable_swiftlint.zip
readonly SWIFTLINT_PORTABLE_URL=https://github.com/realm/SwiftLint/releases/download/${SWIFTLINT_VERSION}/${SWIFTLINT_PORTABLE_FILENAME}
. build-scripts/xcode/aux_scripts/download_file.sh ${SWIFTLINT_PORTABLE_FILENAME} ${SWIFTLINT_PORTABLE_URL} Downloads --remove-cached
cd Downloads && unzip -o ${SWIFTLINT_PORTABLE_FILENAME}
${PROJECT_DIR}/Downloads/swiftlint autocorrect --path ${PROJECT_DIR}/Sources --config ${CONFIG_PATH} && ${PROJECT_DIR}/Downloads/swiftlint --path ${PROJECT_DIR}/Sources --config ${CONFIG_PATH}

1
swiftlint_base.yml Symbolic link
View File

@ -0,0 +1 @@
build-scripts/xcode/.swiftlint.yml