Move SSD nullable text fallbacks to typed Kotlin

ober

aa6a4ad15295c7c3baf791f8186a3286d1cdd081

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 67807d6..940c366 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -1757,7 +1757,7 @@
                 treeExportQuotaExceeded
                 byteArraySizeBytes byteArrayBytesWithinLimit
                 textUtf8Bytes textUtf8SizeBytes textUtf8BytesWithinLimit
-                nullableTextPresent nullableTextOrEmpty
+                nullableTextPresent nullableTextOrEmpty nullableTextOrDefault
                 nullableByteCountPresent nullableByteCountOrZero
                 nullableByteCountWithinLimit
                 oldDestinationBytes urlEffectivePort
@@ -1879,6 +1879,8 @@
           (not (nullable-null? value)))
         (def (nullableTextOrEmpty (value : (Nullable String))) : String
           (if (nullable-null? value) "" (nullable-get value)))
+        (def (nullableTextOrDefault (value : (Nullable String)) (fallback : String)) : String
+          (if (nullable-null? value) fallback (nullable-get value)))
         (def (nullableByteCountPresent (bytes : (Nullable Int))) : Bool
           (not (nullable-null? bytes)))
         (def (nullableByteCountOrZero (bytes : (Nullable Int))) : Int
@@ -7542,7 +7544,7 @@
        "                }"
        "            }"
        "        }"
-       "        return uri.lastPathSegment ?: \"ssd.pdf\""
+       "        return nullableTextOrDefault(uri.lastPathSegment, \"ssd.pdf\")"
        "    }"
        ""
        "    private fun installClientCrashLogger() {"
@@ -7553,7 +7555,7 @@
        "            val payload = try {"
        "                clientLogPayload("
        "                    \"ssd-uncaught-exception\","
-       "                    clientLogCrashFields(crashingThread.name ?: \"\", throwableLog(throwable))"
+       "                    clientLogCrashFields(nullableTextOrEmpty(crashingThread.name), throwableLog(throwable))"
        "                )"
        "            } catch (_: Exception) { clientLogFallbackPayload(\"ssd-uncaught-exception\") }"
        "            try {"
@@ -7618,13 +7620,13 @@
        "        clientLogPayloadJson("
        "            event,"
        "            SystemClock.uptimeMillis(),"
-       "            Thread.currentThread().name ?: \"\","
+       "            nullableTextOrEmpty(Thread.currentThread().name),"
        "            appLogInfo(),"
        "            deviceLogInfo(),"
        "            pdfName,"
        "            pageIndex + 1,"
        "            pageCount,"
-       "            selectedGroupId ?: \"\","
+       "            nullableTextOrEmpty(selectedGroupId),"
        "            fields"
        "        )"
        ""
@@ -7635,16 +7637,16 @@
        "            @Suppress(\"DEPRECATION\")"
        "            val legacyVersionCode = info.versionCode.toLong()"
        "            val versionCode = androidPackageVersionCode(Build.VERSION.SDK_INT, Build.VERSION_CODES.P, info.longVersionCode, legacyVersionCode)"
-       "            appLogVersionInfo(packageName, info.versionName ?: \"\", versionCode)"
+       "            appLogVersionInfo(packageName, nullableTextOrEmpty(info.versionName), versionCode)"
        "        } catch (_: Exception) { out }"
        "    }"
        ""
        "    private fun deviceLogInfo(): JSONObject ="
        "        deviceLogInfoJson("
        "            Build.VERSION.SDK_INT,"
-       "            Build.VERSION.RELEASE ?: \"\","
-       "            Build.MANUFACTURER ?: \"\","
-       "            Build.MODEL ?: \"\""
+       "            nullableTextOrEmpty(Build.VERSION.RELEASE),"
+       "            nullableTextOrEmpty(Build.MANUFACTURER),"
+       "            nullableTextOrEmpty(Build.MODEL)"
        "        )"
        ""
        "    private fun throwableLog(error: Throwable): JSONObject {"
@@ -7652,7 +7654,7 @@
        "        error.printStackTrace(PrintWriter(writer))"
        "        val stack = writer.toString()"
        "        val stackText = truncateClientLogStack(stack)"
-       "        return throwableLogJson(error.javaClass.name, error.message ?: \"\", stackText)"
+       "        return throwableLogJson(error.javaClass.name, nullableTextOrEmpty(error.message), stackText)"
        "    }"
        ""
        "    private fun setStatus(text: String) {"
@@ -8834,7 +8836,7 @@
        "            throw IllegalStateException(\"HTTP response exceeds compressed-byte limit\")"
        "        }"
        "        val raw = LimitedInputStream(connection.inputStream, MAX_HTTP_COMPRESSED_BYTES)"
-       "        val input = responseInputStream(raw, connection.contentEncoding ?: \"\")"
+       "        val input = responseInputStream(raw, nullableTextOrEmpty(connection.contentEncoding))"
        "        return input.use { readBoundedBytes(it, MAX_HTTP_TEXT_BYTES).decodeToString() }"
        "    }"
        ""