From 291ff1cb709c7953352b95e03b33ce6f7e42864e Mon Sep 17 00:00:00 2001 From: Ross Savage <551697+dangeross@users.noreply.github.com> Date: Tue, 17 Jun 2025 08:49:45 +0000 Subject: [PATCH] Fix React Native Kotlin return enum mapping (#952) --- .../langs/react-native/src/gen_kotlin/mod.rs | 54 ++++++++++--------- .../src/gen_kotlin/templates/Helpers.kt | 11 +++- .../breezsdkliquid/BreezSDKLiquidMapper.kt | 39 ++++++++------ 3 files changed, 61 insertions(+), 43 deletions(-) diff --git a/lib/bindings/langs/react-native/src/gen_kotlin/mod.rs b/lib/bindings/langs/react-native/src/gen_kotlin/mod.rs index da00642..797b497 100644 --- a/lib/bindings/langs/react-native/src/gen_kotlin/mod.rs +++ b/lib/bindings/langs/react-native/src/gen_kotlin/mod.rs @@ -95,31 +95,33 @@ pub mod filters { type_name: &str, ci: &ComponentInterface, ) -> Result { - let res: Result = match type_name { - "Boolean" => Ok("array.pushBoolean(value)".to_string()), - "Double" => Ok("array.pushDouble(value)".to_string()), - "Int" => Ok("array.pushInt(value)".to_string()), - "ReadableArray" => Ok("array.pushArray(value)".to_string()), - "ReadableMap" => Ok("array.pushMap(value)".to_string()), - "String" => Ok("array.pushString(value)".to_string()), - "UByte" => Ok("array.pushInt(value.toInt())".to_string()), - "UInt" => Ok("array.pushInt(value.toInt())".to_string()), - "UShort" => Ok("array.pushInt(value.toInt())".to_string()), - "ULong" => Ok("array.pushDouble(value.toDouble())".to_string()), - _ => match ci.get_type(type_name) { - Some(t) => match t { - Type::Enum(inner) => { - let enum_def = ci.get_enum_definition(&inner).unwrap(); - match enum_def.is_flat() { - true => Ok("array.pushString(value.name.lowercase())".to_string()), - false => Ok("array.pushMap(readableMapOf(value))".to_string()), + let res: Result = + match type_name { + "Boolean" => Ok("array.pushBoolean(value)".to_string()), + "Double" => Ok("array.pushDouble(value)".to_string()), + "Int" => Ok("array.pushInt(value)".to_string()), + "ReadableArray" => Ok("array.pushArray(value)".to_string()), + "ReadableMap" => Ok("array.pushMap(value)".to_string()), + "String" => Ok("array.pushString(value)".to_string()), + "UByte" => Ok("array.pushInt(value.toInt())".to_string()), + "UInt" => Ok("array.pushInt(value.toInt())".to_string()), + "UShort" => Ok("array.pushInt(value.toInt())".to_string()), + "ULong" => Ok("array.pushDouble(value.toDouble())".to_string()), + _ => match ci.get_type(type_name) { + Some(t) => match t { + Type::Enum(inner) => { + let enum_def = ci.get_enum_definition(&inner).unwrap(); + match enum_def.is_flat() { + true => Ok("array.pushString(snakeToLowerCamelCase(value.name))" + .to_string()), + false => Ok("array.pushMap(readableMapOf(value))".to_string()), + } } - } - _ => Ok("array.pushMap(readableMapOf(value))".to_string()), + _ => Ok("array.pushMap(readableMapOf(value))".to_string()), + }, + None => unimplemented!("known type: {type_name}"), }, - None => unimplemented!("known type: {type_name}"), - }, - }; + }; res } @@ -157,9 +159,11 @@ pub mod filters { match enum_def.is_flat() { true => match optional { true => Ok(format!( - "{obj_name}.{field_name}?.let {{ it.name.lowercase() }}" + "{obj_name}.{field_name}?.let {{ snakeToLowerCamelCase(it.name) }}" + )), + false => Ok(format!( + "snakeToLowerCamelCase({obj_name}.{field_name}.name)" )), - false => Ok(format!("{obj_name}.{field_name}.name.lowercase()")), }, false => match optional { true => Ok(format!( diff --git a/lib/bindings/langs/react-native/src/gen_kotlin/templates/Helpers.kt b/lib/bindings/langs/react-native/src/gen_kotlin/templates/Helpers.kt index 1931a1f..63b5d1a 100644 --- a/lib/bindings/langs/react-native/src/gen_kotlin/templates/Helpers.kt +++ b/lib/bindings/langs/react-native/src/gen_kotlin/templates/Helpers.kt @@ -98,8 +98,15 @@ fun errUnexpectedValue(fieldName: String): String { } fun camelToUpperSnakeCase(str: String): String { - val pattern = "(?<=.)[A-Z]".toRegex() - return str.replace(pattern, "_$0").uppercase() + return "(?<=.)[A-Z]".toRegex().replace(str) { + "_${it.value}" + }.uppercase() +} + +fun snakeToLowerCamelCase(str: String): String { + return "_[a-zA-Z]".toRegex().replace(str.lowercase()) { + it.value.replace("_", "").uppercase() + } } internal fun ReadableArray.toList(): List<*> { diff --git a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt index db46deb..d29aefb 100644 --- a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt +++ b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt @@ -270,7 +270,7 @@ fun asBitcoinAddressData(bitcoinAddressData: ReadableMap): BitcoinAddressData? { fun readableMapOf(bitcoinAddressData: BitcoinAddressData): ReadableMap = readableMapOf( "address" to bitcoinAddressData.address, - "network" to bitcoinAddressData.network.name.lowercase(), + "network" to snakeToLowerCamelCase(bitcoinAddressData.network.name), "amountSat" to bitcoinAddressData.amountSat, "label" to bitcoinAddressData.label, "message" to bitcoinAddressData.message, @@ -502,7 +502,7 @@ fun readableMapOf(config: Config): ReadableMap = "liquidExplorer" to readableMapOf(config.liquidExplorer), "bitcoinExplorer" to readableMapOf(config.bitcoinExplorer), "workingDir" to config.workingDir, - "network" to config.network.name.lowercase(), + "network" to snakeToLowerCamelCase(config.network.name), "paymentTimeoutSec" to config.paymentTimeoutSec, "syncServiceUrl" to config.syncServiceUrl, "breezApiKey" to config.breezApiKey, @@ -919,7 +919,7 @@ fun asLnInvoice(lnInvoice: ReadableMap): LnInvoice? { fun readableMapOf(lnInvoice: LnInvoice): ReadableMap = readableMapOf( "bolt11" to lnInvoice.bolt11, - "network" to lnInvoice.network.name.lowercase(), + "network" to snakeToLowerCamelCase(lnInvoice.network.name), "payeePubkey" to lnInvoice.payeePubkey, "paymentHash" to lnInvoice.paymentHash, "description" to lnInvoice.description, @@ -1082,7 +1082,7 @@ fun asLiquidAddressData(liquidAddressData: ReadableMap): LiquidAddressData? { fun readableMapOf(liquidAddressData: LiquidAddressData): ReadableMap = readableMapOf( "address" to liquidAddressData.address, - "network" to liquidAddressData.network.name.lowercase(), + "network" to snakeToLowerCamelCase(liquidAddressData.network.name), "assetId" to liquidAddressData.assetId, "amount" to liquidAddressData.amount, "amountSat" to liquidAddressData.amountSat, @@ -1847,8 +1847,8 @@ fun readableMapOf(payment: Payment): ReadableMap = "timestamp" to payment.timestamp, "amountSat" to payment.amountSat, "feesSat" to payment.feesSat, - "paymentType" to payment.paymentType.name.lowercase(), - "status" to payment.status.name.lowercase(), + "paymentType" to snakeToLowerCamelCase(payment.paymentType.name), + "status" to snakeToLowerCamelCase(payment.status.name), "details" to readableMapOf(payment.details), "swapperFeesSat" to payment.swapperFeesSat, "destination" to payment.destination, @@ -1885,7 +1885,7 @@ fun asPrepareBuyBitcoinRequest(prepareBuyBitcoinRequest: ReadableMap): PrepareBu fun readableMapOf(prepareBuyBitcoinRequest: PrepareBuyBitcoinRequest): ReadableMap = readableMapOf( - "provider" to prepareBuyBitcoinRequest.provider.name.lowercase(), + "provider" to snakeToLowerCamelCase(prepareBuyBitcoinRequest.provider.name), "amountSat" to prepareBuyBitcoinRequest.amountSat, ) @@ -1920,7 +1920,7 @@ fun asPrepareBuyBitcoinResponse(prepareBuyBitcoinResponse: ReadableMap): Prepare fun readableMapOf(prepareBuyBitcoinResponse: PrepareBuyBitcoinResponse): ReadableMap = readableMapOf( - "provider" to prepareBuyBitcoinResponse.provider.name.lowercase(), + "provider" to snakeToLowerCamelCase(prepareBuyBitcoinResponse.provider.name), "amountSat" to prepareBuyBitcoinResponse.amountSat, "feesSat" to prepareBuyBitcoinResponse.feesSat, ) @@ -2144,7 +2144,7 @@ fun asPrepareReceiveRequest(prepareReceiveRequest: ReadableMap): PrepareReceiveR fun readableMapOf(prepareReceiveRequest: PrepareReceiveRequest): ReadableMap = readableMapOf( - "paymentMethod" to prepareReceiveRequest.paymentMethod.name.lowercase(), + "paymentMethod" to snakeToLowerCamelCase(prepareReceiveRequest.paymentMethod.name), "amount" to prepareReceiveRequest.amount?.let { readableMapOf(it) }, ) @@ -2215,7 +2215,7 @@ fun asPrepareReceiveResponse(prepareReceiveResponse: ReadableMap): PrepareReceiv fun readableMapOf(prepareReceiveResponse: PrepareReceiveResponse): ReadableMap = readableMapOf( - "paymentMethod" to prepareReceiveResponse.paymentMethod.name.lowercase(), + "paymentMethod" to snakeToLowerCamelCase(prepareReceiveResponse.paymentMethod.name), "feesSat" to prepareReceiveResponse.feesSat, "amount" to prepareReceiveResponse.amount?.let { readableMapOf(it) }, "minPayerAmountSat" to prepareReceiveResponse.minPayerAmountSat, @@ -4103,8 +4103,8 @@ fun pushToArray( is LocaleOverrides -> array.pushMap(readableMapOf(value)) is LocalizedName -> array.pushMap(readableMapOf(value)) is Payment -> array.pushMap(readableMapOf(value)) - is PaymentState -> array.pushString(value.name.lowercase()) - is PaymentType -> array.pushString(value.name.lowercase()) + is PaymentState -> array.pushString(snakeToLowerCamelCase(value.name)) + is PaymentType -> array.pushString(snakeToLowerCamelCase(value.name)) is Rate -> array.pushMap(readableMapOf(value)) is RefundableSwap -> array.pushMap(readableMapOf(value)) is RouteHint -> array.pushMap(readableMapOf(value)) @@ -4187,10 +4187,17 @@ fun errUnexpectedType(type: Any?): String { fun errUnexpectedValue(fieldName: String): String = "Unexpected value for optional field $fieldName" -fun camelToUpperSnakeCase(str: String): String { - val pattern = "(?<=.)[A-Z]".toRegex() - return str.replace(pattern, "_$0").uppercase() -} +fun camelToUpperSnakeCase(str: String): String = + "(?<=.)[A-Z]" + .toRegex() + .replace(str) { + "_${it.value}" + }.uppercase() + +fun snakeToLowerCamelCase(str: String): String = + "_[a-zA-Z]".toRegex().replace(str.lowercase()) { + it.value.replace("_", "").uppercase() + } internal fun ReadableArray.toList(): List<*> { val arrayList = mutableListOf()