6 Commits

Author SHA1 Message Date
Adrian Kuta
bec1fe02a7 feat: tree-structure-compose (LazyTree) + O(n) addChild cycle check
- New published module tree-structure-compose: a LazyTree composable for Compose
  Multiplatform (JVM/desktop, iOS, Wasm) with lazy rendering and expand/collapse.
- Fix an O(n^2) regression in addChild(): only walk ancestors for cycle detection
  when the child already has a subtree (a fresh leaf can never form a cycle), so
  building deep trees is O(n) again. Caught by the deep-chain stack-safety test on JS.
- README: Compose usage section; align all install snippets to 4.0.0.
- Version catalog: Compose Multiplatform + compose-compiler plugins.

Verified locally: JVM, JS(node), Wasm(node), iOS-simulator tests + apiCheck all green;
Compose module compiles for JVM, Wasm and iOS.
2026-06-07 18:55:07 +02:00
Adrian Kuta
69d19f89e3 feat!: v4.0 breaking API cleanup + explicitApi
BREAKING changes to the core:
- treeIterator is now a read-only `val`; added `iterator(order)` and use `asSequence(order)`.
- removeChild() only removes a direct child of the receiver; added `detach()` to unhook a node.
- addChild() rejects re-parenting and cycles (throws TreeNodeException); detach() first to move.
- clear() no longer nulls the receiver's own parent; only removes descendants.
- path() returns List<TreeNode<T>>? (null) instead of throwing.

Also:
- Enable strict explicitApi() across core + both modules; add explicit `public` modifiers.
- Update tests for the new contracts + add TreeNodeV4Test; refresh .api baselines.
- README + CHANGELOG (with migration notes); bump version to 4.0.0.

47 JVM tests green.
2026-06-07 18:47:40 +02:00
Adrian Kuta
c9bbea59b0 ci: binary-compat API baselines, multiplatform matrix CI, module docs
- Commit binary-compatibility-validator .api baselines for core + both modules.
- Replace JVM-only CI with a matrix: Ubuntu runs JVM/JS(node)/Wasm(node)/Native
  + apiCheck; macOS runs the iOS simulator tests.
- README: install + usage for tree-structure-serialization and -coroutines.
- Update kotlin-js-store/yarn.lock for the new modules' JS test deps.

Verified locally: JVM, JS(node), Wasm(node) and iOS-simulator tests pass for
core + both modules; native compiles & links (exec runs on the Linux CI runner).
2026-06-06 13:51:22 +02:00
Adrian Kuta
e1f01c4e2d feat: Kotlin 2.x/K2, version catalog, serialization & coroutines modules, docs
v3.4 modernization (continued):

- Migrate to Kotlin 2.x (K2); introduce gradle/libs.versions.toml version catalog;
  simplify the JS/Wasm/Node and iOS source-set wiring for the K2 hierarchy template.
- Apply binary-compatibility-validator and Kover plugins.
- New published module tree-structure-serialization: @Serializable TreeNodeDto with
  toDto()/toTreeNode() round-trip (kotlinx.serialization).
- New published module tree-structure-coroutines: asFlow()/pre/post/levelOrderFlow()
  (kotlinx.coroutines Flow traversal).
- Docs: README examples for Sequence/navigation/functional APIs, class-level KDoc
  (thread-safety/complexity), and a CHANGELOG.md.
- Ignore subproject build/ directories.
- Bump version to 3.4.0.

All JVM tests green (core + both modules).
2026-06-06 13:47:20 +02:00
Adrian Kuta
c45c5b7afa feat: stack-safe traversal + lazy Sequence + navigation/functional extensions
Core additive work for v3.4 (non-breaking):

- Rewrite nodeCount(), height(), clear() and the post-order iterator iteratively
  so deep/degenerate trees no longer throw StackOverflowError (verified to 50k deep).
- Add lazy Sequence traversal: asSequence(order), pre/post/levelOrderSequence().
- Add navigation extensions: isLeaf, degree, root(), ancestors(), siblings(),
  leaves(), descendants().
- Add functional extensions: findNode, filterNodes, anyNode, allNodes, countNodes,
  foldNodes, mapValues, deepCopy, structurallyEquals (all stack-safe).
- Add tests for stack-safety, the new APIs, and previously-uncovered
  height/depth/nodeCount/path (incl. exception paths). 40 tests green on JVM.
2026-06-06 13:35:39 +02:00
Adrian Kuta
6de95f7976 Release 3.1.5: remove debug println, drop worksheet leftover, modernize CI
- Remove stray println(child.value) from TreeNode.removeChild()
- Add regression test for removeChild() return value
- Delete leftover ExampleUnitTest.kt template test
- Remove Example.ws.kts worksheet and kotlin("script-runtime") from jvmMain
- Bump actions/checkout v2 -> v4 in CI workflows
- Update README install snippets to 3.1.5
- Bump version to 3.1.5
2026-06-06 13:03:00 +02:00
42 changed files with 1843 additions and 469 deletions

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v2 uses: actions/checkout@v4
- name: Set up JDK 21 - name: Set up JDK 21
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:

View File

@@ -6,18 +6,26 @@ on:
workflow_call: workflow_call:
jobs: jobs:
build: test:
name: Run unit tests name: ${{ matrix.name }}
runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: JVM / JS / Wasm / Native + API check
os: ubuntu-latest
tasks: jvmTest jsNodeTest wasmJsNodeTest nativeTest apiCheck
- name: iOS
os: macos-latest
tasks: iosSimulatorArm64Test
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v2 uses: actions/checkout@v4
- name: Set up JDK 21 - name: Set up JDK 21
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: temurin distribution: temurin
java-version: '21' java-version: '21'
# Builds the release artifacts of the library
- name: Test - name: Test
run: ./gradlew cleanJvmTest jvmTest run: ./gradlew ${{ matrix.tasks }} --console=plain

1
.gitignore vendored
View File

@@ -9,6 +9,7 @@
/.idea/assetWizardSettings.xml /.idea/assetWizardSettings.xml
.DS_Store .DS_Store
/build /build
build/
/captures /captures
.externalNativeBuild .externalNativeBuild
.cxx .cxx

79
CHANGELOG.md Normal file
View File

@@ -0,0 +1,79 @@
# Changelog
All notable changes to this project are documented here. The format is based on
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [4.0.0]
A breaking release that cleans up the core API and enforces an explicit public surface.
### Changed (breaking)
- `TreeNode.treeIterator` is now a read-only `val` (set it via the constructor). Use
`iterator(order)` or `asSequence(order)` to traverse in a different order per call.
- `removeChild(child)` now only removes a **direct** child of the receiver (previously it removed
the node from its actual parent regardless). Use `child.detach()` to unhook a node from wherever
it lives.
- `addChild(child)` now throws `TreeNodeException` if `child` already has a parent or if the
attachment would create a cycle. Call `detach()` first to move a node.
- `clear()` no longer detaches the receiver from its own parent; it only removes its descendants.
- `path(descendant)` now returns `List<TreeNode<T>>?` (`null` when `descendant` is the root or not a
descendant) instead of throwing `TreeNodeException`.
### Added
- `TreeNode.detach()` — removes a node from its parent.
- `TreeNode.iterator(order)` — a one-shot iterator in a specific order.
- Strict `explicitApi()` mode across all modules.
- New `tree-structure-compose` module: a `LazyTree` composable for Compose Multiplatform.
### Migration
- `node.treeIterator = PostOrder; for (n in node) { … }``for (n in node.asSequence(PostOrder)) { … }`
- `root.removeChild(deepNode)``deepNode.detach()`
- `try { node.path(x) } catch (e: TreeNodeException) { … }``node.path(x)?.let { … }`
## [3.4.0]
### Added
- Lazy `Sequence` traversal: `asSequence(order)`, `preOrderSequence()`, `postOrderSequence()`,
`levelOrderSequence()` — composes with the Kotlin stdlib and short-circuits.
- Navigation extensions: `isLeaf`, `degree`, `root()`, `ancestors()`, `siblings()`, `leaves()`,
`descendants()`.
- Functional extensions: `findNode`, `filterNodes`, `anyNode`, `allNodes`, `countNodes`,
`foldNodes`, `mapValues`, `deepCopy`, `structurallyEquals` (all stack-safe).
- New optional modules published as separate artifacts:
- `tree-structure-serialization``kotlinx.serialization` support via a `TreeNodeDto`.
- `tree-structure-coroutines``Flow` traversal (`asFlow`, `preOrderFlow`, …).
- `CHANGELOG.md`, expanded README examples, and class-level KDoc (thread-safety / complexity).
### Changed
- `nodeCount()`, `height()`, `clear()` and the post-order iterator are now iterative — deep or
degenerate (linear) trees no longer throw `StackOverflowError`.
- Migrated to Kotlin 2.x (K2 compiler) and introduced a Gradle version catalog.
- Build now uses `binary-compatibility-validator` (committed `.api` baselines) and Kover.
## [3.1.5]
### Fixed
- Removed a stray `println` in `TreeNode.removeChild()` that printed to stdout on every removal.
### Removed
- Deleted the `Example.ws.kts` worksheet and the `kotlin("script-runtime")` dependency from the
published JVM artifact, plus the leftover `ExampleUnitTest` template test.
### Changed
- Bumped `actions/checkout` v2 → v4 in CI workflows.
## [3.1.4]
- Updated Kotlin and JS dependencies; added the `wasmJs` target.
## [3.1.3]
- iOS targets and Maven Central (Sonatype Central Portal) publishing.
[Unreleased]: https://github.com/AdrianKuta/Tree-Data-Structure/compare/v4.0.0...HEAD
[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.1.5]: https://github.com/AdrianKuta/Tree-Data-Structure/compare/v3.1.3...v3.1.5
[3.1.4]: https://github.com/AdrianKuta/Tree-Data-Structure/releases/tag/v3.1.4
[3.1.3]: https://github.com/AdrianKuta/Tree-Data-Structure/releases/tag/v3.1.3

122
README.md
View File

@@ -5,8 +5,12 @@
Lightweight Kotlin Multiplatform tree data structure for Kotlin and Java. Includes a small DSL, multiple traversal iterators, and pretty-print support. Lightweight Kotlin Multiplatform tree data structure for Kotlin and Java. Includes a small DSL, multiple traversal iterators, and pretty-print support.
- Kotlin Multiplatform (JVM, JS, iOS, and Native host) - Kotlin Multiplatform (JVM, JS, Wasm, iOS, and Native host)
- Pre-order, Post-order, and Level-order iteration - Pre-order, Post-order, and Level-order iteration
- Lazy `Sequence` traversal that composes with the Kotlin stdlib (`map`/`filter`/`firstOrNull`…)
- Navigation helpers: `root()`, `ancestors()`, `siblings()`, `leaves()`, `descendants()`, `isLeaf`, `degree`
- Functional helpers: `findNode`, `filterNodes`, `anyNode`, `allNodes`, `foldNodes`, `mapValues`, `deepCopy`, `structurallyEquals`
- Stack-safe: traversal and `height()`/`nodeCount()`/`clear()` handle arbitrarily deep trees without `StackOverflowError`
- Simple DSL: tree { child(...) } - Simple DSL: tree { child(...) }
- Utilities: nodeCount(), height(), depth(), path(), prettyString(), clear(), removeChild() - Utilities: nodeCount(), height(), depth(), path(), prettyString(), clear(), removeChild()
@@ -16,14 +20,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:3.1.1") // see badge above for the latest version implementation("com.github.adriankuta:tree-structure:4.0.0") // see badge above for the latest version
} }
``` ```
Gradle (Groovy): Gradle (Groovy):
```groovy ```groovy
dependencies { dependencies {
implementation "com.github.adriankuta:tree-structure:3.1.1" // see badge above for the latest implementation "com.github.adriankuta:tree-structure:4.0.0" // see badge above for the latest
} }
``` ```
@@ -32,7 +36,7 @@ Maven:
<dependency> <dependency>
<groupId>com.github.adriankuta</groupId> <groupId>com.github.adriankuta</groupId>
<artifactId>tree-structure</artifactId> <artifactId>tree-structure</artifactId>
<version>3.1.1</version> <version>4.0.0</version>
</dependency> </dependency>
``` ```
@@ -100,9 +104,8 @@ World
val root = TreeNode("root") val root = TreeNode("root")
// ... build your tree // ... build your tree
// Choose iteration order (default is PreOrder) // Choose iteration order per call (the default order is set in the constructor and is read-only)
root.treeIterator = TreeNodeIterators.PostOrder for (node in root.asSequence(TreeNodeIterators.PostOrder)) println(node.value)
for (node in root) println(node.value)
// Utilities // Utilities
root.nodeCount() // number of descendants root.nodeCount() // number of descendants
@@ -110,10 +113,109 @@ root.height() // longest path to a leaf (in edges)
root.depth() // distance from current node to the root root.depth() // distance from current node to the root
val path = root.path(root.children.first()) // nodes from descendant up to root val path = root.path(root.children.first()) // nodes from descendant up to root
// Mutations // Mutations — removeChild removes a *direct* child; detach() unhooks a node from wherever it lives
val child = root.children.first() val child = root.children.first()
root.removeChild(child) root.removeChild(child) // child is now detached from root
root.clear() // remove entire subtree root.clear() // remove all descendants of root
```
### Lazy traversal with Sequence
Traversal is exposed as a lazy `Sequence`, so it composes with the Kotlin standard library and
short-circuits (it never materializes the whole tree just to find one node):
```kotlin
val tree = tree("World") {
child("North America") { child("USA") }
child("Europe") {
child("Poland")
child("Germany")
}
}
// Pick an order explicitly — no need to mutate the node's state.
tree.preOrderSequence().map { it.value }.toList() // [World, North America, USA, Europe, Poland, Germany]
tree.levelOrderSequence().first { it.value == "USA" } // stops as soon as it's found
tree.asSequence(TreeNodeIterators.PostOrder).count() // 6
```
### Navigation
```kotlin
val usa = tree.findNode { it == "USA" }!!
usa.isLeaf // true
usa.depth() // 2
usa.root().value // "World"
usa.ancestors().map { it.value } // [North America, World]
tree.leaves().map { it.value } // [USA, Poland, Germany]
val europe = tree.findNode { it == "Europe" }!!
europe.children.first().siblings().map { it.value } // [Germany]
```
### Functional operations
```kotlin
tree.anyNode { it == "Poland" } // true
tree.filterNodes { it.length > 5 } // nodes whose value is longer than 5 chars
tree.countNodes { it.startsWith("U") } // 1
// Transform values into a brand-new tree (the original is untouched); stack-safe.
val lengths: TreeNode<Int> = tree.mapValues { it.length }
// Deep copy + structural comparison.
val copy = tree.deepCopy()
tree.structurallyEquals(copy) // true (same values, same shape, different nodes)
```
## Optional modules
The core `tree-structure` artifact has no third-party dependencies. Ecosystem integrations ship as
separate, opt-in artifacts that depend on the core.
### Serialization — `tree-structure-serialization`
`kotlinx.serialization` support. A `TreeNode` holds a parent back-reference (a cycle), so it cannot
be `@Serializable` directly — convert to/from the acyclic `TreeNodeDto` instead.
```kotlin
implementation("com.github.adriankuta:tree-structure-serialization:4.0.0")
```
```kotlin
val json = Json.encodeToString(tree.toDto())
val restored = Json.decodeFromString<TreeNodeDto<String>>(json).toTreeNode()
```
### Coroutines — `tree-structure-coroutines`
Traverse a tree as a cold `Flow` (handy in coroutine/`ViewModel` pipelines).
```kotlin
implementation("com.github.adriankuta:tree-structure-coroutines:4.0.0")
```
```kotlin
tree.preOrderFlow().collect { println(it.value) }
tree.asFlow(TreeNodeIterators.LevelOrder).map { it.value }
```
### Compose UI — `tree-structure-compose`
A `LazyTree` composable for Compose Multiplatform (JVM/desktop, iOS, Wasm). Only the visible nodes
are composed, and you decide how each node looks:
```kotlin
implementation("com.github.adriankuta:tree-structure-compose:4.0.0")
```
```kotlin
LazyTree(root) { node, depth, expanded, toggle ->
Row(Modifier.padding(start = (depth * 16).dp).clickable(onClick = toggle)) {
if (!node.isLeaf) Text(if (expanded) "" else "")
Text(node.value.toString())
}
}
``` ```
## Publishing to Maven Central (central.sonatype.com) ## Publishing to Maven Central (central.sonatype.com)

