Skip to content

Commit

Permalink
chore(ios): fix linter errors and locale sensitive tests for Codable …
Browse files Browse the repository at this point in the history
…implementation (#7680)
  • Loading branch information
Steven0351 authored Sep 26, 2024
1 parent b509e29 commit 5a61720
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 41 deletions.
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

0 comments on commit 5a61720

Please sign in to comment.