Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,7 @@ jobs:
uses: gradle/actions/setup-gradle@v5

- name: Build library
run: ./gradlew assemble --no-configuration-cache
run: ./gradlew :deci:assemble --no-configuration-cache

- name: Compile sample (smoke check)
run: ./gradlew :sample:composeApp:compileKotlinJvm --no-configuration-cache
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
# Changelog

## [Unreleased]

### Removed

- **Intel Apple targets dropped** — `iosX64` and `macosX64` klibs are no longer
published. Consumers targeting Intel macOS or the Intel iOS simulator must stay
on `0.2.2` or earlier. The Apple Silicon targets (`iosArm64`,
`iosSimulatorArm64`, `macosArm64`) are unaffected.

### Changed

- **Android `compileSdk` raised to 37** — projects depending on `deci` must now
compile against Android API level 37 or later.

- **Build scripts modernized — no public API or runtime changes.** Migrated
deprecated Gradle/AGP/Kotlin/Compose DSL across all modules: the AGP KMP
`androidLibrary { }` block → `android { }`, `js(IR)` → `js`, the deprecated
`compose.*` dependency shortcuts → version-catalog coordinates, and the webpack
`devServer.static` property → the `static()` function. Removed unused build
dependencies and version-catalog entries (coroutines core/android/swing, plus
the `android-library`, `ktlint`, and `binary-compatibility-validator` plugin
aliases), and enabled Android host tests so the common test suite also runs on
the Android variant.

## [0.2.2] - 2026-06-05

### Changed

- **Dependency and toolchain updates** — no public API changes. Kotlin
`2.3.20` → `2.4.0`, Android Gradle Plugin `9.0.1` → `9.2.1`, Compose
`1.10.3` → `1.11.1`, kotlinx-coroutines `1.10.2` → `1.11.0`,
kotlinx-serialization `1.10.0` → `1.11.0`, Kotest `6.1.9` → `6.1.11`,
and the Gradle wrapper `9.1.0` → `9.5.1`.

## [0.2.1] - 2026-03-24

### Fixed
Expand Down
11 changes: 6 additions & 5 deletions README.MD
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
<img src="deci-logo.svg" alt="Deci" width="430" />

