Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(ios): fix linter errors and locale sensitive tests for Codable implementation #7680

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 57 additions & 40 deletions ios/Capacitor/Capacitor/Codable/JSValueDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,55 +127,72 @@ extension _JSValueDecoder: Decoder {
SingleValueContainer(data: data, codingPath: codingPath, userInfo: userInfo, options: options)
}

// force casting is fine becasue we've already determined that T is the type in the case
// the swift standard library also force casts in their similar functions
// https://github.com/swiftlang/swift-foundation/blob/da80d51fa3e77f3e7ed57c4300a870689e755713/Sources/FoundationEssentials/JSON/JSONEncoder.swift#L1140
//swiftlint:disable force_cast
fileprivate func decodeData<T>(as type: T.Type) throws -> T where T: Decodable {
switch type {
case is Date.Type:
switch options.dateStrategy {
case .deferredToDate:
return try T(from: self)
case .secondsSince1970:
guard let value = data as? NSNumber else { throw DecodingError.dataCorrupted(data, target: Double.self, codingPath: codingPath) }
return Date(timeIntervalSince1970: value.doubleValue) as! T
case .millisecondsSince1970:
guard let value = data as? NSNumber else { throw DecodingError.dataCorrupted(data, target: Double.self, codingPath: codingPath) }
return Date(timeIntervalSince1970: value.doubleValue / Double(MSEC_PER_SEC)) as! T
case .iso8601:
guard let value = data as? String else { throw DecodingError.dataCorrupted(data, target: String.self, codingPath: codingPath) }
let formatter = ISO8601DateFormatter()
guard let date = formatter.date(from: value) else { throw DecodingError.dataCorrupted(value, target: Date.self, codingPath: codingPath) }
return date as! T
case .formatted(let formatter):
guard let value = data as? String else { throw DecodingError.dataCorrupted(data, target: String.self, codingPath: codingPath) }
guard let date = formatter.date(from: value) else { throw DecodingError.dataCorrupted(value, target: Date.self, codingPath: codingPath) }
return date as! T
case .custom(let decode):
return try decode(self) as! T
@unknown default:
return try T(from: self)
}
return try decodeDate() as! T
case is URL.Type:
guard let str = data as? String,
let url = URL(string: str)
else { throw DecodingError.dataCorrupted(data, target: URL.self, codingPath: codingPath) }

return url as! T
return try decodeUrl() as! T
case is Data.Type:
switch options.dataStrategy {
case .deferredToData:
return try T(from: self)
case .base64:
guard let value = data as? String else { throw DecodingError.dataCorrupted(data, target: String.self, codingPath: codingPath) }
guard let data = Data(base64Encoded: value) else { throw DecodingError.dataCorrupted(value, target: Data.self, codingPath: codingPath) }
return data as! T
case .custom(let decode):
return try decode(self) as! T
@unknown default:
return try T(from: self)
}
return try decodeData() as! T
default:
return try T(from: self)
}
}
//swiftlint:enable force_cast

private func decodeDate() throws -> Date {
switch options.dateStrategy {
case .deferredToDate:
return try Date(from: self)
case .secondsSince1970:
guard let value = data as? NSNumber else { throw DecodingError.dataCorrupted(data, target: Double.self, codingPath: codingPath) }
return Date(timeIntervalSince1970: value.doubleValue)
case .millisecondsSince1970:
guard let value = data as? NSNumber else { throw DecodingError.dataCorrupted(data, target: Double.self, codingPath: codingPath) }
return Date(timeIntervalSince1970: value.doubleValue / Double(MSEC_PER_SEC))
case .iso8601:
guard let value = data as? String else { throw DecodingError.dataCorrupted(data, target: String.self, codingPath: codingPath) }
let formatter = ISO8601DateFormatter()
guard let date = formatter.date(from: value) else { throw DecodingError.dataCorrupted(value, target: Date.self, codingPath: codingPath) }
return date
case .formatted(let formatter):
guard let value = data as? String else { throw DecodingError.dataCorrupted(data, target: String.self, codingPath: codingPath) }
guard let date = formatter.date(from: value) else { throw DecodingError.dataCorrupted(value, target: Date.self, codingPath: codingPath) }
return date
case .custom(let decode):
return try decode(self)
@unknown default:
return try Date(from: self)
}
}

private func decodeUrl() throws -> URL {
guard let str = data as? String,
let url = URL(string: str)
else { throw DecodingError.dataCorrupted(data, target: URL.self, codingPath: codingPath) }

return url
}

private func decodeData() throws -> Data {
switch options.dataStrategy {
case .deferredToData:
return try Data(from: self)
case .base64:
guard let value = data as? String else { throw DecodingError.dataCorrupted(data, target: String.self, codingPath: codingPath) }
guard let data = Data(base64Encoded: value) else { throw DecodingError.dataCorrupted(value, target: Data.self, codingPath: codingPath) }
return data
case .custom(let decode):
return try decode(self)
@unknown default:
return try Data(from: self)
}
}
}

private final class KeyedContainer<Key> where Key: CodingKey {
Expand Down
9 changes: 8 additions & 1 deletion ios/Capacitor/Capacitor/Codable/JSValueEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,12 @@ public final class JSValueEncoder: TopLevelEncoder {
dataEncodingStrategy: DataEncodingStrategy = .deferredToData,
nonConformingFloatEncodingStategy: NonConformingFloatEncodingStrategy = .deferred
) {
self.options = .init(optionalStrategy: optionalEncodingStrategy, dateStrategy: dateEncodingStrategy, dataStrategy: dataEncodingStrategy, nonConformingFloatStrategy: nonConformingFloatEncodingStategy)
self.options = .init(
optionalStrategy: optionalEncodingStrategy,
dateStrategy: dateEncodingStrategy,
dataStrategy: dataEncodingStrategy,
nonConformingFloatStrategy: nonConformingFloatEncodingStategy
)
}


Expand Down Expand Up @@ -591,6 +596,7 @@ extension SingleValueContainer: SingleValueEncodingContainer {
try encodeFloat(value)
}

//swiftlint:disable force_cast
private func encodeFloat<N>(_ value: N) throws where N: FloatingPoint {
if value.isFinite {
data = value as! NSNumber
Expand All @@ -610,6 +616,7 @@ extension SingleValueContainer: SingleValueEncodingContainer {
}
}
}
//swiftlint:enable force_cast

func encode(_ value: Float) throws {
try encodeFloat(value)
Expand Down
1 change: 1 addition & 0 deletions ios/Capacitor/CodableTests/DateCodableTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ private let formatter: DateFormatter = {
formatter.dateStyle = .medium
formatter.timeStyle = .long
formatter.timeZone = .init(abbreviation: "CDT")
formatter.locale = .init(identifier: "en_US")
return formatter
}()
private let formatted = "Sep 5, 2024 at 5:36:20 PM CDT"
Expand Down
Loading