101
api/tree-structure.api Normal file
View File

@@ -0,0 +1,101 @@
public abstract interface class com/github/adriankuta/datastructure/tree/ChildDeclarationInterface {
public abstract synthetic fun child (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lcom/github/adriankuta/datastructure/tree/TreeNode;
}
public final class com/github/adriankuta/datastructure/tree/ChildDeclarationInterface$DefaultImpls {
public static synthetic fun child$default (Lcom/github/adriankuta/datastructure/tree/ChildDeclarationInterface;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/adriankuta/datastructure/tree/TreeNode;
}
public class com/github/adriankuta/datastructure/tree/TreeNode : com/github/adriankuta/datastructure/tree/ChildDeclarationInterface, java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker {
public fun <init> (Ljava/lang/Object;Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;)V
public synthetic fun <init> (Ljava/lang/Object;Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun addChild (Lcom/github/adriankuta/datastructure/tree/TreeNode;)V
public synthetic fun child (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lcom/github/adriankuta/datastructure/tree/TreeNode;
public final fun clear ()V
public final fun depth ()I
public final fun detach ()Z
public final fun getChildren ()Ljava/util/List;
public final fun getParent ()Lcom/github/adriankuta/datastructure/tree/TreeNode;
public final fun getTreeIterator ()Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;
public final fun getValue ()Ljava/lang/Object;
public final fun height ()I
public final fun isRoot ()Z
public fun iterator ()Ljava/util/Iterator;
public final fun iterator (Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;)Ljava/util/Iterator;
public final fun nodeCount ()I
public final fun path (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Ljava/util/List;
public final fun prettyString ()Ljava/lang/String;
public final fun removeChild (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Z
public fun toString ()Ljava/lang/String;
}
public final class com/github/adriankuta/datastructure/tree/TreeNodeFunctionalExtKt {
public static final fun allNodes (Lcom/github/adriankuta/datastructure/tree/TreeNode;Lkotlin/jvm/functions/Function1;)Z
public static final fun anyNode (Lcom/github/adriankuta/datastructure/tree/TreeNode;Lkotlin/jvm/functions/Function1;)Z
public static final fun countNodes (Lcom/github/adriankuta/datastructure/tree/TreeNode;Lkotlin/jvm/functions/Function1;)I
public static final fun deepCopy (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Lcom/github/adriankuta/datastructure/tree/TreeNode;
public static final fun filterNodes (Lcom/github/adriankuta/datastructure/tree/TreeNode;Lkotlin/jvm/functions/Function1;)Ljava/util/List;
public static final fun findNode (Lcom/github/adriankuta/datastructure/tree/TreeNode;Lkotlin/jvm/functions/Function1;)Lcom/github/adriankuta/datastructure/tree/TreeNode;
public static final fun foldNodes (Lcom/github/adriankuta/datastructure/tree/TreeNode;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public static final fun mapValues (Lcom/github/adriankuta/datastructure/tree/TreeNode;Lkotlin/jvm/functions/Function1;)Lcom/github/adriankuta/datastructure/tree/TreeNode;
public static final fun structurallyEquals (Lcom/github/adriankuta/datastructure/tree/TreeNode;Lcom/github/adriankuta/datastructure/tree/TreeNode;)Z
}
public final class com/github/adriankuta/datastructure/tree/TreeNodeNavigationExtKt {
public static final fun ancestors (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Ljava/util/List;
public static final fun descendants (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Ljava/util/List;
public static final fun getDegree (Lcom/github/adriankuta/datastructure/tree/TreeNode;)I
public static final fun isLeaf (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Z
public static final fun leaves (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Ljava/util/List;
public static final fun root (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Lcom/github/adriankuta/datastructure/tree/TreeNode;
public static final fun siblings (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Ljava/util/List;
}
public final class com/github/adriankuta/datastructure/tree/TreeNodeSequenceExtKt {
public static final fun asSequence (Lcom/github/adriankuta/datastructure/tree/TreeNode;Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;)Lkotlin/sequences/Sequence;
public static synthetic fun asSequence$default (Lcom/github/adriankuta/datastructure/tree/TreeNode;Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;ILjava/lang/Object;)Lkotlin/sequences/Sequence;
public static final fun levelOrderSequence (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Lkotlin/sequences/Sequence;
public static final fun postOrderSequence (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Lkotlin/sequences/Sequence;
public static final fun preOrderSequence (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Lkotlin/sequences/Sequence;
}
public final class com/github/adriankuta/datastructure/tree/exceptions/TreeNodeException : java/lang/RuntimeException {
public fun <init> ()V
public fun <init> (Ljava/lang/String;)V
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Throwable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
}
public final class com/github/adriankuta/datastructure/tree/iterators/LevelOrderTreeIterator : java/util/Iterator, kotlin/jvm/internal/markers/KMappedMarker {
public fun <init> (Lcom/github/adriankuta/datastructure/tree/TreeNode;)V
public fun hasNext ()Z
public fun next ()Lcom/github/adriankuta/datastructure/tree/TreeNode;
public synthetic fun next ()Ljava/lang/Object;
public fun remove ()V
}
public final class com/github/adriankuta/datastructure/tree/iterators/PostOrderTreeIterator : java/util/Iterator, kotlin/jvm/internal/markers/KMappedMarker {
public fun <init> (Lcom/github/adriankuta/datastructure/tree/TreeNode;)V
public fun hasNext ()Z
public fun next ()Lcom/github/adriankuta/datastructure/tree/TreeNode;
public synthetic fun next ()Ljava/lang/Object;
public fun remove ()V
}
public final class com/github/adriankuta/datastructure/tree/iterators/PreOrderTreeIterator : java/util/Iterator, kotlin/jvm/internal/markers/KMappedMarker {
public fun <init> (Lcom/github/adriankuta/datastructure/tree/TreeNode;)V
public fun hasNext ()Z
public fun next ()Lcom/github/adriankuta/datastructure/tree/TreeNode;
public synthetic fun next ()Ljava/lang/Object;
public fun remove ()V
}
public final class com/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators : java/lang/Enum {
public static final field LevelOrder Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;
public static final field PostOrder Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;
public static final field PreOrder Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;
public static fun getEntries ()Lkotlin/enums/EnumEntries;
public static fun valueOf (Ljava/lang/String;)Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;
public static fun values ()[Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;
}

View File

@@ -1,19 +1,17 @@
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinWasmTargetDsl
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
plugins { plugins {
kotlin("multiplatform") version "1.9.24" alias(libs.plugins.kotlinMultiplatform)
id("org.jetbrains.dokka") version "1.9.20" alias(libs.plugins.dokka)
id("com.vanniktech.maven.publish") version "0.34.0" alias(libs.plugins.mavenPublish)
alias(libs.plugins.binaryCompatibilityValidator)
alias(libs.plugins.kover)
signing signing
} }
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 = "3.1.4" val PUBLISH_VERSION = "4.0.0"
val snapshot: String? by project val snapshot: String? by project
@@ -29,7 +27,10 @@ mavenPublishing {
pom { pom {
name.set("Tree Data Structure") name.set("Tree Data Structure")
description.set("Simple implementation to store object in tree structure.") description.set(
"Lightweight n-ary tree data structure for Kotlin Multiplatform (JVM, JS, Wasm, iOS, " +
"Native). DSL, pre/post/level-order traversal, lazy Sequence traversal, and pretty-print.",
)
url.set("https://github.com/AdrianKuta/Tree-Data-Structure") url.set("https://github.com/AdrianKuta/Tree-Data-Structure")
licenses { licenses {
@@ -54,28 +55,16 @@ mavenPublishing {
} }
} }
// No legacy publishing {} block or s01 repos — Central Portal handles it.
repositories { repositories {
mavenCentral() mavenCentral()
} }
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
kotlin { kotlin {
jvmToolchain(21); explicitApi()
jvm { jvmToolchain(21)
compilations.all {
kotlinOptions { jvm()
jvmTarget = "21" // <- was "1.8"
}
}
}
// JS targets (IR) for publishing
js(IR) { js(IR) {
browser() browser()
nodejs() nodejs()
@@ -87,21 +76,7 @@ kotlin {
nodejs() nodejs()
} }
rootProject.plugins.withType<NodeJsRootPlugin> { // Apple targets
rootProject.extensions.getByType<NodeJsRootExtension>().nodeVersion = "22.0.0"
}
kotlin.targets.withType<KotlinJsIrTarget> {
if (name == "wasmJs") {
@Suppress("UNCHECKED_CAST")
(this as KotlinWasmTargetDsl).apply {
nodejs {
}
}
}
}
// iOS targets
iosX64() iosX64()
iosArm64() iosArm64()
iosSimulatorArm64() iosSimulatorArm64()
@@ -109,7 +84,7 @@ kotlin {
// Native host target // Native host target
val hostOs = System.getProperty("os.name") val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows") val isMingwX64 = hostOs.startsWith("Windows")
val nativeTarget = when { when {
hostOs == "Mac OS X" -> macosX64("native") hostOs == "Mac OS X" -> macosX64("native")
hostOs == "Linux" -> linuxX64("native") hostOs == "Linux" -> linuxX64("native")
isMingwX64 -> mingwX64("native") isMingwX64 -> mingwX64("native")
@@ -117,25 +92,8 @@ kotlin {
} }
sourceSets { sourceSets {
val commonMain by getting commonTest.dependencies {
val commonTest by getting { dependencies { implementation(kotlin("test")) } } implementation(kotlin("test"))
val jvmMain by getting { dependencies { implementation(kotlin("script-runtime")) } } }
val jvmTest by getting
val jsMain by getting
val jsTest by getting
val wasmJsMain by getting
val wasmJsTest by getting
val nativeMain by getting
val nativeTest by getting
// Shared iOS source sets
val iosMain by creating { dependsOn(commonMain) }
val iosTest by creating { dependsOn(commonTest) }
val iosX64Main by getting { dependsOn(iosMain) }
val iosArm64Main by getting { dependsOn(iosMain) }
val iosSimulatorArm64Main by getting { dependsOn(iosMain) }
val iosX64Test by getting { dependsOn(iosTest) }
val iosArm64Test by getting { dependsOn(iosTest) }
val iosSimulatorArm64Test by getting { dependsOn(iosTest) }
} }
} }

View File

@@ -1,2 +1 @@
kotlin.code.style=official kotlin.code.style=official
kotlin.js.compiler=ir

24
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,24 @@
[versions]
kotlin = "2.1.0"
dokka = "1.9.20"
mavenPublish = "0.34.0"
binaryCompatibilityValidator = "0.16.3"
kover = "0.8.3"
coroutines = "1.9.0"
kotlinxSerialization = "1.7.3"
composeMultiplatform = "1.7.3"
[plugins]
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
mavenPublish = { id = "com.vanniktech.maven.publish", version.ref = "mavenPublish" }
binaryCompatibilityValidator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binaryCompatibilityValidator" }
kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "composeMultiplatform" }
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
[libraries]
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerialization" }

View File

@@ -51,11 +51,6 @@
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
"@types/cookie@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
"@types/cors@^2.8.12": "@types/cors@^2.8.12":
version "2.8.13" version "2.8.13"
resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94" resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94"
@@ -63,33 +58,12 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/eslint-scope@^3.7.3": "@types/estree@^1.0.5":
version "3.7.4" version "1.0.9"
resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.9.tgz#cf3f0e876d7bee15a93ab925b82bf570a3904a24"
integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== integrity sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==
dependencies:
"@types/eslint" "*"
"@types/estree" "*"
"@types/eslint@*": "@types/json-schema@^7.0.8":
version "8.4.10"
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.10.tgz#19731b9685c19ed1552da7052b6f668ed7eb64bb"
integrity sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==
dependencies:
"@types/estree" "*"
"@types/json-schema" "*"
"@types/estree@*":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
"@types/estree@^1.0.0":
version "1.0.8"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e"
integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==
"@types/json-schema@*", "@types/json-schema@^7.0.8":
version "7.0.11" version "7.0.11"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
@@ -104,7 +78,14 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.15.tgz#de0e1fbd2b22b962d45971431e2ae696643d3f5d" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.15.tgz#de0e1fbd2b22b962d45971431e2ae696643d3f5d"
integrity sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw== integrity sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==
"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.11.5": "@types/ws@^8.5.12":
version "8.18.1"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.1.tgz#48464e4bf2ddfd17db13d845467f6070ffea4aa9"
integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==
dependencies:
"@types/node" "*"
"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.12.1":
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6"
integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ== integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==
@@ -170,7 +151,7 @@
resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz#917a20e93f71ad5602966c2d685ae0c6c21f60f1" resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz#917a20e93f71ad5602966c2d685ae0c6c21f60f1"
integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ== integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==
"@webassemblyjs/wasm-edit@^1.11.5": "@webassemblyjs/wasm-edit@^1.12.1":
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz#ac6689f502219b59198ddec42dcd496b1004d597" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz#ac6689f502219b59198ddec42dcd496b1004d597"
integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ== integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==
@@ -205,7 +186,7 @@
"@webassemblyjs/wasm-gen" "1.14.1" "@webassemblyjs/wasm-gen" "1.14.1"
"@webassemblyjs/wasm-parser" "1.14.1" "@webassemblyjs/wasm-parser" "1.14.1"
"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.11.5": "@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.12.1":
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz#b3e13f1893605ca78b52c68e54cf6a865f90b9fb" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz#b3e13f1893605ca78b52c68e54cf6a865f90b9fb"
integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ== integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==
@@ -225,17 +206,17 @@
"@webassemblyjs/ast" "1.14.1" "@webassemblyjs/ast" "1.14.1"
"@xtuc/long" "4.2.2" "@xtuc/long" "4.2.2"
"@webpack-cli/configtest@^2.1.0": "@webpack-cli/configtest@^2.1.1":
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646"
integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==
"@webpack-cli/info@^2.0.1": "@webpack-cli/info@^2.0.2":
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd"
integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==
"@webpack-cli/serve@^2.0.3": "@webpack-cli/serve@^2.0.5":
version "2.0.5" version "2.0.5"
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e"
integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==
@@ -250,11 +231,6 @@
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
abab@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
accepts@~1.3.4: accepts@~1.3.4:
version "1.3.8" version "1.3.8"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
@@ -263,10 +239,10 @@ accepts@~1.3.4:
mime-types "~2.1.34" mime-types "~2.1.34"
negotiator "0.6.3" negotiator "0.6.3"
acorn-import-assertions@^1.7.6: acorn-import-attributes@^1.9.5:
version "1.8.0" version "1.9.5"
resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef"
integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==
acorn@^8.15.0, acorn@^8.7.1: acorn@^8.15.0, acorn@^8.7.1:
version "8.15.0" version "8.15.0"
@@ -312,10 +288,10 @@ ajv@^8.0.0, ajv@^8.9.0:
json-schema-traverse "^1.0.0" json-schema-traverse "^1.0.0"
require-from-string "^2.0.2" require-from-string "^2.0.2"
ansi-colors@4.1.1: ansi-colors@^4.1.3:
version "4.1.1" version "4.1.3"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b"
integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==
ansi-regex@^5.0.1: ansi-regex@^5.0.1:
version "5.0.1" version "5.0.1"
@@ -352,6 +328,11 @@ base64id@2.0.0, base64id@~2.0.0:
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
baseline-browser-mapping@^2.10.12:
version "2.10.34"
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.34.tgz#dedb606362446777cfe328d30d4ee15056d06303"
integrity sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw==
binary-extensions@^2.0.0: binary-extensions@^2.0.0:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
@@ -390,6 +371,13 @@ brace-expansion@^2.0.1:
dependencies: dependencies:
balanced-match "^1.0.0" balanced-match "^1.0.0"
brace-expansion@^2.0.2:
version "2.1.1"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.1.tgz#c68b1c4111c76aae3a6fba55d496cee10c39dad8"
integrity sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==
dependencies:
balanced-match "^1.0.0"
braces@^3.0.2, braces@~3.0.2: braces@^3.0.2, braces@~3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
@@ -397,20 +385,21 @@ braces@^3.0.2, braces@~3.0.2:
dependencies: dependencies:
fill-range "^7.0.1" fill-range "^7.0.1"
browser-stdout@1.3.1: browser-stdout@^1.3.1:
version "1.3.1" version "1.3.1"
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
browserslist@^4.14.5: browserslist@^4.21.10:
version "4.21.4" version "4.28.2"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.2.tgz#f50b65362ef48974ca9f50b3680566d786b811d2"
integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== integrity sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==
dependencies: dependencies:
caniuse-lite "^1.0.30001400" baseline-browser-mapping "^2.10.12"
electron-to-chromium "^1.4.251" caniuse-lite "^1.0.30001782"
node-releases "^2.0.6" electron-to-chromium "^1.5.328"
update-browserslist-db "^1.0.9" node-releases "^2.0.36"
update-browserslist-db "^1.2.3"
buffer-from@^1.0.0: buffer-from@^1.0.0:
version "1.1.2" version "1.1.2"
@@ -435,10 +424,10 @@ camelcase@^6.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
caniuse-lite@^1.0.30001400: caniuse-lite@^1.0.30001782:
version "1.0.30001439" version "1.0.30001797"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz#ab7371faeb4adff4b74dad1718a6fd122e45d9cb" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz#1332709e1439f01ff92085dd17001e0a45897ec0"
integrity sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A== integrity sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==
chalk@^4.1.0: chalk@^4.1.0:
version "4.1.2" version "4.1.2"
@@ -448,7 +437,7 @@ chalk@^4.1.0:
ansi-styles "^4.1.0" ansi-styles "^4.1.0"
supports-color "^7.1.0" supports-color "^7.1.0"
chokidar@3.5.3, chokidar@^3.5.1: chokidar@^3.5.1:
version "3.5.3" version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
@@ -463,6 +452,21 @@ chokidar@3.5.3, chokidar@^3.5.1:
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" fsevents "~2.3.2"
chokidar@^3.5.3:
version "3.6.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
dependencies:
anymatch "~3.1.2"
braces "~3.0.2"
glob-parent "~5.1.2"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.6.0"
optionalDependencies:
fsevents "~2.3.2"
chrome-trace-event@^1.0.2: chrome-trace-event@^1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
@@ -533,10 +537,10 @@ content-type@~1.0.4:
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
cookie@~0.4.1: cookie@~0.7.2:
version "0.4.2" version "0.7.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
cors@~2.8.5: cors@~2.8.5:
version "2.8.5" version "2.8.5"
@@ -572,13 +576,20 @@ debug@2.6.9:
dependencies: dependencies:
ms "2.0.0" ms "2.0.0"
debug@4.3.4, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: debug@^4.3.4:
version "4.3.4" version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies: dependencies:
ms "2.1.2" ms "2.1.2"
debug@^4.3.5, debug@~4.4.1:
version "4.4.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
dependencies:
ms "^2.1.3"
decamelize@^4.0.0: decamelize@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
@@ -599,10 +610,10 @@ di@^0.0.1:
resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA== integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==
diff@5.0.0: diff@^5.2.0:
version "5.0.0" version "5.2.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.2.tgz#0a4742797281d09cfa699b79ea32d27723623bad"
integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== integrity sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==
dom-serialize@^2.2.1: dom-serialize@^2.2.1:
version "2.2.1" version "2.2.1"
@@ -619,10 +630,10 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
electron-to-chromium@^1.4.251: electron-to-chromium@^1.5.328:
version "1.4.284" version "1.5.368"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.368.tgz#8e8d4600c5f5f01e891f8f843b4a941afb640412"
integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== integrity sha512-7RckJJK4uESJF9PxvfMWd3TGqIiieUTG4HxnKaKuIpGbcr+r2ZEB3g2gAhCP3Fqm42vJSzLfgab9eva/C4/XVw==
emoji-regex@^8.0.0: emoji-regex@^8.0.0:
version "8.0.0" version "8.0.0"
@@ -634,34 +645,34 @@ encodeurl@~1.0.2:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
engine.io-parser@~5.0.3: engine.io-parser@~5.2.1:
version "5.0.4" version "5.2.3"
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz#00dc5b97b1f233a23c9398d0209504cf5f94d92f"
integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg== integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==
engine.io@~6.2.1: engine.io@~6.6.0:
version "6.2.1" version "6.6.8"
resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.2.1.tgz#e3f7826ebc4140db9bbaa9021ad6b1efb175878f" resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.6.8.tgz#52c43629964fb9d84bf991e0e34e3c28d4e0d3e0"
integrity sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA== integrity sha512-2agL3ueZhqxoVrfmntO8yuVj+uNSlIOnhykYHk3Cq0ShYPdUjjUiSJrQvXjq01I9jAuI0Zl2YO8Evv5Mqytm5g==
dependencies: dependencies:
"@types/cookie" "^0.4.1"
"@types/cors" "^2.8.12" "@types/cors" "^2.8.12"
"@types/node" ">=10.0.0" "@types/node" ">=10.0.0"
"@types/ws" "^8.5.12"
accepts "~1.3.4" accepts "~1.3.4"
base64id "2.0.0" base64id "2.0.0"
cookie "~0.4.1" cookie "~0.7.2"
cors "~2.8.5" cors "~2.8.5"
debug "~4.3.1" debug "~4.4.1"
engine.io-parser "~5.0.3" engine.io-parser "~5.2.1"
ws "~8.2.3" ws "~8.20.1"
enhanced-resolve@^5.13.0: enhanced-resolve@^5.17.1:
version "5.18.4" version "5.23.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz#c22d33055f3952035ce6a144ce092447c525f828" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.23.0.tgz#dfdf8d1c9065e4b52f8a598356138931c07305f9"
integrity sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q== integrity sha512-yJN/BOOLxcOW2aQgeif9mSnaUB8KtvmMMp56oA1kx1CRfBKbhZm2pJ+NBY+3eOboHxix8lfjWpHE0Ei5U8RbSA==
dependencies: dependencies:
graceful-fs "^4.2.4" graceful-fs "^4.2.4"
tapable "^2.2.0" tapable "^2.3.3"
ent@~2.2.0: ent@~2.2.0:
version "2.2.0" version "2.2.0"
@@ -683,12 +694,17 @@ escalade@^3.1.1:
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escalade@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
escape-html@~1.0.3: escape-html@~1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
escape-string-regexp@4.0.0: escape-string-regexp@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
@@ -773,14 +789,6 @@ finalhandler@1.1.2:
statuses "~1.5.0" statuses "~1.5.0"
unpipe "~1.0.0" unpipe "~1.0.0"
find-up@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
dependencies:
locate-path "^6.0.0"
path-exists "^4.0.0"
find-up@^4.0.0: find-up@^4.0.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
@@ -789,6 +797,14 @@ find-up@^4.0.0:
locate-path "^5.0.0" locate-path "^5.0.0"
path-exists "^4.0.0" path-exists "^4.0.0"
find-up@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
dependencies:
locate-path "^6.0.0"
path-exists "^4.0.0"
flat@^5.0.2: flat@^5.0.2:
version "5.0.2" version "5.0.2"
resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
@@ -864,18 +880,6 @@ glob-to-regexp@^0.4.1:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
glob@7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.1.3, glob@^7.1.7: glob@^7.1.3, glob@^7.1.7:
version "7.2.3" version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
@@ -888,12 +892,23 @@ glob@^7.1.3, glob@^7.1.7:
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: glob@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^5.0.1"
once "^1.3.0"
graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6:
version "4.2.10" version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
graceful-fs@^4.2.10: graceful-fs@^4.2.10, graceful-fs@^4.2.11:
version "4.2.11" version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
@@ -922,7 +937,7 @@ hasown@^2.0.2:
dependencies: dependencies:
function-bind "^1.1.2" function-bind "^1.1.2"
he@1.2.0: he@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
@@ -1064,10 +1079,10 @@ jest-worker@^27.4.5:
merge-stream "^2.0.0" merge-stream "^2.0.0"
supports-color "^8.0.0" supports-color "^8.0.0"
js-yaml@4.1.0: js-yaml@^4.1.0:
version "4.1.0" version "4.2.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.2.0.tgz#2bd9e85682dd91bd469afb809d816043b3d49524"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== integrity sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==
dependencies: dependencies:
argparse "^2.0.1" argparse "^2.0.1"
@@ -1114,19 +1129,19 @@ karma-sourcemap-loader@0.4.0:
dependencies: dependencies:
graceful-fs "^4.2.10" graceful-fs "^4.2.10"
karma-webpack@5.0.0: karma-webpack@5.0.1:
version "5.0.0" version "5.0.1"
resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.0.tgz#2a2c7b80163fe7ffd1010f83f5507f95ef39f840" resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.1.tgz#4eafd31bbe684a747a6e8f3e4ad373e53979ced4"
integrity sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA== integrity sha512-oo38O+P3W2mSPCSUrQdySSPv1LvPpXP+f+bBimNomS5sW+1V4SuhCuW8TfJzV+rDv921w2fDSDw0xJbPe6U+kQ==
dependencies: dependencies:
glob "^7.1.3" glob "^7.1.3"
minimatch "^3.0.4" minimatch "^9.0.3"
webpack-merge "^4.1.5" webpack-merge "^4.1.5"
karma@6.4.2: karma@6.4.4:
version "6.4.2" version "6.4.4"
resolved "https://registry.yarnpkg.com/karma/-/karma-6.4.2.tgz#a983f874cee6f35990c4b2dcc3d274653714de8e" resolved "https://registry.yarnpkg.com/karma/-/karma-6.4.4.tgz#dfa5a426cf5a8b53b43cd54ef0d0d09742351492"
integrity sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ== integrity sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==
dependencies: dependencies:
"@colors/colors" "1.5.0" "@colors/colors" "1.5.0"
body-parser "^1.19.0" body-parser "^1.19.0"
@@ -1147,7 +1162,7 @@ karma@6.4.2:
qjobs "^1.2.0" qjobs "^1.2.0"
range-parser "^1.2.1" range-parser "^1.2.1"
rimraf "^3.0.2" rimraf "^3.0.2"
socket.io "^4.4.1" socket.io "^4.7.2"
source-map "^0.6.1" source-map "^0.6.1"
tmp "^0.2.1" tmp "^0.2.1"
ua-parser-js "^0.7.30" ua-parser-js "^0.7.30"
@@ -1158,6 +1173,13 @@ kind-of@^6.0.2:
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
kotlin-web-helpers@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/kotlin-web-helpers/-/kotlin-web-helpers-2.0.0.tgz#b112096b273c1e733e0b86560998235c09a19286"
integrity sha512-xkVGl60Ygn/zuLkDPx+oHj7jeLR7hCvoNF99nhwXMn8a3ApB4lLiC9pk4ol4NHPjyoCbvQctBqvzUcp8pkqyWw==
dependencies:
format-util "^1.0.5"
loader-runner@^4.2.0: loader-runner@^4.2.0:
version "4.3.0" version "4.3.0"
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
@@ -1182,7 +1204,7 @@ lodash@^4.17.15, lodash@^4.17.21:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-symbols@4.1.0: log-symbols@^4.1.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
@@ -1228,13 +1250,6 @@ mime@^2.5.2:
resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
minimatch@5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b"
integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4, minimatch@^3.1.1: minimatch@^3.0.4, minimatch@^3.1.1:
version "3.1.2" version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
@@ -1242,6 +1257,20 @@ minimatch@^3.0.4, minimatch@^3.1.1:
dependencies: dependencies:
brace-expansion "^1.1.7" brace-expansion "^1.1.7"
minimatch@^5.0.1, minimatch@^5.1.6:
version "5.1.9"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.9.tgz#1293ef15db0098b394540e8f9f744f9fda8dee4b"
integrity sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==
dependencies:
brace-expansion "^2.0.1"
minimatch@^9.0.3:
version "9.0.9"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.9.tgz#9b0cb9fcb78087f6fd7eababe2511c4d3d60574e"
integrity sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==
dependencies:
brace-expansion "^2.0.2"
minimist@^1.2.3, minimist@^1.2.6: minimist@^1.2.3, minimist@^1.2.6:
version "1.2.7" version "1.2.7"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
@@ -1254,32 +1283,31 @@ mkdirp@^0.5.5:
dependencies: dependencies:
minimist "^1.2.6" minimist "^1.2.6"
mocha@10.2.0: mocha@10.7.3:
version "10.2.0" version "10.7.3"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.7.3.tgz#ae32003cabbd52b59aece17846056a68eb4b0752"
integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== integrity sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==
dependencies: dependencies:
ansi-colors "4.1.1" ansi-colors "^4.1.3"
browser-stdout "1.3.1" browser-stdout "^1.3.1"
chokidar "3.5.3" chokidar "^3.5.3"
debug "4.3.4" debug "^4.3.5"
diff "5.0.0" diff "^5.2.0"
escape-string-regexp "4.0.0" escape-string-regexp "^4.0.0"
find-up "5.0.0" find-up "^5.0.0"
glob "7.2.0" glob "^8.1.0"
he "1.2.0" he "^1.2.0"
js-yaml "4.1.0" js-yaml "^4.1.0"
log-symbols "4.1.0" log-symbols "^4.1.0"
minimatch "5.0.1" minimatch "^5.1.6"
ms "2.1.3" ms "^2.1.3"
nanoid "3.3.3" serialize-javascript "^6.0.2"
serialize-javascript "6.0.0" strip-json-comments "^3.1.1"
strip-json-comments "3.1.1" supports-color "^8.1.1"
supports-color "8.1.1" workerpool "^6.5.1"
workerpool "6.2.1" yargs "^16.2.0"
yargs "16.2.0" yargs-parser "^20.2.9"
yargs-parser "20.2.4" yargs-unparser "^2.0.0"
yargs-unparser "2.0.0"
ms@2.0.0: ms@2.0.0:
version "2.0.0" version "2.0.0"
@@ -1291,16 +1319,11 @@ ms@2.1.2:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
ms@2.1.3: ms@^2.1.3:
version "2.1.3" version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
nanoid@3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==
negotiator@0.6.3: negotiator@0.6.3:
version "0.6.3" version "0.6.3"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
@@ -1311,10 +1334,10 @@ neo-async@^2.6.2:
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
node-releases@^2.0.6: node-releases@^2.0.36:
version "2.0.7" version "2.0.47"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.7.tgz#593edbc7c22860ee4d32d3933cfebdfab0c0e0e5" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.47.tgz#521bb2786da8eb140b748841c0b3b3a75334ffc4"
integrity sha512-EJ3rzxL9pTWPjk5arA0s0dgXpnyiAbJDE6wHT62g7VsgrgQgmmZ+Ru++M1BFofncWja+Pnn3rEr3fieRySAdKQ== integrity sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==
normalize-path@^3.0.0, normalize-path@~3.0.0: normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0" version "3.0.0"
@@ -1410,10 +1433,10 @@ path-parse@^1.0.7:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
picocolors@^1.0.0: picocolors@^1.1.1:
version "1.0.0" version "1.1.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
picomatch@^2.0.4, picomatch@^2.2.1: picomatch@^2.0.4, picomatch@^2.2.1:
version "2.3.1" version "2.3.1"
@@ -1538,7 +1561,7 @@ safe-buffer@^5.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
schema-utils@^3.1.2: schema-utils@^3.2.0:
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
@@ -1557,13 +1580,6 @@ schema-utils@^4.3.0:
ajv-formats "^2.1.1" ajv-formats "^2.1.1"
ajv-keywords "^5.1.0" ajv-keywords "^5.1.0"
serialize-javascript@6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
dependencies:
randombytes "^2.1.0"
serialize-javascript@^6.0.2: serialize-javascript@^6.0.2:
version "6.0.2" version "6.0.2"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2"
@@ -1604,42 +1620,45 @@ side-channel@^1.0.4:
get-intrinsic "^1.0.2" get-intrinsic "^1.0.2"
object-inspect "^1.9.0" object-inspect "^1.9.0"
socket.io-adapter@~2.4.0: socket.io-adapter@~2.5.2:
version "2.4.0" version "2.5.7"
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.7.tgz#463428625f55be6f2f784a4501013b71454c0761"
integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== integrity sha512-e0LyK91f3cUxTmv95/KzoLg47+zF+s/sbxRGDNsyG4dmIP8ZSX8ax6byOxfJXeNNtS/8AZlfD+uP7gBeR7DLlg==
dependencies:
debug "~4.4.1"
ws "~8.20.1"
socket.io-parser@~4.2.1: socket.io-parser@~4.2.4:
version "4.2.1" version "4.2.6"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.1.tgz#01c96efa11ded938dcb21cbe590c26af5eff65e5" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.6.tgz#19156bf179af3931abd05260cfb1491822578a6f"
integrity sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g== integrity sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==
dependencies: dependencies:
"@socket.io/component-emitter" "~3.1.0" "@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1" debug "~4.4.1"
socket.io@^4.4.1: socket.io@^4.7.2:
version "4.5.4" version "4.8.3"
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.4.tgz#a4513f06e87451c17013b8d13fdfaf8da5a86a90" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.8.3.tgz#ca6ba1431c69532e1e0a6f496deebeb601dbc4df"
integrity sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ== integrity sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==
dependencies: dependencies:
accepts "~1.3.4" accepts "~1.3.4"
base64id "~2.0.0" base64id "~2.0.0"
debug "~4.3.2" cors "~2.8.5"
engine.io "~6.2.1" debug "~4.4.1"
socket.io-adapter "~2.4.0" engine.io "~6.6.0"
socket.io-parser "~4.2.1" socket.io-adapter "~2.5.2"
socket.io-parser "~4.2.4"
source-map-js@^1.0.2: source-map-js@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
source-map-loader@4.0.1: source-map-loader@5.0.0:
version "4.0.1" version "5.0.0"
resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-4.0.1.tgz#72f00d05f5d1f90f80974eda781cbd7107c125f2" resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-5.0.0.tgz#f593a916e1cc54471cfc8851b905c8a845fc7e38"
integrity sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA== integrity sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==
dependencies: dependencies:
abab "^2.0.6"
iconv-lite "^0.6.3" iconv-lite "^0.6.3"
source-map-js "^1.0.2" source-map-js "^1.0.2"
@@ -1691,18 +1710,11 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1:
dependencies: dependencies:
ansi-regex "^5.0.1" ansi-regex "^5.0.1"
strip-json-comments@3.1.1: strip-json-comments@^3.1.1:
version "3.1.1" version "3.1.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
supports-color@8.1.1, supports-color@^8.0.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-color@^7.1.0: supports-color@^7.1.0:
version "7.2.0" version "7.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
@@ -1710,25 +1722,36 @@ supports-color@^7.1.0:
dependencies: dependencies:
has-flag "^4.0.0" has-flag "^4.0.0"
supports-color@^8.0.0, supports-color@^8.1.1:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-preserve-symlinks-flag@^1.0.0: supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
tapable@^2.1.1, tapable@^2.2.0: tapable@^2.1.1:
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
terser-webpack-plugin@^5.3.7: tapable@^2.3.3:
version "5.3.16" version "2.3.3"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz#741e448cc3f93d8026ebe4f7ef9e4afacfd56330" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.3.3.tgz#5da7c9992c46038221267985ab28421a8879f160"
integrity sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q== integrity sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==
terser-webpack-plugin@^5.3.10:
version "5.6.1"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz#47bc41bd8b8fab8383b62ec763b7394829097e7b"
integrity sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==
dependencies: dependencies:
"@jridgewell/trace-mapping" "^0.3.25" "@jridgewell/trace-mapping" "^0.3.25"
jest-worker "^27.4.5" jest-worker "^27.4.5"
schema-utils "^4.3.0" schema-utils "^4.3.0"
serialize-javascript "^6.0.2"
terser "^5.31.1" terser "^5.31.1"
terser@^5.31.1: terser@^5.31.1:
@@ -1768,10 +1791,10 @@ type-is@~1.6.18:
media-typer "0.3.0" media-typer "0.3.0"
mime-types "~2.1.24" mime-types "~2.1.24"
typescript@5.0.4: typescript@5.5.4:
version "5.0.4" version "5.5.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba"
integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==
ua-parser-js@^0.7.30: ua-parser-js@^0.7.30:
version "0.7.32" version "0.7.32"
@@ -1788,13 +1811,13 @@ unpipe@1.0.0, unpipe@~1.0.0:
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
update-browserslist-db@^1.0.9: update-browserslist-db@^1.2.3:
version "1.0.10" version "1.2.3"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d"
integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==
dependencies: dependencies:
escalade "^3.1.1" escalade "^3.2.0"
picocolors "^1.0.0" picocolors "^1.1.1"
uri-js@^4.2.2: uri-js@^4.2.2:
version "4.4.1" version "4.4.1"
@@ -1818,23 +1841,23 @@ void-elements@^2.0.0:
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung== integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==
watchpack@^2.4.0: watchpack@^2.4.1:
version "2.5.0" version "2.5.1"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.5.0.tgz#fa115d5ccaa4bf3aa594f586257c0bc4768939fd" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.5.1.tgz#dd38b601f669e0cbf567cb802e75cead82cde102"
integrity sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA== integrity sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==
dependencies: dependencies:
glob-to-regexp "^0.4.1" glob-to-regexp "^0.4.1"
graceful-fs "^4.1.2" graceful-fs "^4.1.2"
webpack-cli@5.1.0: webpack-cli@5.1.4:
version "5.1.0" version "5.1.4"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.0.tgz#abc4b1f44b50250f2632d8b8b536cfe2f6257891" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b"
integrity sha512-a7KRJnCxejFoDpYTOwzm5o21ZXMaNqtRlvS183XzGDUPRdVEzJNImcQokqYZ8BNTnk9DkKiuWxw75+DCCoZ26w== integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==
dependencies: dependencies:
"@discoveryjs/json-ext" "^0.5.0" "@discoveryjs/json-ext" "^0.5.0"
"@webpack-cli/configtest" "^2.1.0" "@webpack-cli/configtest" "^2.1.1"
"@webpack-cli/info" "^2.0.1" "@webpack-cli/info" "^2.0.2"
"@webpack-cli/serve" "^2.0.3" "@webpack-cli/serve" "^2.0.5"
colorette "^2.0.14" colorette "^2.0.14"
commander "^10.0.1" commander "^10.0.1"
cross-spawn "^7.0.3" cross-spawn "^7.0.3"
@@ -1865,34 +1888,33 @@ webpack-sources@^3.2.3:
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
webpack@5.82.0: webpack@5.94.0:
version "5.82.0" version "5.94.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.82.0.tgz#3c0d074dec79401db026b4ba0fb23d6333f88e7d" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f"
integrity sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg== integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==
dependencies: dependencies:
"@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.5"
"@types/estree" "^1.0.0" "@webassemblyjs/ast" "^1.12.1"
"@webassemblyjs/ast" "^1.11.5" "@webassemblyjs/wasm-edit" "^1.12.1"
"@webassemblyjs/wasm-edit" "^1.11.5" "@webassemblyjs/wasm-parser" "^1.12.1"
"@webassemblyjs/wasm-parser" "^1.11.5"
acorn "^8.7.1" acorn "^8.7.1"
acorn-import-assertions "^1.7.6" acorn-import-attributes "^1.9.5"
browserslist "^4.14.5" browserslist "^4.21.10"
chrome-trace-event "^1.0.2" chrome-trace-event "^1.0.2"
enhanced-resolve "^5.13.0" enhanced-resolve "^5.17.1"
es-module-lexer "^1.2.1" es-module-lexer "^1.2.1"
eslint-scope "5.1.1" eslint-scope "5.1.1"
events "^3.2.0" events "^3.2.0"
glob-to-regexp "^0.4.1" glob-to-regexp "^0.4.1"
graceful-fs "^4.2.9" graceful-fs "^4.2.11"
json-parse-even-better-errors "^2.3.1" json-parse-even-better-errors "^2.3.1"
loader-runner "^4.2.0" loader-runner "^4.2.0"
mime-types "^2.1.27" mime-types "^2.1.27"
neo-async "^2.6.2" neo-async "^2.6.2"
schema-utils "^3.1.2" schema-utils "^3.2.0"
tapable "^2.1.1" tapable "^2.1.1"
terser-webpack-plugin "^5.3.7" terser-webpack-plugin "^5.3.10"
watchpack "^2.4.0" watchpack "^2.4.1"
webpack-sources "^3.2.3" webpack-sources "^3.2.3"
which@^1.2.1: which@^1.2.1:
@@ -1914,10 +1936,10 @@ wildcard@^2.0.0:
resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec"
integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==
workerpool@6.2.1: workerpool@^6.5.1:
version "6.2.1" version "6.5.1"
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544"
integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==
wrap-ansi@^7.0.0: wrap-ansi@^7.0.0:
version "7.0.0" version "7.0.0"
@@ -1933,27 +1955,22 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
ws@~8.2.3: ws@~8.20.1:
version "8.2.3" version "8.20.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" resolved "https://registry.yarnpkg.com/ws/-/ws-8.20.1.tgz#91a9ae2b312ccf98e0a85ec499b48cef45ab0ddb"
integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== integrity sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==
y18n@^5.0.5: y18n@^5.0.5:
version "5.0.8" version "5.0.8"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
yargs-parser@20.2.4: yargs-parser@^20.2.2, yargs-parser@^20.2.9:
version "20.2.4"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
yargs-parser@^20.2.2:
version "20.2.9" version "20.2.9"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
yargs-unparser@2.0.0: yargs-unparser@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"
integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==
@@ -1963,7 +1980,7 @@ yargs-unparser@2.0.0:
flat "^5.0.2" flat "^5.0.2"
is-plain-obj "^2.1.0" is-plain-obj "^2.1.0"
yargs@16.2.0, yargs@^16.1.1: yargs@^16.1.1, yargs@^16.2.0:
version "16.2.0" version "16.2.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==

View File

@@ -1,3 +1,5 @@
rootProject.name = "tree-structure" rootProject.name = "tree-structure"
include(":tree-structure-serialization")
include(":tree-structure-coroutines")
include(":tree-structure-compose")

View File

@@ -2,7 +2,7 @@ package com.github.adriankuta.datastructure.tree
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
interface ChildDeclarationInterface<T> { public interface ChildDeclarationInterface<T> {
/** /**
* This method is used to easily create child in node. * This method is used to easily create child in node.
@@ -20,5 +20,5 @@ interface ChildDeclarationInterface<T> {
* @return New created TreeNode. * @return New created TreeNode.
*/ */
@JvmSynthetic @JvmSynthetic
fun child(value: T, childDeclaration: ChildDeclaration<T>? = null): TreeNode<T> public fun child(value: T, childDeclaration: ChildDeclaration<T>? = null): TreeNode<T>
} }

View File

@@ -9,16 +9,32 @@ import com.github.adriankuta.datastructure.tree.iterators.TreeNodeIterators.*
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
/** /**
* @param treeIterator Choose one of available iterators from [TreeNodeIterators] * A node in a generic, mutable n-ary tree. Each node holds a [value], a reference to its [parent]
* and an ordered list of [children].
*
* Iterating a node (via [iterator], or the lazy [asSequence]/[preOrderSequence] extensions) visits
* the node and all of its descendants. Traversal and the [height]/[nodeCount]/[clear] helpers are
* implemented iteratively, so they are safe on arbitrarily deep trees.
*
* **Not thread-safe.** Nodes are mutable ([addChild]/[removeChild]/[clear] mutate the structure and
* parent pointers). Sharing a tree across threads requires external synchronization, and the tree
* must not be modified while it is being iterated.
*
* Equality is by reference (identity); use the `structurallyEquals` extension to compare two trees
* by value and shape.
*
* @param value the value stored in this node.
* @param treeIterator the default traversal order used by [iterator]. Prefer the
* `asSequence(order)` / `preOrderSequence()` extensions to choose an order without mutating state.
*/ */
open class TreeNode<T>(val value: T, var treeIterator: TreeNodeIterators = PreOrder) : Iterable<TreeNode<T>>, ChildDeclarationInterface<T> { public open class TreeNode<T>(public val value: T, public val treeIterator: TreeNodeIterators = PreOrder) : Iterable<TreeNode<T>>, ChildDeclarationInterface<T> {
private var _parent: TreeNode<T>? = null private var _parent: TreeNode<T>? = null
/** /**
* The converse notion of a child, an immediate ancestor. * The converse notion of a child, an immediate ancestor.
*/ */
val parent: TreeNode<T>? public val parent: TreeNode<T>?
get() = _parent get() = _parent
private val _children = mutableListOf<TreeNode<T>>() private val _children = mutableListOf<TreeNode<T>>()
@@ -26,28 +42,60 @@ open class TreeNode<T>(val value: T, var treeIterator: TreeNodeIterators = PreOr
/** /**
* A group of nodes with the same parent. * A group of nodes with the same parent.
*/ */
val children: List<TreeNode<T>> public val children: List<TreeNode<T>>
get() = _children get() = _children
/** /**
* Checks whether the current tree node is the root of the tree * Checks whether the current tree node is the root of the tree
* @return `true` if the current tree node is root of the tree, `false` otherwise. * @return `true` if the current tree node is root of the tree, `false` otherwise.
*/ */
val isRoot: Boolean public val isRoot: Boolean
get() = _parent == null get() = _parent == null
/** /**
* Add new child to current node or root. * Adds [child] as a direct child of this node.
* *
* @param child A node which will be directly connected to current node. * @param child a node that is not already attached to a tree. To move a node that already has a
* parent, call [detach] on it first.
* @throws TreeNodeException if [child] already has a parent, or if attaching it here would create
* a cycle (i.e. [child] is this node or one of its ancestors).
*/ */
fun addChild(child: TreeNode<T>) { public fun addChild(child: TreeNode<T>) {
if (child._parent != null) {
throw TreeNodeException("$child already has a parent; call detach() before re-attaching it.")
}
if (child === this) {
throw TreeNodeException("Adding $child here would create a cycle.")
}
// Only a node that already has its own subtree can contain `this` and thus form a cycle.
// Skipping this walk for leaves keeps building deep trees O(n) instead of O(n²).
if (child._children.isNotEmpty()) {
var ancestor: TreeNode<T>? = _parent
while (ancestor != null) {
if (ancestor === child) {
throw TreeNodeException("Adding $child here would create a cycle.")
}
ancestor = ancestor._parent
}
}
child._parent = this child._parent = this
_children.add(child) _children.add(child)
} }
/**
* Detaches this node from its parent, removing it from the parent's [children].
*
* @return `true` if this node was attached and is now detached; `false` if it was already a root.
*/
public fun detach(): Boolean {
val currentParent = _parent ?: return false
currentParent._children.remove(this)
_parent = null
return true
}
@JvmSynthetic @JvmSynthetic
override fun child(value: T, childDeclaration: ChildDeclaration<T>?): TreeNode<T> { public override fun child(value: T, childDeclaration: ChildDeclaration<T>?): TreeNode<T> {
val newChild = TreeNode(value) val newChild = TreeNode(value)
newChild._parent = this newChild._parent = this
if (childDeclaration != null) if (childDeclaration != null)
@@ -57,43 +105,55 @@ open class TreeNode<T>(val value: T, var treeIterator: TreeNodeIterators = PreOr
} }
/** /**
* Removes a single instance of the specified node from this tree, if it is present. * Removes [child] from this node's direct [children], if present.
* *
* @return `true` if the node has been successfully removed; `false` if it was not present in the tree. * This only removes a *direct* child of the receiver; it does not reach into other nodes. To
* remove a node from wherever it currently lives, call [detach] on it instead.
*
* @return `true` if [child] was a direct child and has been removed; `false` otherwise.
*/ */
fun removeChild(child: TreeNode<T>): Boolean { public fun removeChild(child: TreeNode<T>): Boolean {
println(child.value) val removed = _children.remove(child)
val removed = child._parent?._children?.remove(child) if (removed) child._parent = null
child._parent = null return removed
return removed ?: false
} }
/** /**
* This function go through tree and counts children. Root element is not counted. * This function go through tree and counts children. Root element is not counted.
* @return All child and nested child count. * @return All child and nested child count.
*/ */
fun nodeCount(): Int { public fun nodeCount(): Int {
if (_children.isEmpty()) var count = 0
return 0 val stack = ArrayDeque<TreeNode<T>>()
return _children.size + stack.addAll(_children)
_children.sumOf { it.nodeCount() } while (stack.isNotEmpty()) {
val node = stack.removeLast()
count++
stack.addAll(node._children)
}
return count
} }
/** /**
* @return The number of edges on the longest path between current node and a descendant leaf. * @return The number of edges on the longest path between current node and a descendant leaf.
*/ */
fun height(): Int { public fun height(): Int {
val childrenMaxDepth = _children.map { it.height() } var maxDepth = 0
.maxOrNull() val stack = ArrayDeque<Pair<TreeNode<T>, Int>>()
?: -1 // -1 because this method counts nodes, and edges are always one less then nodes. stack.addLast(this to 0)
return childrenMaxDepth + 1 while (stack.isNotEmpty()) {
val (node, depthSoFar) = stack.removeLast()
if (depthSoFar > maxDepth) maxDepth = depthSoFar
node._children.forEach { stack.addLast(it to depthSoFar + 1) }
}
return maxDepth
} }
/** /**
* Distance is the number of edges along the shortest path between two nodes. * Distance is the number of edges along the shortest path between two nodes.
* @return The distance between current node and the root. * @return The distance between current node and the root.
*/ */
fun depth(): Int { public fun depth(): Int {
var depth = 0 var depth = 0
var tempParent = parent var tempParent = parent
@@ -105,44 +165,52 @@ open class TreeNode<T>(val value: T, var treeIterator: TreeNodeIterators = PreOr
} }
/** /**
* Returns the collection of nodes, which connect the current node * Returns the chain of nodes from [descendant] up to and including this node, or `null` if
* with its descendants * [descendant] is not a strict descendant of this node.
* *
* @param descendant the bottom child node for which the path is calculated * @param descendant the node to walk up from.
* @return collection of nodes, which connect the current node with its descendants * @return the path `[descendant, …, this]`, or `null` if [descendant] is the root or is not
* @throws TreeNodeException exception that may be thrown in case if the * located in this node's subtree.
* current node does not have such descendant or if the
* specified tree node is root
*/ */
@Throws(TreeNodeException::class) public fun path(descendant: TreeNode<T>): List<TreeNode<T>>? {
fun path(descendant: TreeNode<T>): List<TreeNode<T>> { if (descendant.isRoot) return null
val path = mutableListOf<TreeNode<T>>() val path = mutableListOf<TreeNode<T>>()
var node = descendant var node = descendant
path.add(node) path.add(node)
while (!node.isRoot) { while (!node.isRoot) {
node = node.parent!! node = node.parent!!
path.add(node) path.add(node)
if (node == this) if (node == this) return path
return path
} }
throw TreeNodeException("The specified tree node $descendant is not the descendant of tree node $this") return null
} }
/** /**
* Remove all children from root and every node in tree. * Removes every descendant of this node. Afterwards [children] is empty and all former
* descendants are detached (their parent is `null`). This node itself stays attached to its own
* parent.
*/ */
fun clear() { public fun clear() {
_parent = null val descendants = ArrayDeque<TreeNode<T>>()
_children.forEach { it.clear() } val stack = ArrayDeque<TreeNode<T>>()
stack.addAll(_children)
while (stack.isNotEmpty()) {
val node = stack.removeLast()
descendants.addLast(node)
stack.addAll(node._children)
}
descendants.forEach { node ->
node._parent = null
node._children.clear()
}
_children.clear() _children.clear()
} }
override fun toString(): String { public override fun toString(): String {
return value.toString() return value.toString()
} }
fun prettyString(): String { public fun prettyString(): String {
val stringBuilder = StringBuilder() val stringBuilder = StringBuilder()
print(stringBuilder, "", "") print(stringBuilder, "", "")
return stringBuilder.toString() return stringBuilder.toString()
@@ -164,9 +232,14 @@ open class TreeNode<T>(val value: T, var treeIterator: TreeNodeIterators = PreOr
} }
/** /**
* You can change default iterator by changing [treeIterator] property. * Returns an iterator over this node and its descendants using the default [treeIterator] order.
* Use [iterator] with an explicit order, or the `asSequence(order)` extension, to traverse in a
* different order without changing this node's default.
*/ */
override fun iterator(): Iterator<TreeNode<T>> = when (treeIterator) { public override fun iterator(): Iterator<TreeNode<T>> = iterator(treeIterator)
/** Returns an iterator over this node and its descendants in the given [order]. */
public fun iterator(order: TreeNodeIterators): Iterator<TreeNode<T>> = when (order) {
PreOrder -> PreOrderTreeIterator(this) PreOrder -> PreOrderTreeIterator(this)
PostOrder -> PostOrderTreeIterator(this) PostOrder -> PostOrderTreeIterator(this)
LevelOrder -> LevelOrderTreeIterator(this) LevelOrder -> LevelOrderTreeIterator(this)

View File

@@ -3,7 +3,7 @@ package com.github.adriankuta.datastructure.tree
import com.github.adriankuta.datastructure.tree.iterators.TreeNodeIterators import com.github.adriankuta.datastructure.tree.iterators.TreeNodeIterators
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
typealias ChildDeclaration<T> = ChildDeclarationInterface<T>.() -> Unit public typealias ChildDeclaration<T> = ChildDeclarationInterface<T>.() -> Unit
/** /**
* This method can be used to initialize new tree. * This method can be used to initialize new tree.
@@ -14,7 +14,7 @@ typealias ChildDeclaration<T> = ChildDeclarationInterface<T>.() -> Unit
* @see [ChildDeclarationInterface.child] * @see [ChildDeclarationInterface.child]
*/ */
@JvmSynthetic @JvmSynthetic
inline fun <reified T> tree( public inline fun <reified T> tree(
root: T, root: T,
defaultIterator: TreeNodeIterators = TreeNodeIterators.PreOrder, defaultIterator: TreeNodeIterators = TreeNodeIterators.PreOrder,
childDeclaration: ChildDeclaration<T> childDeclaration: ChildDeclaration<T>

View File

@@ -0,0 +1,65 @@
package com.github.adriankuta.datastructure.tree
/** Returns the first node (pre-order) whose value matches [predicate], or `null`. Short-circuits. */
public fun <T> TreeNode<T>.findNode(predicate: (T) -> Boolean): TreeNode<T>? =
preOrderSequence().firstOrNull { predicate(it.value) }
/** All nodes (pre-order) whose value matches [predicate]. */
public fun <T> TreeNode<T>.filterNodes(predicate: (T) -> Boolean): List<TreeNode<T>> =
preOrderSequence().filter { predicate(it.value) }.toList()
/** `true` if any node's value matches [predicate]. Short-circuits. */
public fun <T> TreeNode<T>.anyNode(predicate: (T) -> Boolean): Boolean =
preOrderSequence().any { predicate(it.value) }
/** `true` if every node's value matches [predicate]. Short-circuits. */
public fun <T> TreeNode<T>.allNodes(predicate: (T) -> Boolean): Boolean =
preOrderSequence().all { predicate(it.value) }
/** Counts nodes whose value matches [predicate]. */
public fun <T> TreeNode<T>.countNodes(predicate: (T) -> Boolean): Int =
preOrderSequence().count { predicate(it.value) }
/** Folds [operation] over all nodes in pre-order, starting from [initial]. */
public fun <T, R> TreeNode<T>.foldNodes(initial: R, operation: (acc: R, node: TreeNode<T>) -> R): R =
preOrderSequence().fold(initial) { acc, node -> operation(acc, node) }
/**
* Returns a new tree with the same shape whose values are produced by [transform]. The original is
* left untouched. Stack-safe (iterative), so it handles arbitrarily deep trees.
*/
public fun <T, R> TreeNode<T>.mapValues(transform: (T) -> R): TreeNode<R> {
val newRoot = TreeNode(transform(value), treeIterator)
val stack = ArrayDeque<Pair<TreeNode<T>, TreeNode<R>>>()
stack.addLast(this to newRoot)
while (stack.isNotEmpty()) {
val (source, target) = stack.removeLast()
source.children.forEach { child ->
val mappedChild = TreeNode(transform(child.value), child.treeIterator)
target.addChild(mappedChild)
stack.addLast(child to mappedChild)
}
}
return newRoot
}
/** Returns an independent deep copy of this subtree (same values, same shape, new nodes). */
public fun <T> TreeNode<T>.deepCopy(): TreeNode<T> = mapValues { it }
/**
* Structural equality: `true` when [other] holds the same values in the same shape. Unlike
* [TreeNode]'s reference equality, this compares the entire subtree. Stack-safe.
*/
public fun <T> TreeNode<T>.structurallyEquals(other: TreeNode<T>): Boolean {
val stack = ArrayDeque<Pair<TreeNode<T>, TreeNode<T>>>()
stack.addLast(this to other)
while (stack.isNotEmpty()) {
val (a, b) = stack.removeLast()
if (a.value != b.value) return false
if (a.children.size != b.children.size) return false
for (i in a.children.indices) {
stack.addLast(a.children[i] to b.children[i])
}
}
return true
}

View File

@@ -0,0 +1,41 @@
package com.github.adriankuta.datastructure.tree
/** `true` when this node has no children. */
public val <T> TreeNode<T>.isLeaf: Boolean get() = children.isEmpty()
/** The number of direct children of this node. */
public val <T> TreeNode<T>.degree: Int get() = children.size
/** Walks up the parent chain and returns the topmost ancestor (the tree root). */
public fun <T> TreeNode<T>.root(): TreeNode<T> {
var node = this
var parent = node.parent
while (parent != null) {
node = parent
parent = node.parent
}
return node
}
/** The chain of ancestors from the immediate [parent] up to (and including) the root. */
public fun <T> TreeNode<T>.ancestors(): List<TreeNode<T>> {
val result = mutableListOf<TreeNode<T>>()
var parent = this.parent
while (parent != null) {
result.add(parent)
parent = parent.parent
}
return result
}
/** The other children of this node's parent (excludes this node). Empty for the root. */
public fun <T> TreeNode<T>.siblings(): List<TreeNode<T>> =
parent?.children?.filter { it !== this } ?: emptyList()
/** All leaf nodes in this subtree, in pre-order. */
public fun <T> TreeNode<T>.leaves(): List<TreeNode<T>> =
preOrderSequence().filter { it.isLeaf }.toList()
/** All nodes in this subtree except this node, in pre-order. */
public fun <T> TreeNode<T>.descendants(): List<TreeNode<T>> =
preOrderSequence().filter { it !== this }.toList()

View File

@@ -0,0 +1,31 @@
package com.github.adriankuta.datastructure.tree
import com.github.adriankuta.datastructure.tree.iterators.LevelOrderTreeIterator
import com.github.adriankuta.datastructure.tree.iterators.PostOrderTreeIterator
import com.github.adriankuta.datastructure.tree.iterators.PreOrderTreeIterator
import com.github.adriankuta.datastructure.tree.iterators.TreeNodeIterators
/**
* Lazily traverses this subtree in the given [order] as a [Sequence], without forcing the whole
* traversal up front. Pairs with the Kotlin stdlib, e.g.
* `root.asSequence().map { it.value }.firstOrNull { it == target }`.
*/
public fun <T> TreeNode<T>.asSequence(
order: TreeNodeIterators = TreeNodeIterators.PreOrder,
): Sequence<TreeNode<T>> {
val self = this
return when (order) {
TreeNodeIterators.PreOrder -> Sequence { PreOrderTreeIterator(self) }
TreeNodeIterators.PostOrder -> Sequence { PostOrderTreeIterator(self) }
TreeNodeIterators.LevelOrder -> Sequence { LevelOrderTreeIterator(self) }
}
}
/** Lazy pre-order traversal as a [Sequence]. */
public fun <T> TreeNode<T>.preOrderSequence(): Sequence<TreeNode<T>> = asSequence(TreeNodeIterators.PreOrder)
/** Lazy post-order traversal as a [Sequence]. */
public fun <T> TreeNode<T>.postOrderSequence(): Sequence<TreeNode<T>> = asSequence(TreeNodeIterators.PostOrder)
/** Lazy level-order (breadth-first) traversal as a [Sequence]. */
public fun <T> TreeNode<T>.levelOrderSequence(): Sequence<TreeNode<T>> = asSequence(TreeNodeIterators.LevelOrder)

View File

@@ -2,5 +2,5 @@ package com.github.adriankuta.datastructure.tree.exceptions
import kotlin.jvm.JvmOverloads import kotlin.jvm.JvmOverloads
class TreeNodeException @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : public class TreeNodeException @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) :
RuntimeException(message, cause) RuntimeException(message, cause)

View File

@@ -20,7 +20,7 @@ import com.github.adriankuta.datastructure.tree.TreeNode
* Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 * Output: 1 2 3 4 5 6 7 8 9 10 11 12 13
* ``` * ```
*/ */
class LevelOrderTreeIterator<T>(root: TreeNode<T>) : Iterator<TreeNode<T>> { public class LevelOrderTreeIterator<T>(root: TreeNode<T>) : Iterator<TreeNode<T>> {
private val stack = ArrayDeque<TreeNode<T>>() private val stack = ArrayDeque<TreeNode<T>>()
@@ -28,9 +28,9 @@ class LevelOrderTreeIterator<T>(root: TreeNode<T>) : Iterator<TreeNode<T>> {
stack.addLast(root) stack.addLast(root)
} }
override fun hasNext(): Boolean = stack.isNotEmpty() public override fun hasNext(): Boolean = stack.isNotEmpty()
override fun next(): TreeNode<T> { public override fun next(): TreeNode<T> {
val node = stack.removeFirst() val node = stack.removeFirst()
node.children node.children
.forEach { stack.addLast(it) } .forEach { stack.addLast(it) }

View File

@@ -20,29 +20,24 @@ import com.github.adriankuta.datastructure.tree.TreeNode
* Output: 10 5 11 12 13 6 2 3 7 8 9 4 1 * Output: 10 5 11 12 13 6 2 3 7 8 9 4 1
* ``` * ```
*/ */
class PostOrderTreeIterator<T>(root: TreeNode<T>) : Iterator<TreeNode<T>> { public class PostOrderTreeIterator<T>(root: TreeNode<T>) : Iterator<TreeNode<T>> {
private val stack = ArrayDeque<TreeNode<T>>() private val result = ArrayDeque<TreeNode<T>>()
init { init {
stack.addAll(getChildrenStack(root)) // Iterative post-order: pop a node, prepend it to `result`, then push its children
} // left-to-right. Reading `result` front-to-back yields post-order — without the deep
// recursion that overflowed the stack on degenerate (linear) trees.
override fun hasNext(): Boolean = stack.isNotEmpty()
override fun next(): TreeNode<T> {
return stack.removeFirst()
}
private fun getChildrenStack(node: TreeNode<T>): ArrayDeque<TreeNode<T>> {
val stack = ArrayDeque<TreeNode<T>>() val stack = ArrayDeque<TreeNode<T>>()
if(node.children.isEmpty()) { stack.addLast(root)
return ArrayDeque(listOf(node)) while (stack.isNotEmpty()) {
} val node = stack.removeLast()
node.children.forEach { result.addFirst(node)
stack.addAll(getChildrenStack(it)) node.children.forEach { stack.addLast(it) }
}
stack.addLast(node)
return stack
} }
} }
public override fun hasNext(): Boolean = result.isNotEmpty()
public override fun next(): TreeNode<T> = result.removeFirst()
}

View File

@@ -20,7 +20,7 @@ import com.github.adriankuta.datastructure.tree.TreeNode
* Output: 1 2 5 10 6 11 12 13 3 4 7 8 9 * Output: 1 2 5 10 6 11 12 13 3 4 7 8 9
* ``` * ```
*/ */
class PreOrderTreeIterator<T>(root: TreeNode<T>) : Iterator<TreeNode<T>> { public class PreOrderTreeIterator<T>(root: TreeNode<T>) : Iterator<TreeNode<T>> {
private val stack = ArrayDeque<TreeNode<T>>() private val stack = ArrayDeque<TreeNode<T>>()
@@ -28,9 +28,9 @@ class PreOrderTreeIterator<T>(root: TreeNode<T>) : Iterator<TreeNode<T>> {
stack.addLast(root) stack.addLast(root)
} }
override fun hasNext(): Boolean = stack.isNotEmpty() public override fun hasNext(): Boolean = stack.isNotEmpty()
override fun next(): TreeNode<T> { public override fun next(): TreeNode<T> {
val node = stack.removeLast() val node = stack.removeLast()
node.children node.children
.asReversed() .asReversed()

View File

@@ -5,7 +5,7 @@ package com.github.adriankuta.datastructure.tree.iterators
* @see PostOrder * @see PostOrder
* @see LevelOrder * @see LevelOrder
*/ */
enum class TreeNodeIterators { public enum class TreeNodeIterators {
/** /**
* Tree is iterated by using `Pre-order Traversal Algorithm" * Tree is iterated by using `Pre-order Traversal Algorithm"
* The pre-order traversal is a topologically sorted one, * The pre-order traversal is a topologically sorted one,

View File

@@ -1,16 +0,0 @@
package com.github.adriankuta.datastructure.tree
import kotlin.test.Test
import kotlin.test.assertEquals
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

View File

@@ -0,0 +1,78 @@
package com.github.adriankuta.datastructure.tree
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotSame
import kotlin.test.assertNull
import kotlin.test.assertSame
import kotlin.test.assertTrue
class TreeNodeFunctionalTest {
private fun sample() = tree(1) {
child(2) {
child(4)
child(5)
}
child(3) {
child(6)
}
}
@Test
fun findNode() {
assertEquals(6, sample().findNode { it == 6 }?.value)
assertNull(sample().findNode { it == 99 })
}
@Test
fun filterNodes() =
assertContentEquals(listOf(2, 4, 6), sample().filterNodes { it % 2 == 0 }.map { it.value })
@Test
fun anyNode() {
assertTrue(sample().anyNode { it == 6 })
assertFalse(sample().anyNode { it == 99 })
}
@Test
fun allNodes() {
assertTrue(sample().allNodes { it > 0 })
assertFalse(sample().allNodes { it < 5 })
}
@Test
fun countNodes() = assertEquals(3, sample().countNodes { it > 3 })
@Test
fun foldNodes() = assertEquals(21, sample().foldNodes(0) { acc, node -> acc + node.value })
@Test
fun mapPreservesStructureAndTransformsValues() {
val mapped = sample().mapValues { it * 10 }
assertContentEquals(
listOf(10, 20, 40, 50, 30, 60),
mapped.preOrderSequence().map { it.value }.toList(),
)
}
@Test
fun deepCopyIsStructurallyEqualButDistinct() {
val original = sample()
val copy = original.deepCopy()
assertNotSame(original, copy)
assertTrue(original.structurallyEquals(copy))
}
@Test
fun structurallyEqualsDistinguishesByValueAndShape() {
assertTrue(sample().structurallyEquals(sample()))
val different = tree(1) {
child(2) { child(4) }
child(3) { child(6) }
}
assertFalse(sample().structurallyEquals(different))
}
}

View File

@@ -0,0 +1,66 @@
package com.github.adriankuta.datastructure.tree
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertSame
import kotlin.test.assertTrue
class TreeNodeNavigationTest {
private val root = TreeNode(1)
private val n2 = TreeNode(2)
private val n3 = TreeNode(3)
private val n4 = TreeNode(4)
private val n5 = TreeNode(5)
private val n6 = TreeNode(6)
init {
root.addChild(n2)
root.addChild(n3)
n2.addChild(n4)
n2.addChild(n5)
n3.addChild(n6)
}
@Test
fun isLeaf() {
assertTrue(n4.isLeaf)
assertFalse(root.isLeaf)
}
@Test
fun degree() {
assertEquals(2, root.degree)
assertEquals(0, n4.degree)
}
@Test
fun root() {
assertSame(root, n6.root())
assertSame(root, root.root())
}
@Test
fun ancestors() {
assertContentEquals(listOf(n2, root), n4.ancestors())
assertContentEquals(emptyList(), root.ancestors())
}
@Test
fun siblings() {
assertContentEquals(listOf(n5), n4.siblings())
assertContentEquals(emptyList(), root.siblings())
}
@Test
fun leaves() {
assertContentEquals(listOf(n4, n5, n6), root.leaves())
}
@Test
fun descendants() {
assertContentEquals(listOf(n2, n4, n5, n3, n6), root.descendants())
}
}

View File

@@ -0,0 +1,46 @@
package com.github.adriankuta.datastructure.tree
import com.github.adriankuta.datastructure.tree.iterators.TreeNodeIterators
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class TreeNodeSequenceTest {
private fun sample() = tree(1) {
child(2) {
child(4)
child(5)
}
child(3) {
child(6)
}
}
@Test
fun preOrderSequence() =
assertContentEquals(listOf(1, 2, 4, 5, 3, 6), sample().preOrderSequence().map { it.value }.toList())
@Test
fun postOrderSequence() =
assertContentEquals(listOf(4, 5, 2, 6, 3, 1), sample().postOrderSequence().map { it.value }.toList())
@Test
fun levelOrderSequence() =
assertContentEquals(listOf(1, 2, 3, 4, 5, 6), sample().levelOrderSequence().map { it.value }.toList())
@Test
fun asSequenceDefaultsToPreOrder() =
assertContentEquals(listOf(1, 2, 4, 5, 3, 6), sample().asSequence().map { it.value }.toList())
@Test
fun asSequenceHonorsExplicitOrder() =
assertContentEquals(
listOf(1, 2, 3, 4, 5, 6),
sample().asSequence(TreeNodeIterators.LevelOrder).map { it.value }.toList(),
)
@Test
fun sequenceShortCircuitsLazily() =
assertEquals(4, sample().preOrderSequence().map { it.value }.first { it == 4 })
}

View File

@@ -0,0 +1,47 @@
package com.github.adriankuta.datastructure.tree
import com.github.adriankuta.datastructure.tree.iterators.TreeNodeIterators
import kotlin.test.Test
import kotlin.test.assertEquals
/**
* A deep, degenerate (linear) tree must not overflow the call stack. These tests build a chain
* thousands of nodes deep — recursive implementations of [TreeNode.height], [TreeNode.nodeCount]
* and the post-order iterator blow the stack here, so they pin the iterative rewrites.
*/
class TreeNodeStackSafetyTest {
private val depth = 50_000
private fun deepChain(): TreeNode<Int> {
val root = TreeNode(0)
var current = root
for (i in 1..depth) {
val child = TreeNode(i)
current.addChild(child)
current = child
}
return root
}
@Test
fun heightDoesNotOverflowOnDeepTree() {
assertEquals(depth, deepChain().height())
}
@Test
fun nodeCountDoesNotOverflowOnDeepTree() {
// nodeCount() excludes the root, so a chain of `depth` extra nodes counts as `depth`.
assertEquals(depth, deepChain().nodeCount())
}
@Test
fun postOrderIterationDoesNotOverflowOnDeepTree() {
assertEquals(depth + 1, deepChain().asSequence(TreeNodeIterators.PostOrder).count())
}
@Test
fun preOrderIterationDoesNotOverflowOnDeepTree() {
assertEquals(depth + 1, deepChain().asSequence(TreeNodeIterators.PreOrder).count())
}
}

View File

@@ -4,7 +4,9 @@ import com.github.adriankuta.datastructure.tree.iterators.TreeNodeIterators
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertContentEquals import kotlin.test.assertContentEquals
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNull import kotlin.test.assertNull
import kotlin.test.assertTrue
class TreeNodeTest { class TreeNodeTest {
@@ -49,7 +51,7 @@ class TreeNodeTest {
) )
root.removeChild(curdNode) root.removeChild(curdNode)
root.removeChild(gingerTeaNode) gingerTeaNode.detach()
assertEquals( assertEquals(
"Root\n" + "Root\n" +
"└── Beverages\n" + "└── Beverages\n" +
@@ -62,6 +64,18 @@ class TreeNodeTest {
) )
} }
@Test
fun removeChildReturnsTrueWhenPresentFalseOtherwise() {
val root = TreeNode("Root")
val child = TreeNode("Child")
root.addChild(child)
assertTrue(root.removeChild(child), "Removing a present child returns true")
assertFalse(root.removeChild(child), "Removing an already-removed child returns false")
assertNull(child.parent, "Removed child is detached from its parent")
assertEquals(emptyList(), root.children)
}
@Test @Test
fun clearTest() { fun clearTest() {
val root = TreeNode("Root") val root = TreeNode("Root")

View File

@@ -0,0 +1,53 @@
package com.github.adriankuta.datastructure.tree
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertNull
class TreeNodeUtilitiesTest {
private val root = TreeNode(1)
private val a = TreeNode(2)
private val b = TreeNode(3)
init {
root.addChild(a)
a.addChild(b)
}
@Test
fun nodeCountCountsDescendantsExcludingRoot() {
assertEquals(0, TreeNode("solo").nodeCount())
assertEquals(2, root.nodeCount())
}
@Test
fun heightIsLongestEdgePathToLeaf() {
assertEquals(0, TreeNode("solo").height())
assertEquals(2, root.height())
assertEquals(1, a.height())
}
@Test
fun depthIsDistanceToRoot() {
assertEquals(0, root.depth())
assertEquals(1, a.depth())
assertEquals(2, b.depth())
}
@Test
fun pathReturnsDescendantToReceiverChain() {
assertContentEquals(listOf(b, a, root), root.path(b))
}
@Test
fun pathReturnsNullWhenNotADescendant() {
assertNull(root.path(TreeNode(99)))
}
@Test
fun pathReturnsNullWhenDescendantIsRootItself() {
assertNull(root.path(root))
}
}

View File

@@ -0,0 +1,105 @@
package com.github.adriankuta.datastructure.tree
import com.github.adriankuta.datastructure.tree.exceptions.TreeNodeException
import com.github.adriankuta.datastructure.tree.iterators.TreeNodeIterators
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertNull
import kotlin.test.assertSame
import kotlin.test.assertTrue
class TreeNodeV4Test {
@Test
fun addChildRejectsNodeThatAlreadyHasAParent() {
val a = TreeNode("a")
val b = TreeNode("b")
a.addChild(b)
val other = TreeNode("other")
assertFailsWith<TreeNodeException> { other.addChild(b) }
}
@Test
fun addChildRejectsCycles() {
val root = TreeNode("root")
val child = TreeNode("child")
root.addChild(child)
// Attaching an ancestor under its own descendant would create a cycle.
assertFailsWith<TreeNodeException> { child.addChild(root) }
// Attaching a node under itself is also a cycle.
assertFailsWith<TreeNodeException> { root.addChild(root) }
}
@Test
fun detachRemovesFromParent() {
val root = TreeNode("root")
val child = TreeNode("child")
root.addChild(child)
assertTrue(child.detach())
assertNull(child.parent)
assertContentEquals(emptyList(), root.children)
// Detached node can now be re-attached elsewhere.
val newParent = TreeNode("newParent")
newParent.addChild(child)
assertSame(newParent, child.parent)
}
@Test
fun detachOnRootReturnsFalse() {
assertFalse(TreeNode("root").detach())
}
@Test
fun removeChildOnlyRemovesDirectChildren() {
val root = TreeNode("root")
val parent = TreeNode("parent")
val grandchild = TreeNode("grandchild")
root.addChild(parent)
parent.addChild(grandchild)
// grandchild is not a direct child of root -> no-op, returns false.
assertFalse(root.removeChild(grandchild))
assertSame(parent, grandchild.parent)
// direct child removal works.
assertTrue(parent.removeChild(grandchild))
assertNull(grandchild.parent)
}
@Test
fun clearOnNonRootKeepsItAttachedToItsParent() {
val root = TreeNode("root")
val branch = TreeNode("branch")
val leaf = TreeNode("leaf")
root.addChild(branch)
branch.addChild(leaf)
branch.clear()
assertContentEquals(emptyList(), branch.children)
assertSame(root, branch.parent) // branch stays attached to root
assertContentEquals(listOf(branch), root.children)
assertNull(leaf.parent) // former descendant is detached
}
@Test
fun iteratorAcceptsExplicitOrderWithoutMutatingDefault() {
val tree = tree(1) {
child(2) { child(4) }
child(3)
}
val postOrder = tree.iterator(TreeNodeIterators.PostOrder).asSequence().map { it.value }.toList()
assertContentEquals(listOf(4, 2, 3, 1), postOrder)
// Default order is unchanged (PreOrder).
assertEquals(TreeNodeIterators.PreOrder, tree.treeIterator)
assertContentEquals(listOf(1, 2, 4, 3), tree.map { it.value })
}
}

View File

@@ -1,14 +0,0 @@
import com.github.adriankuta.datastructure.tree.tree
val root =
tree("World") {
child("North America") {
child("USA")
}
child("Europe") {
child("Poland")
child("Germany")
}
}
print(root.prettyString())

View File

@@ -0,0 +1,4 @@
public final class com/github/adriankuta/datastructure/tree/compose/LazyTreeKt {
public static final fun LazyTree (Lcom/github/adriankuta/datastructure/tree/TreeNode;Landroidx/compose/ui/Modifier;ZLkotlin/jvm/functions/Function6;Landroidx/compose/runtime/Composer;II)V
}

View File

@@ -0,0 +1,74 @@
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
alias(libs.plugins.dokka)
alias(libs.plugins.mavenPublish)
signing
}
group = "com.github.adriankuta"
version = rootProject.version
mavenPublishing {
publishToMavenCentral(automaticRelease = false)
signAllPublications()
coordinates("com.github.adriankuta", "tree-structure-compose", version.toString())
pom {
name.set("Tree Data Structure — Compose Multiplatform")
description.set("A LazyTree composable (expand/collapse, lazy rendering) for the tree-structure library.")
url.set("https://github.com/AdrianKuta/Tree-Data-Structure")
licenses {
license {
name.set("MIT License")
url.set("https://opensource.org/licenses/MIT")
distribution.set("repo")
}
}
developers {
developer {
id.set("AdrianKuta")
name.set("Adrian Kuta")
email.set("adrian.kuta93@gmail.com")
}
}
scm {
url.set("https://github.com/AdrianKuta/Tree-Data-Structure")
connection.set("scm:git:https://github.com/AdrianKuta/Tree-Data-Structure.git")
developerConnection.set("scm:git:ssh://git@github.com/AdrianKuta/Tree-Data-Structure.git")
}
}
}
repositories {
mavenCentral()
google()
}
kotlin {
explicitApi()
jvmToolchain(21)
jvm()
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser()
}
iosX64()
iosArm64()
iosSimulatorArm64()
sourceSets {
commonMain.dependencies {
api(project(":"))
implementation(compose.runtime)
implementation(compose.foundation)
}
}
}

View File

@@ -0,0 +1,71 @@
package com.github.adriankuta.datastructure.tree.compose
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.github.adriankuta.datastructure.tree.TreeNode
/**
* A lazily-rendered, expand/collapse tree for Compose Multiplatform. Only the currently-visible
* nodes are composed, so it scales to large trees. Expansion state is remembered internally, keyed
* by node identity.
*
* ```
* LazyTree(root) { node, depth, expanded, toggle ->
* Row(Modifier.padding(start = (depth * 16).dp).clickable(onClick = toggle)) {
* if (!node.isLeaf) Text(if (expanded) "▾" else "▸")
* Text(node.value.toString())
* }
* }
* ```
*
* @param root the root of the tree to display.
* @param modifier the [Modifier] applied to the underlying [LazyColumn].
* @param initiallyExpanded whether nodes start expanded.
* @param nodeContent renders a single node. Receives the node, its depth (root = 0), whether it is
* expanded, and a `toggle` callback that flips this node's expansion state.
*/
@Composable
public fun <T> LazyTree(
root: TreeNode<T>,
modifier: Modifier = Modifier,
initiallyExpanded: Boolean = true,
nodeContent: @Composable (node: TreeNode<T>, depth: Int, expanded: Boolean, toggle: () -> Unit) -> Unit,
) {
val expansion = remember(root) { mutableStateMapOf<TreeNode<T>, Boolean>() }
val isExpanded: (TreeNode<T>) -> Boolean = { node -> expansion[node] ?: initiallyExpanded }
val visible = flattenVisible(root, isExpanded)
LazyColumn(modifier = modifier) {
items(visible.size) { index ->
val (node, depth) = visible[index]
nodeContent(node, depth, isExpanded(node)) {
expansion[node] = !isExpanded(node)
}
}
}
}
/**
* Flattens the tree into the list of currently-visible `(node, depth)` pairs in pre-order, skipping
* the subtrees of collapsed nodes. Iterative, so it is safe on deep trees.
*/
private fun <T> flattenVisible(
root: TreeNode<T>,
isExpanded: (TreeNode<T>) -> Boolean,
): List<Pair<TreeNode<T>, Int>> {
val result = mutableListOf<Pair<TreeNode<T>, Int>>()
val stack = ArrayDeque<Pair<TreeNode<T>, Int>>()
stack.addLast(root to 0)
while (stack.isNotEmpty()) {
val (node, depth) = stack.removeLast()
result.add(node to depth)
if (isExpanded(node)) {
node.children.asReversed().forEach { child -> stack.addLast(child to depth + 1) }
}
}
return result
}

View File

@@ -0,0 +1,8 @@
public final class com/github/adriankuta/datastructure/tree/coroutines/TreeNodeFlowExtKt {
public static final fun asFlow (Lcom/github/adriankuta/datastructure/tree/TreeNode;Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;)Lkotlinx/coroutines/flow/Flow;
public static synthetic fun asFlow$default (Lcom/github/adriankuta/datastructure/tree/TreeNode;Lcom/github/adriankuta/datastructure/tree/iterators/TreeNodeIterators;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
public static final fun levelOrderFlow (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Lkotlinx/coroutines/flow/Flow;
public static final fun postOrderFlow (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Lkotlinx/coroutines/flow/Flow;
public static final fun preOrderFlow (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Lkotlinx/coroutines/flow/Flow;
}

View File

@@ -0,0 +1,89 @@
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.dokka)
alias(libs.plugins.mavenPublish)
signing
}
group = "com.github.adriankuta"
version = rootProject.version
mavenPublishing {
publishToMavenCentral(automaticRelease = false)
signAllPublications()
coordinates("com.github.adriankuta", "tree-structure-coroutines", version.toString())
pom {
name.set("Tree Data Structure — coroutines")
description.set("kotlinx.coroutines Flow traversal for the tree-structure library.")
url.set("https://github.com/AdrianKuta/Tree-Data-Structure")
licenses {
license {
name.set("MIT License")
url.set("https://opensource.org/licenses/MIT")
distribution.set("repo")
}
}
developers {
developer {
id.set("AdrianKuta")
name.set("Adrian Kuta")
email.set("adrian.kuta93@gmail.com")
}
}
scm {
url.set("https://github.com/AdrianKuta/Tree-Data-Structure")
connection.set("scm:git:https://github.com/AdrianKuta/Tree-Data-Structure.git")
developerConnection.set("scm:git:ssh://git@github.com/AdrianKuta/Tree-Data-Structure.git")
}
}
}
repositories {
mavenCentral()
}
kotlin {
explicitApi()
jvmToolchain(21)
jvm()
js(IR) {
browser()
nodejs()
}
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser()
nodejs()
}
iosX64()
iosArm64()
iosSimulatorArm64()
val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows")
when {
hostOs == "Mac OS X" -> macosX64("native")
hostOs == "Linux" -> linuxX64("native")
isMingwX64 -> mingwX64("native")
else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
}
sourceSets {
commonMain.dependencies {
api(project(":"))
api(libs.kotlinx.coroutines.core)
}
commonTest.dependencies {
implementation(kotlin("test"))
implementation(libs.kotlinx.coroutines.test)
}
}
}

View File

@@ -0,0 +1,24 @@
package com.github.adriankuta.datastructure.tree.coroutines
import com.github.adriankuta.datastructure.tree.TreeNode
import com.github.adriankuta.datastructure.tree.asSequence
import com.github.adriankuta.datastructure.tree.iterators.TreeNodeIterators
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
/**
* Emits this node and all of its descendants as a cold [Flow], traversed in the given [order].
* Useful for plugging tree traversal into coroutine/Flow pipelines (e.g. in a ViewModel).
*/
public fun <T> TreeNode<T>.asFlow(
order: TreeNodeIterators = TreeNodeIterators.PreOrder,
): Flow<TreeNode<T>> = asSequence(order).asFlow()
/** Pre-order traversal as a cold [Flow]. */
public fun <T> TreeNode<T>.preOrderFlow(): Flow<TreeNode<T>> = asFlow(TreeNodeIterators.PreOrder)
/** Post-order traversal as a cold [Flow]. */
public fun <T> TreeNode<T>.postOrderFlow(): Flow<TreeNode<T>> = asFlow(TreeNodeIterators.PostOrder)
/** Level-order (breadth-first) traversal as a cold [Flow]. */
public fun <T> TreeNode<T>.levelOrderFlow(): Flow<TreeNode<T>> = asFlow(TreeNodeIterators.LevelOrder)

View File

@@ -0,0 +1,35 @@
package com.github.adriankuta.datastructure.tree.coroutines
import com.github.adriankuta.datastructure.tree.iterators.TreeNodeIterators
import com.github.adriankuta.datastructure.tree.tree
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
class TreeNodeFlowTest {
private fun sample() = tree(1) {
child(2) {
child(4)
child(5)
}
child(3) {
child(6)
}
}
@Test
fun preOrderFlowEmitsInPreOrder() = runTest {
assertEquals(listOf(1, 2, 4, 5, 3, 6), sample().preOrderFlow().map { it.value }.toList())
}
@Test
fun levelOrderFlowEmitsInLevelOrder() = runTest {
assertEquals(
listOf(1, 2, 3, 4, 5, 6),
sample().asFlow(TreeNodeIterators.LevelOrder).map { it.value }.toList(),
)
}
}

View File

@@ -0,0 +1,35 @@
public final class com/github/adriankuta/datastructure/tree/serialization/TreeNodeDto {
public static final field Companion Lcom/github/adriankuta/datastructure/tree/serialization/TreeNodeDto$Companion;
public fun <init> (Ljava/lang/Object;Ljava/util/List;)V
public synthetic fun <init> (Ljava/lang/Object;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/Object;
public final fun component2 ()Ljava/util/List;
public final fun copy (Ljava/lang/Object;Ljava/util/List;)Lcom/github/adriankuta/datastructure/tree/serialization/TreeNodeDto;
public static synthetic fun copy$default (Lcom/github/adriankuta/datastructure/tree/serialization/TreeNodeDto;Ljava/lang/Object;Ljava/util/List;ILjava/lang/Object;)Lcom/github/adriankuta/datastructure/tree/serialization/TreeNodeDto;
public fun equals (Ljava/lang/Object;)Z
public final fun getChildren ()Ljava/util/List;
public final fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public synthetic class com/github/adriankuta/datastructure/tree/serialization/TreeNodeDto$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public fun <init> (Lkotlinx/serialization/KSerializer;)V
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/github/adriankuta/datastructure/tree/serialization/TreeNodeDto;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/github/adriankuta/datastructure/tree/serialization/TreeNodeDto;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public final fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}
public final class com/github/adriankuta/datastructure/tree/serialization/TreeNodeDto$Companion {
public final fun serializer (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;
}
public final class com/github/adriankuta/datastructure/tree/serialization/TreeNodeDtoKt {
public static final fun toDto (Lcom/github/adriankuta/datastructure/tree/TreeNode;)Lcom/github/adriankuta/datastructure/tree/serialization/TreeNodeDto;
public static final fun toTreeNode (Lcom/github/adriankuta/datastructure/tree/serialization/TreeNodeDto;)Lcom/github/adriankuta/datastructure/tree/TreeNode;
}

View File

@@ -0,0 +1,89 @@
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.kotlinSerialization)
alias(libs.plugins.dokka)
alias(libs.plugins.mavenPublish)
signing
}
group = "com.github.adriankuta"
version = rootProject.version
mavenPublishing {
publishToMavenCentral(automaticRelease = false)
signAllPublications()
coordinates("com.github.adriankuta", "tree-structure-serialization", version.toString())
pom {
name.set("Tree Data Structure — kotlinx.serialization")
description.set("kotlinx.serialization support (TreeNodeDto round-trip) for the tree-structure library.")
url.set("https://github.com/AdrianKuta/Tree-Data-Structure")
licenses {
license {
name.set("MIT License")
url.set("https://opensource.org/licenses/MIT")
distribution.set("repo")
}
}
developers {
developer {
id.set("AdrianKuta")
name.set("Adrian Kuta")
email.set("adrian.kuta93@gmail.com")
}
}
scm {
url.set("https://github.com/AdrianKuta/Tree-Data-Structure")
connection.set("scm:git:https://github.com/AdrianKuta/Tree-Data-Structure.git")
developerConnection.set("scm:git:ssh://git@github.com/AdrianKuta/Tree-Data-Structure.git")
}
}
}
repositories {
mavenCentral()
}
kotlin {
explicitApi()
jvmToolchain(21)
jvm()
js(IR) {
browser()
nodejs()
}
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser()
nodejs()
}
iosX64()
iosArm64()
iosSimulatorArm64()
val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows")
when {
hostOs == "Mac OS X" -> macosX64("native")
hostOs == "Linux" -> linuxX64("native")
isMingwX64 -> mingwX64("native")
else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
}
sourceSets {
commonMain.dependencies {
api(project(":"))
api(libs.kotlinx.serialization.json)
}
commonTest.dependencies {
implementation(kotlin("test"))
}
}
}

View File

@@ -0,0 +1,30 @@
package com.github.adriankuta.datastructure.tree.serialization
import com.github.adriankuta.datastructure.tree.TreeNode
import kotlinx.serialization.Serializable
/**
* A serializable, acyclic view of a [TreeNode] subtree. [TreeNode] itself holds a back-reference to
* its parent (a cycle), so it cannot be `@Serializable` directly — convert to/from this DTO instead.
*
* ```
* val json = Json.encodeToString(tree.toDto())
* val restored = Json.decodeFromString<TreeNodeDto<String>>(json).toTreeNode()
* ```
*/
@Serializable
public data class TreeNodeDto<T>(
public val value: T,
public val children: List<TreeNodeDto<T>> = emptyList(),
)
/** Converts this subtree into a serializable [TreeNodeDto], preserving values and shape. */
public fun <T> TreeNode<T>.toDto(): TreeNodeDto<T> =
TreeNodeDto(value, children.map { it.toDto() })
/** Rebuilds a mutable [TreeNode] tree from this DTO. */
public fun <T> TreeNodeDto<T>.toTreeNode(): TreeNode<T> {
val node = TreeNode(value)
children.forEach { node.addChild(it.toTreeNode()) }
return node
}

View File

@@ -0,0 +1,40 @@
package com.github.adriankuta.datastructure.tree.serialization
import com.github.adriankuta.datastructure.tree.structurallyEquals
import com.github.adriankuta.datastructure.tree.tree
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class TreeNodeSerializationTest {
@Test
fun roundTripsThroughJson() {
val original = tree("World") {
child("North America") { child("USA") }
child("Europe") {
child("Poland")
child("Germany")
}
}
val json = Json.encodeToString(original.toDto())
val restored = Json.decodeFromString<TreeNodeDto<String>>(json).toTreeNode()
assertTrue(original.structurallyEquals(restored))
}
@Test
fun dtoMirrorsTreeShape() {
val dto = tree(1) {
child(2)
child(3) { child(4) }
}.toDto()
assertEquals(1, dto.value)
assertEquals(2, dto.children.size)
assertEquals(4, dto.children[1].children[0].value)
}
}