JSON Minify — Kotlin source
Remove all whitespace from JSON for the most compact serialization. Validates as it minifies, runs entirely in your browser, with a shareable link to your exact input.
This is the Kotlin implementation — the same logic the interactive tool runs, in a shareable, citable form.
// json-minify — compact JSON to its smallest valid form. Kotlin port
// (canonical TS: src/lib/json-minify.ts; Go twin: cli/json-minify). The JVM
// stdlib has no JSON codec, so — like the Rust port — this is a hand-rolled
// RFC 8259 scanner: validate, copy tokens verbatim, drop only whitespace.
class JsonMinify private constructor(private val src: String) {
private val out = StringBuilder()
private var i = 0
private fun peek(): Char = if (i < src.length) src[i] else Char.MIN_VALUE
private fun take(): Char { val c = peek(); i++; return c } // '\0' at end-of-input
private fun skipWs() { while (peek() in " \t\n\r") i++ }
private fun digits(): Boolean { var any = false; while (peek() in '0'..'9') { i++; any = true }; return any }
private fun string(): Boolean {
out.append('"'); i++ // opening quote
while (true) {
val c = take()
when {
c == '"' -> { out.append(c); return true }
c == '\\' -> {
val e = take()
out.append(e)
if (e == 'u') repeat(4) { val h = take(); if (h !in '0'..'9' && h !in 'a'..'f' && h !in 'A'..'F') return false; out.append(h) }
else if (e !in "\"\\/bfnrt") return false
}
c < ' ' -> return false // control char / EOF
else -> out.append(c)
}
}
}
// Numbers are grammar-checked and copied verbatim — no float round-trip.
private fun number(): Boolean {
val start = i
if (peek() == '-') i++
if (peek() == '0') i++ // "01" is rejected by the caller
else if (peek() in '1'..'9') { i++; while (peek() in '0'..'9') i++ }
else return false // bare '-'
if (peek() == '.') { i++; if (!digits()) return false }
if (peek() == 'e' || peek() == 'E') { i++; if (peek() == '+' || peek() == '-') i++; if (!digits()) return false }
out.append(src, start, i)
return true;
}
private fun literal(word: String): Boolean {
if (!src.startsWith(word, i)) return false
out.append(word); i += word.length
return true
}
private fun value(): Boolean {
skipWs()
val c = peek()
if (c == '{' || c == '[') {
val close = if (c == '{') '}' else ']'
out.append(c); i++; skipWs()
if (peek() == close) { out.append(close); i++; return true } // {} / []
while (true) {
if (close == '}') { skipWs(); if (peek() != '"' || !string()) return false; skipWs(); if (take() != ':') return false; out.append(':') }
if (!value()) return false
skipWs()
val d = take()
if (d == ',') { out.append(d); continue }
if (d == close) { out.append(close); return true }
return false
}
}
if (c == '"') return string()
if (c == 't' || c == 'f' || c == 'n') return literal(if (c == 't') "true" else if (c == 'f') "false" else "null")
return (c == '-' || c in '0'..'9') && number()
}
companion object {
// Compact JSON serialization of input, or null for invalid JSON.
fun minify(input: String): String? {
val p = JsonMinify(input)
if (!p.value()) return null
p.skipWs()
return if (p.i == p.src.length) p.out.toString() else null // trailing garbage
}
}
}
fun main() {
println(JsonMinify.minify("{\n \"a\": 1,\n \"b\": [\n 1,\n 2\n ]\n}")) // {"a":1,"b":[1,2]}
println(JsonMinify.minify("{invalid}")) // null — invalid JSON
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →