Skip to content

Commit 0a51ddc

Browse files
committed
zdl-kotlin: refactor FluentMap to extension methods
1 parent 73d3570 commit 0a51ddc

File tree

8 files changed

+226
-123
lines changed

8 files changed

+226
-123
lines changed

CONTRIBUTING.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Contributing to ZDL Kotlin
2+
3+
## Building Locally
4+
5+
### Prerequisites
6+
- JDK 17 or higher
7+
- Node.js 18 or higher (for JS/NPM package)
8+
9+
### Build Commands
10+
11+
```bash
12+
# Build the project
13+
./gradlew build
14+
15+
# Publish to local Maven repository
16+
./gradlew clean publishToMavenLocal
17+
18+
# Run tests
19+
./gradlew test
20+
21+
# Run tests with coverage
22+
./gradlew build koverHtmlReport
23+
24+
# Build JS package and run Node.js integration tests
25+
./gradlew nodeIntegrationTest
26+
```
27+
28+
## Release Process
29+
30+
### 1. Create a Release
31+
32+
Trigger the **Create Gradle Release** workflow from GitHub Actions:
33+
34+
1. Go to **Actions****Create Gradle Release****Run workflow**
35+
2. Enter the release version (e.g., `1.5.0`)
36+
3. Enter the next development version (e.g., `1.6.0-SNAPSHOT`)
37+
38+
This workflow will:
39+
- Update version in `build.gradle.kts` to the release version
40+
- Create a git tag `v{version}`
41+
- Update version to the next development version
42+
- Create a PR with the changes
43+
- Auto-merge the PR
44+
- Push the release tag
45+
46+
### 2. Publish the Release
47+
48+
After the tag is created, create a GitHub Release:
49+
50+
1. Go to **Releases****Draft a new release**
51+
2. Select the tag created in step 1 (e.g., `v1.5.0`)
52+
3. Generate release notes or write your own
53+
4. Publish the release
54+
55+
This automatically triggers the **Publish Release to Maven Central and NPM** workflow, which:
56+
- Builds and tests the project
57+
- Publishes to Maven Central
58+
- Publishes to NPM registry as `@zenwave360/zdl`
59+
60+
### 3. Snapshot Releases
61+
62+
Snapshots are automatically published when pushing to `develop` or `next` branches via the **Build and Publish Snapshots** workflow.
63+
64+
> **Note**: Snapshot publishing to Maven Central is currently disabled. Enable by uncommenting the publish step in `.github/workflows/publish-snapshots.yml`.
65+
66+
## Required Secrets
67+
68+
The following GitHub secrets must be configured for releases:
69+
70+
- `CENTRAL_USERNAME` - Maven Central username
71+
- `CENTRAL_TOKEN` - Maven Central token
72+
- `SIGN_KEY` - GPG signing key
73+
- `SIGN_KEY_PASS` - GPG signing key password
74+
- `NPM_TOKEN` - NPM authentication token
75+

nodejs-test-project/package-lock.json

Lines changed: 1 addition & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/commonMain/kotlin/io/zenwave360/zdl/ZdlParser.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class ZdlParser {
3030
return this
3131
}
3232

33-
fun parseModel(model: String): ZdlModel {
33+
fun parseModel(model: String): Map<String, Any?> {
3434
val zdl = CharStreams.fromString(model)
3535
val lexer = ZdlLexer(zdl)
3636
val tokens = CommonTokenStream(lexer)
@@ -49,7 +49,7 @@ class ZdlParser {
4949
} catch (e: Exception) {
5050
e.printStackTrace()
5151
}
52-
return zdlModel
52+
return zdlModel.asJavaMap()
5353
}
5454
}
5555

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,64 @@
11
package io.zenwave360.zdl.antlr
22