[![Maven Central](https://img.shields.io/maven-central/v/org.kimplify/deci)](https://central.sonatype.com/artifact/org.kimplify/deci)
[![Kotlin](https://img.shields.io/badge/Kotlin-2.3.20-7F52FF)](https://kotlinlang.org)
[![Kotlin](https://img.shields.io/badge/Kotlin-2.4.0-7F52FF)](https://kotlinlang.org)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

Deci is a Kotlin Multiplatform library for high-precision decimal arithmetic. Built for money, taxes, invoicing, and any workload where `Float`/`Double` cannot be trusted.

## Features

- **Multiplatform** -- Android, JVM, iOS, macOS, JS, WASM, Linux, Windows
- **Multiplatform** -- Android, JVM, iOS, macOS, JS, WASM
- **Exact decimal math** -- backed by `BigDecimal`, `NSDecimalNumber`, and `decimal.js`
- **Predictable rounding** -- explicit rounding modes, no silent precision loss
- **Serialization ready** -- `kotlinx.serialization` support out of the box

## Installation

> Use the latest version shown in the Maven Central badge above.

Kotlin Multiplatform:
```kotlin
kotlin {
sourceSets {
commonMain.dependencies {
implementation("org.kimplify:deci:0.2.0")
implementation("org.kimplify:deci:0.2.2")
}
}
}
Expand All @@ -29,7 +31,7 @@ kotlin {
Single-platform:
```kotlin
dependencies {
implementation("org.kimplify:deci:0.2.0")
implementation("org.kimplify:deci:0.2.2")
}
```

Expand Down Expand Up @@ -164,7 +166,6 @@ Values serialize as JSON **strings** to preserve trailing zeros and avoid lossy
| Android / JVM | `java.math.BigDecimal` |
| iOS / macOS | `NSDecimalNumber` |
| JS / WASM | `decimal.js` v10.6.0 |
| Linux / Windows | Pure Kotlin |

## Configuration

Expand Down
2 changes: 0 additions & 2 deletions build-logic/src/main/kotlin/deci.kmp.library.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ kotlin {
wasmJs { browser() }

// Apple targets
iosX64()
iosArm64()
iosSimulatorArm64()
macosX64()
macosArm64()

applyDefaultHierarchyTemplate()
Expand Down
2 changes: 0 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,4 @@ plugins {
alias(libs.plugins.compose.compiler).apply(false)
alias(libs.plugins.kotlinx.serialization).apply(false)
alias(libs.plugins.android.application).apply(false)
alias(libs.plugins.ktlint).apply(false)
alias(libs.plugins.binary.compatibility.validator).apply(false)
}
16 changes: 4 additions & 12 deletions deci/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,22 @@ val libsCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val deciVersion: String = libsCatalog.findVersion("version").get().requiredVersion

kotlin {
androidLibrary {
android {
namespace = "org.kimplify.deci"
compileSdk = 36
compileSdk = 37
minSdk = 21
withHostTest {}
}

sourceSets {
commonMain.dependencies {
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.kotlinx.serialization.json)
}

commonTest.dependencies {
implementation(kotlin("test"))
implementation(libs.kotest.property)
}

androidMain.dependencies {
implementation(libs.kotlinx.coroutines.android)
}

jvmMain.dependencies {
implementation(libs.kotlinx.coroutines.swing)
implementation(libs.kotlinx.coroutines.test)
}

jsMain.dependencies {
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ kotlin.code.style=official
kotlin.daemon.jvmargs=-Xmx4G
kotlin.native.binary.gc=cms
kotlin.incremental.wasm=true
kotlin.native.ignoreDisabledTargets=true

#Android
android.useAndroidX=true
Expand Down
28 changes: 15 additions & 13 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
[versions]
version = "0.2.1"
version = "0.2.2"

kotlin = "2.3.20"
agp = "9.0.1"
kotlin = "2.4.0"
agp = "9.2.1"
maven-publish = "0.36.0"
compose = "1.10.3"
kotlinx-coroutines = "1.10.2"
kotlinx-serialization = "1.10.0"
compose = "1.11.1"
compose-material3 = "1.9.0"
compose-material-icons = "1.7.3"
kotlinx-coroutines = "1.11.0"
kotlinx-serialization = "1.11.0"
androidx-activityCompose = "1.13.0"
ktlint-plugin = "14.2.0"
binary-compatibility-validator = "0.18.1"
kotest = "6.1.9"
kotest = "6.1.11"

[libraries]

kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" }
compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose" }
compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose" }
compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "compose" }
compose-material = { module = "org.jetbrains.compose.material:material", version.ref = "compose" }
compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "compose-material3" }
compose-materialIconsExtended = { module = "org.jetbrains.compose.material:material-icons-extended", version.ref = "compose-material-icons" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
androidx-activityCompose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
Expand All @@ -29,12 +34,9 @@ bcv-gradle-plugin = { module = "org.jetbrains.kotlinx:binary-compatibility-valid
[plugins]

multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
android-library = { id = "com.android.library", version.ref = "agp" }
maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "maven-publish" }
compose = { id = "org.jetbrains.compose", version.ref = "compose" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
android-application = { id = "com.android.application", version.ref = "agp" }
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-plugin" }
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
android-kmp-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
31 changes: 28 additions & 3 deletions kotlin-js-store/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2870,7 +2870,16 @@ streamroller@^3.1.5:
debug "^4.3.4"
fs-extra "^8.1.0"

"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -2902,7 +2911,14 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand Down Expand Up @@ -3245,7 +3261,16 @@ workerpool@^9.2.0:
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-9.3.4.tgz#f6c92395b2141afd78e2a889e80cb338fe9fca41"
integrity sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==

"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
Expand Down
2 changes: 1 addition & 1 deletion sample/androidApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {

android {
namespace = "org.kimplify.deci.sample"
compileSdk = 36
compileSdk = 37

defaultConfig {
minSdk = 24
Expand Down
33 changes: 14 additions & 19 deletions sample/composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,22 @@ plugins {
kotlin {
jvmToolchain(21)

androidLibrary {
android {
namespace = "org.kimplify.deci.sample.shared"
compileSdk = 36
compileSdk = 37
minSdk = 24
}
jvm()
js(IR) {
js {
outputModuleName.set("composeApp-js")
browser {
val rootDirPath = project.rootDir.path
val projectDirPath = project.projectDir.path
commonWebpackConfig {
outputFileName = "composeApp-js.js"
devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply {
static = (static ?: mutableListOf()).apply {
add(rootDirPath)
add(projectDirPath)
}
static(rootDirPath)
static(projectDirPath)
}
}
runTask {
Expand All @@ -49,17 +47,14 @@ kotlin {
commonWebpackConfig {
outputFileName = "composeApp.js"
devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply {
static = (static ?: mutableListOf()).apply {
add(rootDirPath)
add(projectDirPath)
}
static(rootDirPath)
static(projectDirPath)
}
}
}
binaries.executable()
}
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
Expand All @@ -71,12 +66,12 @@ kotlin {

sourceSets {
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.ui)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.material3)
implementation(compose.materialIconsExtended)
implementation(libs.compose.runtime)
implementation(libs.compose.ui)
implementation(libs.compose.foundation)
implementation(libs.compose.material)
implementation(libs.compose.material3)
implementation(libs.compose.materialIconsExtended)
implementation(project(":deci"))
implementation(libs.kotlinx.serialization.json)
}
Expand All @@ -101,4 +96,4 @@ compose.desktop {
vendor = "Kimplify"
}
}
}
}
Loading