mirror of
https://github.com/AdrianKuta/Tree-Data-Structure.git
synced 2026-06-19 19:00:14 +02:00
Release 4.1.1: publish on macOS to restore Apple/iOS artifacts
This commit is contained in:
5
.github/workflows/publishRelease.yml
vendored
5
.github/workflows/publishRelease.yml
vendored
@@ -16,7 +16,10 @@ jobs:
|
|||||||
needs: test
|
needs: test
|
||||||
name: Publish Production
|
name: Publish Production
|
||||||
environment: production
|
environment: production
|
||||||
runs-on: ubuntu-latest
|
# MUST be macOS: Kotlin/Native Apple targets (iosArm64/iosX64/iosSimulatorArm64) can only be
|
||||||
|
# built on a macOS host. On a Linux runner those tasks are silently skipped, so the iOS klibs
|
||||||
|
# never get uploaded (the build still goes green) — exactly what happened for 3.1.5–4.1.0.
|
||||||
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|||||||
11
CHANGELOG.md
11
CHANGELOG.md
@@ -6,6 +6,14 @@ All notable changes to this project are documented here. The format is based on
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [4.1.1] - 2026-06-08
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Restored the Apple/iOS artifacts (`iosArm64`, `iosX64`, `iosSimulatorArm64`) for the core and every
|
||||||
|
module. The release workflow published from a Linux runner, which cannot build Kotlin/Native Apple
|
||||||
|
targets, so they were silently omitted from 3.1.5–4.1.0; publishing now runs on macOS. No API or
|
||||||
|
behavior changes from 4.1.0 — this is a packaging fix only.
|
||||||
|
|
||||||
## [4.1.0] - 2026-06-07
|
## [4.1.0] - 2026-06-07
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -91,7 +99,8 @@ A breaking release that cleans up the core API and enforces an explicit public s
|
|||||||
## [3.1.3]
|
## [3.1.3]
|
||||||
- iOS targets and Maven Central (Sonatype Central Portal) publishing.
|
- iOS targets and Maven Central (Sonatype Central Portal) publishing.
|
||||||
|
|
||||||
[Unreleased]: https://github.com/AdrianKuta/Tree-Data-Structure/compare/v4.1.0...HEAD
|
[Unreleased]: https://github.com/AdrianKuta/Tree-Data-Structure/compare/v4.1.1...HEAD
|
||||||
|
[4.1.1]: https://github.com/AdrianKuta/Tree-Data-Structure/compare/v4.1.0...v4.1.1
|
||||||
[4.1.0]: https://github.com/AdrianKuta/Tree-Data-Structure/compare/v4.0.0...v4.1.0
|
[4.1.0]: https://github.com/AdrianKuta/Tree-Data-Structure/compare/v4.0.0...v4.1.0
|
||||||
[4.0.0]: https://github.com/AdrianKuta/Tree-Data-Structure/compare/v3.4.0...v4.0.0
|
[4.0.0]: https://github.com/AdrianKuta/Tree-Data-Structure/compare/v3.4.0...v4.0.0
|
||||||
[3.4.0]: https://github.com/AdrianKuta/Tree-Data-Structure/compare/v3.1.5...v3.4.0
|
[3.4.0]: https://github.com/AdrianKuta/Tree-Data-Structure/compare/v3.1.5...v3.4.0
|
||||||
|
|||||||
14
README.md
14
README.md
@@ -30,14 +30,14 @@ Gradle (Kotlin DSL):
|
|||||||
```kotlin
|
```kotlin
|
||||||
// commonMain for KMP projects, or any sourceSet/module where you need it
|
// commonMain for KMP projects, or any sourceSet/module where you need it
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("com.github.adriankuta:tree-structure:4.1.0") // latest version is on the badge above
|
implementation("com.github.adriankuta:tree-structure:4.1.1") // latest version is on the badge above
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Gradle (Groovy):
|
Gradle (Groovy):
|
||||||
```groovy
|
```groovy
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "com.github.adriankuta:tree-structure:4.1.0"
|
implementation "com.github.adriankuta:tree-structure:4.1.1"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ Maven:
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.adriankuta</groupId>
|
<groupId>com.github.adriankuta</groupId>
|
||||||
<artifactId>tree-structure</artifactId>
|
<artifactId>tree-structure</artifactId>
|
||||||
<version>4.1.0</version>
|
<version>4.1.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ that depends on the core.
|
|||||||
`@Serializable` directly. Convert to and from the acyclic `TreeNodeDto` instead.
|
`@Serializable` directly. Convert to and from the acyclic `TreeNodeDto` instead.
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
implementation("com.github.adriankuta:tree-structure-serialization:4.1.0")
|
implementation("com.github.adriankuta:tree-structure-serialization:4.1.1")
|
||||||
```
|
```
|
||||||
```kotlin
|
```kotlin
|
||||||
val json = Json.encodeToString(root.toDto())
|
val json = Json.encodeToString(root.toDto())
|
||||||
@@ -172,7 +172,7 @@ val restored = Json.decodeFromString<TreeNodeDto<String>>(json).toTreeNode()
|
|||||||
Traverse a tree as a cold `Flow`, which is handy inside coroutine and `ViewModel` pipelines.
|
Traverse a tree as a cold `Flow`, which is handy inside coroutine and `ViewModel` pipelines.
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
implementation("com.github.adriankuta:tree-structure-coroutines:4.1.0")
|
implementation("com.github.adriankuta:tree-structure-coroutines:4.1.1")
|
||||||
```
|
```
|
||||||
```kotlin
|
```kotlin
|
||||||
root.preOrderFlow().collect { println(it.value) }
|
root.preOrderFlow().collect { println(it.value) }
|
||||||
@@ -185,7 +185,7 @@ A `LazyTree` composable for Compose Multiplatform (JVM/desktop, iOS, Wasm). Only
|
|||||||
are composed, and you decide how each node looks:
|
are composed, and you decide how each node looks:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
implementation("com.github.adriankuta:tree-structure-compose:4.1.0")
|
implementation("com.github.adriankuta:tree-structure-compose:4.1.1")
|
||||||
```
|
```
|
||||||
```kotlin
|
```kotlin
|
||||||
LazyTree(root) { node, depth, expanded, toggle ->
|
LazyTree(root) { node, depth, expanded, toggle ->
|
||||||
@@ -204,7 +204,7 @@ subtrees are reused, so updates are cheap and old roots stay valid. Backed by
|
|||||||
`kotlinx.collections.immutable`.
|
`kotlinx.collections.immutable`.
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
implementation("com.github.adriankuta:tree-structure-immutable:4.1.0")
|
implementation("com.github.adriankuta:tree-structure-immutable:4.1.1")
|
||||||
```
|
```
|
||||||
```kotlin
|
```kotlin
|
||||||
val root = ImmutableTreeNode("World").addChild(ImmutableTreeNode("Europe"))
|
val root = ImmutableTreeNode("World").addChild(ImmutableTreeNode("Europe"))
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ plugins {
|
|||||||
|
|
||||||
val PUBLISH_GROUP_ID = "com.github.adriankuta"
|
val PUBLISH_GROUP_ID = "com.github.adriankuta"
|
||||||
val PUBLISH_ARTIFACT_ID = "tree-structure" // base artifact; KMP will add -jvm, -ios*, etc.
|
val PUBLISH_ARTIFACT_ID = "tree-structure" // base artifact; KMP will add -jvm, -ios*, etc.
|
||||||
val PUBLISH_VERSION = "4.1.0"
|
val PUBLISH_VERSION = "4.1.1"
|
||||||
|
|
||||||
val snapshot: String? by project
|
val snapshot: String? by project
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
# Design — four additive enhancements to `tree-structure` (target 4.1.0)
|
||||||
|
|
||||||
|
Date: 2026-06-07. Source issues: #34, #35, #36, #33. Integration: **four separate PRs**,
|
||||||
|
one per issue (`Closes #NN`), matching the repo's per-issue PR convention (#32).
|
||||||
|
|
||||||
|
## Shared rules (every issue)
|
||||||
|
|
||||||
|
- `explicitApi()` is on everywhere → every new public declaration is `public` with KDoc.
|
||||||
|
- New tests live in `commonTest`, use `kotlin("test")`, and mirror the existing test style
|
||||||
|
(`TreeNodeV4Test.kt`, `TreeNodeNavigationTest.kt`, …).
|
||||||
|
- Add a bullet to `CHANGELOG.md` under `## [Unreleased]` → `### Added` (do **not** bump
|
||||||
|
`PUBLISH_VERSION`; releases are a separate manual step).
|
||||||
|
- Regenerate the binary-compatibility baseline with `./gradlew apiDump`; verify with `apiCheck`.
|
||||||
|
- Do not modify the core public surface in a breaking way — these are additive only.
|
||||||
|
|
||||||
|
## #34 — Structural mutation helpers → **members on `TreeNode`**
|
||||||
|
|
||||||
|
Members (not extensions) because they need the private `_children`/`_parent` and the cycle/parent
|
||||||
|
validation.
|
||||||
|
|
||||||
|
- Extract the existing inline validation from `addChild` into a private
|
||||||
|
`validateAttachable(child)` and reuse it.
|
||||||
|
- `insertChild(index: Int, child)` — validated insert at index (bounds `0.._children.size`).
|
||||||
|
- `removeChildAt(index: Int): TreeNode<T>` — remove and return the detached child.
|
||||||
|
- `replaceChild(index: Int, child): TreeNode<T>` — swap, return the old (now detached) child.
|
||||||
|
- `moveChild(child, toIndex): Boolean` — reorder an existing direct child; no re-parent/cycle
|
||||||
|
check needed (it is already a child); `false` if `child` is not a direct child.
|
||||||
|
- `addChildren(vararg children)` — validated append of several (per-child `addChild` semantics).
|
||||||
|
- `sortChildren(comparator: Comparator<TreeNode<T>>)` — stable in-place reorder.
|
||||||
|
|
||||||
|
## #35 — Query algorithms → **extensions** in new `TreeNodeQueryExt.kt`
|
||||||
|
|
||||||
|
Built on the public API (`ancestors()`, `parent`, `depth()`, sequences). Return `null` when the
|
||||||
|
two nodes are unrelated (different trees).
|
||||||
|
|
||||||
|
- `lowestCommonAncestor(other): TreeNode<T>?` — deepest common node; includes self/other as
|
||||||
|
candidates (`LCA(a, a) == a`, `LCA(a, descendantOfA) == a`).
|
||||||
|
- `distance(other): Int?` — `depth(this) + depth(other) - 2 * depth(lca)`.
|
||||||
|
- `pathBetween(other): List<TreeNode<T>>?` — `[this … lca … other]`.
|
||||||
|
- `contains(value): Boolean` — value search over the subtree, including the receiver.
|
||||||
|
|
||||||
|
Document complexity (parent-walk based; O(depth) for LCA/distance, O(n) for `contains`).
|
||||||
|
|
||||||
|
## #36 — Customizable `prettyString()` → **extension** in new `TreeNodePrettyPrintExt.kt`
|
||||||
|
|
||||||
|
- `data class TreeConnectors(branch, lastBranch, vertical, empty)` with a `companion`:
|
||||||
|
`Default` (current Unicode box-drawing) and `Ascii`.
|
||||||
|
- `fun TreeNode<T>.prettyString(connectors = TreeConnectors.Default,
|
||||||
|
render: (value: T, depth: Int, isLast: Boolean) -> String = { v, _, _ -> v.toString() }): String`.
|
||||||
|
- The no-arg member `prettyString()` is unchanged; member resolution wins for `node.prettyString()`,
|
||||||
|
so existing behaviour and output are byte-for-byte identical.
|
||||||
|
|
||||||
|
## #33 — Immutable variant → **new module `:tree-structure-immutable`**
|
||||||
|
|
||||||
|
Largest item; fully isolated from the other three except for `settings.gradle.kts`,
|
||||||
|
`libs.versions.toml`, the root `build.gradle.kts` Dokka aggregation block, and `CHANGELOG.md`.
|
||||||
|
|
||||||
|
- `settings.gradle.kts`: `include(":tree-structure-immutable")`.
|
||||||
|
- New `build.gradle.kts` mirroring the serialization module's KMP target matrix; deps
|
||||||
|
`api(project(":"))` + `kotlinx-collections-immutable`.
|
||||||
|
- `libs.versions.toml`: add `kotlinx-collections-immutable` (a recent stable, e.g. 0.3.8) and
|
||||||
|
wire it.
|
||||||
|
- Root `build.gradle.kts`: add `dokka(project(":tree-structure-immutable"))` to the aggregation.
|
||||||
|
- `ImmutableTreeNode<T>` backed by `persistentListOf` children; `addChild` / `removeChild` /
|
||||||
|
`mapValues` return a new root with unchanged subtrees structurally shared. Mirror pre/post/
|
||||||
|
level-order traversal helpers.
|
||||||
|
- Its own `tree-structure-immutable/api/` baseline via `apiDump`.
|
||||||
|
|
||||||
|
## Orchestration
|
||||||
|
|
||||||
|
- Four git worktrees off `origin/master`, one branch each (`feat/...`), for full isolation — no
|
||||||
|
collisions on `TreeNode.kt`, `api/*.api`, or `CHANGELOG.md`.
|
||||||
|
- A workflow pipelines each issue: implement (code + KDoc + tests + CHANGELOG + `apiDump`) and
|
||||||
|
verify locally (`jvmTest` + `apiCheck`), then an adversarial reviewer checks issue-conformance,
|
||||||
|
test quality, invariants, explicit API, `.api` freshness, and that it builds. Local checks are
|
||||||
|
JVM-only for speed; CI validates the full KMP matrix on each PR.
|
||||||
|
- Then push each passing branch and open a PR (`Closes #NN`); remove the worktrees afterward.
|
||||||
Reference in New Issue
Block a user