3-
class FluentMap private constructor(
4-
private val backingMap: MutableMap<String, Any?> = linkedMapOf()
5-
) : MutableMap<String, Any?> by backingMap {
6-
7-
companion object {
8-
fun build(block: FluentMap.() -> Unit = {}): FluentMap =
9-
FluentMap(linkedMapOf()).apply(block)
10-
}
11-
12-
// Provide access to underlying Java Map (useful for JSONPath on JVM)
13-
fun asJavaMap(): MutableMap<String, Any?> = backingMap
14-
15-
// Idiomatic API (avoid signature clash with MutableMap.put)
16-
fun putEntry(key: String, value: Any?): FluentMap = apply { backingMap[key] = value }
17-
fun putAllEntries(map: Map<String, Any?>): FluentMap = apply { backingMap.putAll(map) }
18-
19-
fun appendTo(collection: String, key: String, value: Any?): FluentMap = apply {
20-
val nestedMap = backingMap.getOrPut(collection) { linkedMapOf<String, Any?>() } as MutableMap<String, Any?>
21-
nestedMap[key] = value
22-
}
23-
24-
fun appendToWithMap(collection: String, map: Map<String, Any?>): FluentMap = apply {
25-
val nestedMap = backingMap.getOrPut(collection) { linkedMapOf<String, Any?>() } as MutableMap<String, Any?>
26-
nestedMap.putAll(map)
27-
}
28-
29-
fun appendToList(collection: String, value: Any?): FluentMap = apply {
30-
val nestedList = backingMap.getOrPut(collection) { mutableListOf<Any?>() } as MutableList<Any?>
31-
nestedList.add(value)
32-
}
33-
34-
// Compatibility API (to be refactored later)
35-
fun with(key: String, value: Any?): FluentMap = putEntry(key, value)
3+
/**
4+
* Utility functions for building and manipulating MutableMap instances with a fluent API.
5+
* These replace the previous FluentMap class to avoid ClassCastException issues with Java interop.
6+
*/
7+
8+
/**
9+
* Build a new MutableMap with optional initialization block.
10+
*/
11+
fun buildMap(block: MutableMap<String, Any?>.() -> Unit = {}): MutableMap<String, Any?> =
12+
linkedMapOf<String, Any?>().apply(block)
13+
14+
/**
15+
* Put a key-value pair and return the map for chaining.
16+
*/
17+
fun MutableMap<String, Any?>.with(key: String, value: Any?): MutableMap<String, Any?> =
18+
apply { this[key] = value }
19+
20+
/**
21+
* Put a key-value pair and return the map for chaining (alias for with).
22+
*/
23+
fun MutableMap<String, Any?>.putEntry(key: String, value: Any?): MutableMap<String, Any?> =
24+
apply { this[key] = value }
25+
26+
/**
27+
* Put all entries from another map and return the map for chaining.
28+
*/
29+
fun MutableMap<String, Any?>.putAllEntries(map: Map<String, Any?>): MutableMap<String, Any?> =
30+
apply { this.putAll(map) }
31+
32+
/**
33+
* Append a key-value pair to a nested map within this map.
34+
* If the collection doesn't exist, it will be created as a LinkedHashMap.
35+
*/
36+
fun MutableMap<String, Any?>.appendTo(collection: String, key: String, value: Any?): MutableMap<String, Any?> = apply {
37+
val nestedMap = this.getOrPut(collection) { linkedMapOf<String, Any?>() } as MutableMap<String, Any?>
38+
nestedMap[key] = value
3639
}
3740

41+
/**
42+
* Append all entries from a map to a nested map within this map.
43+
* If the collection doesn't exist, it will be created as a LinkedHashMap.
44+
*/
45+
fun MutableMap<String, Any?>.appendToWithMap(collection: String, map: Map<String, Any?>): MutableMap<String, Any?> = apply {
46+
val nestedMap = this.getOrPut(collection) { linkedMapOf<String, Any?>() } as MutableMap<String, Any?>
47+
nestedMap.putAll(map)
48+
}
49+
50+
/**
51+
* Append a value to a nested list within this map.
52+
* If the collection doesn't exist, it will be created as a MutableList.
53+
*/
54+
fun MutableMap<String, Any?>.appendToList(collection: String, value: Any?): MutableMap<String, Any?> = apply {
55+
val nestedList = this.getOrPut(collection) { mutableListOf<Any?>() } as MutableList<Any?>
56+
nestedList.add(value)
57+
}
58+
59+
/**
60+
* Returns this map (useful for Java interop compatibility).
61+
* Previously used to unwrap FluentMap to underlying map.
62+
*/
63+
fun MutableMap<String, Any?>.asJavaMap(): MutableMap<String, Any?> = this
64+

0 commit comments

Comments
 (0)