Skip to content

Instantly share code, notes, and snippets.

@MojtabaHs
Last active February 26, 2024 14:47
Show Gist options
  • Save MojtabaHs/1f9a0f19bafaecd0c94f585648244303 to your computer and use it in GitHub Desktop.
Save MojtabaHs/1f9a0f19bafaecd0c94f585648244303 to your computer and use it in GitHub Desktop.
Strategy for decoding UpperCamelCase JSONs to preferred lowerCamelCase version.
public extension JSONDecoder.KeyDecodingStrategy {
/// Convert from "UpperCamelCaseKeys" to "lowerCamelCaseKeys" before attempting to match a key with the one specified by each type.
///
/// The conversion to upper case uses `Locale.system`, also known as the ICU "root" locale. This means the result is consistent regardless of the current user's locale and language preferences.
///
/// - Copyright: This function is based on this [source](https://gist.github.com/MojtabaHs/1f9a0f19bafaecd0c94f585648244303)
static var convertFromUpperCamelCase: Self {
.custom { keys in
/// - Precondition: `Keys` array must never be empty.
guard let key = keys.last else { fatalError("Keys should not be empty") }
/// - Important: `Integer key`means that the json is a first level array. Do not change the key for an array!
guard key.intValue == nil else { return key }
let codingKeyType = type(of: key)
let lowerCamelCased = key.stringValue.lowercased(first: 1)
/// - Precondition: There should be no issues to initialize a new coding key.
guard let transformedKey = codingKeyType.init(stringValue: lowerCamelCased) else {
fatalError("Could not initialize a coding key for \"\(lowerCamelCased)\"")
}
return transformedKey
}
}
}
public extension String {
func lowercased(first count: Int) -> String {
prefix(count).lowercased() + dropFirst(count)
}
}
// USAGE:
/*
let jsonDecoder: JSONDecoder = {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromUpperCamelCase
return decoder
}()
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment