YamlScalar.toFloat() / toDouble() delegate to String::toFloat / String::toDouble (src/commonMain/kotlin/com/charleskorn/kaml/YamlNode.kt:97,124). The accepted input set of those stdlib functions is not the same on every target, so the same document parses on one target and throws on another.
Measured
Probe ran YamlScalar(content, path).toDouble() / .toFloat() / .toInt() on jvm, macosArm64, jsNode and wasmJsNode.
| content |
JVM |
Native |
JS |
Wasm |
1f 1d 1F 1D |
1.0 |
1.0 |
throws |
throws |
0x1p3 |
8.0 |
8.0 |
throws |
throws |
0x2 as float/double |
throws |
throws |
2.0 |
throws |
Infinity -Infinity NaN |
accepted |
accepted |
accepted |
accepted |
1e5 .5 |
100000.0 / 0.5 |
same |
same |
same |
Two separate splits:
1f, 1d, 1F, 1D, 0x1p3 — accepted on JVM and Native, rejected on JS and Wasm. Java's Double.parseDouble accepts the f/d type suffix and the hexadecimal float form; +"1f" in JS is NaN. Not documented anywhere.
0x2 as a float — accepted on JS only, because Kotlin/JS String.toDouble() is unary plus and JS number conversion reads hexadecimal. Already known: YamlScalarTest.kt:251-265 disables the "invalid float" assertion for 0x2 and 0o2 on JS. That is a test workaround, not a fix.
None of 1f, 1d, 0x1p3, Infinity, NaN are floats under the YAML 1.2 core schema. Only .inf / .nan are, and those are already handled explicitly before the stdlib call.
Repro
Yaml.default.decodeFromString(Double.serializer(), "1f") // 1.0 on jvm/native, throws on js/wasm
Yaml.default.decodeFromString(Double.serializer(), "0x1p3") // 8.0 on jvm/native, throws on js/wasm
Yaml.default.decodeFromString(Double.serializer(), "0x2") // 2.0 on js, throws elsewhere
Fix
Scan content against the YAML 1.2 core schema float grammar before calling the stdlib, the same way ScalarClassifier in kotaml-json already does for the conversion path. That removes both splits at once and drops the JS carve-out in YamlScalarTest.
Behaviour change: input that decodes today on some targets stops decoding. Every affected form is outside the YAML float schema, so nothing that is valid YAML is lost.
Related: #28.
YamlScalar.toFloat()/toDouble()delegate toString::toFloat/String::toDouble(src/commonMain/kotlin/com/charleskorn/kaml/YamlNode.kt:97,124). The accepted input set of those stdlib functions is not the same on every target, so the same document parses on one target and throws on another.Measured
Probe ran
YamlScalar(content, path).toDouble()/.toFloat()/.toInt()on jvm, macosArm64, jsNode and wasmJsNode.1f1d1F1D0x1p30x2as float/doubleInfinity-InfinityNaN1e5.5Two separate splits:
1f,1d,1F,1D,0x1p3— accepted on JVM and Native, rejected on JS and Wasm. Java'sDouble.parseDoubleaccepts thef/dtype suffix and the hexadecimal float form;+"1f"in JS isNaN. Not documented anywhere.0x2as a float — accepted on JS only, because Kotlin/JSString.toDouble()is unary plus and JS number conversion reads hexadecimal. Already known:YamlScalarTest.kt:251-265disables the "invalid float" assertion for0x2and0o2on JS. That is a test workaround, not a fix.None of
1f,1d,0x1p3,Infinity,NaNare floats under the YAML 1.2 core schema. Only.inf/.nanare, and those are already handled explicitly before the stdlib call.Repro
Fix
Scan
contentagainst the YAML 1.2 core schema float grammar before calling the stdlib, the same wayScalarClassifierinkotaml-jsonalready does for the conversion path. That removes both splits at once and drops the JS carve-out inYamlScalarTest.Behaviour change: input that decodes today on some targets stops decoding. Every affected form is outside the YAML float schema, so nothing that is valid YAML is lost.
Related: #28.