Skip to content

Commit 056d8b4

Browse files
authored
Merge pull request #13 from aether-framework/feature/release-ready-for-0.2.0-without-version-bump
Update to version 0.2.0 with new features and improvements
2 parents 6edbe8f + 181c982 commit 056d8b4

8 files changed

Lines changed: 128 additions & 38 deletions

File tree

CHANGELOG.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,65 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
66

77
---
88

9+
## [0.2.0] - 2026-01-06
10+
11+
### Added
12+
13+
#### Testkit Module (`aether-datafixers-testkit`)
14+
- **TestData** — Fluent builders for creating test data (`TestData.gson().object()...`)
15+
- **AetherAssertions** — Custom AssertJ assertions for `Dynamic`, `DataResult`, `Typed`
16+
- **DataFixTester** — Test harness for isolated DataFix testing with fluent API
17+
- **MigrationTester** — Test harness for full migration chain testing
18+
- **SchemaTester** — Test harness for schema validation
19+
- **QuickFix** — Factory methods for common fix patterns (rename, add, remove, transform)
20+
- **MockSchemas** — Mock schema utilities for testing
21+
- **RecordingContext** — Context that records warnings for test verification
22+
23+
#### Migration Diagnostics
24+
- **DiagnosticContext** — Opt-in diagnostic context for capturing migration reports
25+
- **DiagnosticOptions** — Configurable options (snapshots, rule details, pretty print)
26+
- **MigrationReport** — Structured report with timing, applied fixes, and touched types
27+
- **FixExecution** — Per-fix execution details with before/after snapshots
28+
- **RuleApplication** — Per-rule application details
29+
30+
#### Extended Rewrite Rules
31+
- `Rules.renameFields(ops, map)` — Batch rename multiple fields
32+
- `Rules.removeFields(ops, fields...)` — Batch remove multiple fields
33+
- `Rules.groupFields(ops, target, fields...)` — Group flat fields into nested object
34+
- `Rules.flattenField(ops, field)` — Flatten nested object to root level
35+
- `Rules.moveField(ops, source, target)` — Move field between paths
36+
- `Rules.copyField(ops, source, target)` — Copy field to new location
37+
- `Rules.transformFieldAt(ops, path, fn)` — Transform at nested path
38+
- `Rules.renameFieldAt(ops, path, newName)` — Rename at nested path
39+
- `Rules.removeFieldAt(ops, path)` — Remove at nested path
40+
- `Rules.addFieldAt(ops, path, value)` — Add at nested path
41+
- `Rules.ifFieldExists(ops, field, rule)` — Conditional on field existence
42+
- `Rules.ifFieldMissing(ops, field, rule)` — Conditional on field absence
43+
- `Rules.ifFieldEquals(ops, field, value, rule)` — Conditional on field value
44+
45+
#### High-Performance APIs
46+
- **BatchTransform** — Builder for batching multiple field operations
47+
- `Rules.batch(ops, builder)` — Apply multiple operations in single encode/decode cycle
48+
- `Rules.conditionalTransform(ops, predicate, transform)` — Single-pass conditional transform
49+
- `Rules.ifFieldExists(ops, field, transform)` — Single-pass version (Function overload)
50+
- `Rules.ifFieldMissing(ops, field, transform)` — Single-pass version (Function overload)
51+
- `Rules.ifFieldEquals(ops, field, value, transform)` — Single-pass version (Function overload)
52+
53+
### Changed
54+
55+
#### Performance Optimizations
56+
- Path parsing now uses character-based parsing instead of regex with memoization cache
57+
- `DataFixRegistry.getFixes()` pre-allocates result list and avoids second copy
58+
- `DataFixerImpl` removes redundant validation in hot path (moved to registration time)
59+
- Fix version ordering validated once at registration instead of per-application
60+
61+
### Documentation
62+
- Added comprehensive how-to guides for all extended rules
63+
- Added migration diagnostics usage guide
64+
- Updated quick reference with new APIs (including Testkit module)
65+
66+
---
67+
968
## [0.1.0] - 2025-12-22
1069

1170
### 🎉 Initial Release

README.md

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
![License](https://img.shields.io/badge/license-MIT-red)
22
![Maven Central](https://img.shields.io/maven-central/v/de.splatgames.aether/aether-datafixers)
3-
![Version](https://img.shields.io/badge/version-0.1.0-orange)
3+
![Version](https://img.shields.io/badge/version-0.2.0-orange)
44

55
# Aether Datafixers 🔧
66

@@ -10,14 +10,17 @@ inspired by Minecraft's DataFixer Upper (DFU), with a focus on **simplicity**, *
1010

1111
---
1212

13-
## ✨ Features (v0.1.0)
13+
## ✨ Features (v0.2.0)
1414

1515
-**Schema-Based Versioning** — Define data types per version with `Schema` and `TypeRegistry`
1616
-**Forward Patching** — Apply `DataFix` instances sequentially to migrate data across versions
1717
-**Format-Agnostic** — Work with any serialization format via `Dynamic<T>` and `DynamicOps<T>`
1818
-**Codec System** — Bidirectional transformation between typed Java objects and dynamic representations
1919
-**Type Safety** — Strong typing with `TypeReference` identifiers for data routing
2020
-**Testkit** — Fluent test data builders, custom assertions, and test harnesses for DataFix testing
21+
-**Migration Diagnostics** — Opt-in structured reports with timing, applied fixes, and snapshots
22+
-**Extended Rewrite Rules** — Batch operations, path-based transforms, conditional rules
23+
-**High-Performance APIs**`Rules.batch()` for single-pass multi-operation transforms
2124
-**JDK 17+** — Built and tested on modern LTS JVMs
2225

2326
---
@@ -79,23 +82,23 @@ Dynamic<?> updated = fixer.update(
7982
<dependency>
8083
<groupId>de.splatgames.aether</groupId>
8184
<artifactId>aether-datafixers-core</artifactId>
82-
<version>0.1.0</version>
85+
<version>0.2.0</version>
8386
</dependency>
8487
```
8588

8689
**Gradle (Groovy)**
8790

8891
```groovy
8992
dependencies {
90-
implementation 'de.splatgames.aether:aether-datafixers-core:0.1.0'
93+
implementation 'de.splatgames.aether:aether-datafixers-core:0.2.0'
9194
}
9295
```
9396

9497
**Gradle (Kotlin)**
9598

9699
```kotlin
97100
dependencies {
98-
implementation("de.splatgames.aether:aether-datafixers-core:0.1.0")
101+
implementation("de.splatgames.aether:aether-datafixers-core:0.2.0")
99102
}
100103
```
101104

@@ -115,7 +118,7 @@ The Bill of Materials (BOM) ensures consistent versions across all Aether Datafi
115118
<dependency>
116119
<groupId>de.splatgames.aether</groupId>
117120
<artifactId>aether-datafixers-bom</artifactId>
118-
<version>0.1.0</version>
121+
<version>0.2.0</version>
119122
<type>pom</type>
120123
<scope>import</scope>
121124
</dependency>
@@ -139,7 +142,7 @@ The Bill of Materials (BOM) ensures consistent versions across all Aether Datafi
139142

140143
```groovy
141144
dependencies {
142-
implementation platform('de.splatgames.aether:aether-datafixers-bom:0.1.0')
145+
implementation platform('de.splatgames.aether:aether-datafixers-bom:0.2.0')
143146
144147
// No version needed
145148
implementation 'de.splatgames.aether:aether-datafixers-core'
@@ -151,7 +154,7 @@ dependencies {
151154

152155
```kotlin
153156
dependencies {
154-
implementation(platform("de.splatgames.aether:aether-datafixers-bom:0.1.0"))
157+
implementation(platform("de.splatgames.aether:aether-datafixers-bom:0.2.0"))
155158

156159
// No version needed
157160
implementation("de.splatgames.aether:aether-datafixers-core")
@@ -400,20 +403,21 @@ mvn test
400403

401404
## 🗺️ Roadmap
402405

403-
- **v0.1.0** (current)
406+
- **v0.1.0**
404407
- Core API and default implementations
405408
- Schema-based versioning with TypeRegistry
406409
- DataFix forward patching system
407410
- Dynamic/DynamicOps format abstraction
408411
- Basic codec infrastructure
409412

410-
- **v0.2.0** (next)
413+
- **v0.2.0** (current)
411414
- **Testkit module** — Fluent test data builders, custom AssertJ assertions, test harnesses
412-
- **Migration diagnostics** — Optional structured report (applied fixes, touched types, timing)
413-
- **Extended rewrite rules** — Common operations like nested rename/move/copy helpers
414-
- **Performance optimizations** — Caching, lazy evaluation improvements (doesn't change API or determinism)
415+
- **Migration diagnostics** — Opt-in structured reports with timing, applied fixes, and snapshots
416+
- **Extended rewrite rules** — Batch operations, path-based transforms, conditional rules
417+
- **High-performance APIs**`Rules.batch()` and single-pass conditional transforms
418+
- **Performance optimizations** — Path caching, optimized fix registry, reduced allocations
415419

416-
- **v0.3.0**
420+
- **v0.3.0** (next)
417421
- **CLI module** — Migrate files and print/export a migration report (batch-friendly)
418422
- **Schema tooling** — Runtime schema validation + diff utilities between versions
419423

aether-datafixers-api/src/main/java/de/splatgames/aether/datafixers/api/rewrite/BatchTransform.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
* @param <T> the underlying data format type (e.g., JsonElement)
7676
* @author Erik Pförtner
7777
* @see Rules#batch(DynamicOps, java.util.function.Consumer)
78-
* @since 0.3.0
78+
* @since 0.2.0
7979
*/
8080
public final class BatchTransform<T> {
8181

aether-datafixers-api/src/main/java/de/splatgames/aether/datafixers/api/rewrite/Rules.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,7 +1128,7 @@ public static <T> TypeRewriteRule transformField(@NotNull final DynamicOps<T> op
11281128
* @return a rule that applies all operations in a single pass, never {@code null}
11291129
* @throws NullPointerException if any argument is {@code null}
11301130
* @see BatchTransform
1131-
* @since 0.3.0
1131+
* @since 0.2.0
11321132
*/
11331133
@NotNull
11341134
public static <T> TypeRewriteRule batch(@NotNull final DynamicOps<T> ops,
@@ -2013,7 +2013,7 @@ public String toString() {
20132013
* @param transform the transformation to apply if condition is true, must not be {@code null}
20142014
* @return a conditional rule that operates in a single pass, never {@code null}
20152015
* @throws NullPointerException if any argument is {@code null}
2016-
* @since 0.3.0
2016+
* @since 0.2.0
20172017
*/
20182018
@NotNull
20192019
public static <T> TypeRewriteRule conditionalTransform(
@@ -2059,7 +2059,7 @@ public static <T> TypeRewriteRule conditionalTransform(
20592059
* @param transform the transformation to apply if field exists, must not be {@code null}
20602060
* @return a conditional rule that operates in a single pass, never {@code null}
20612061
* @throws NullPointerException if any argument is {@code null}
2062-
* @since 0.3.0
2062+
* @since 0.2.0
20632063
*/
20642064
@NotNull
20652065
public static <T> TypeRewriteRule ifFieldExists(
@@ -2105,7 +2105,7 @@ public static <T> TypeRewriteRule ifFieldExists(
21052105
* @param transform the transformation to apply if field is missing, must not be {@code null}
21062106
* @return a conditional rule that operates in a single pass, never {@code null}
21072107
* @throws NullPointerException if any argument is {@code null}
2108-
* @since 0.3.0
2108+
* @since 0.2.0
21092109
*/
21102110
@NotNull
21112111
public static <T> TypeRewriteRule ifFieldMissing(
@@ -2154,7 +2154,7 @@ public static <T> TypeRewriteRule ifFieldMissing(
21542154
* @param transform the transformation to apply if field equals value, must not be {@code null}
21552155
* @return a conditional rule that operates in a single pass, never {@code null}
21562156
* @throws NullPointerException if any argument is {@code null}
2157-
* @since 0.3.0
2157+
* @since 0.2.0
21582158
*/
21592159
@NotNull
21602160
public static <T, V> TypeRewriteRule ifFieldEquals(

docs/appendix/changelog.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,33 @@ New convenience methods in `Rules` class for common transformation patterns:
6262
- `ifFieldMissing(ops, field, rule)` — Apply rule if field missing
6363
- `ifFieldEquals(ops, field, value, rule)` — Apply rule if field equals value
6464

65+
### High-Performance APIs
66+
67+
New APIs for optimized transformations:
68+
69+
**BatchTransform:**
70+
- `Rules.batch(ops, builder)` — Apply multiple operations in single encode/decode cycle
71+
- `BatchTransform.rename(from, to)` — Rename field in batch
72+
- `BatchTransform.remove(field)` — Remove field in batch
73+
- `BatchTransform.set(field, valueSupplier)` — Set field in batch
74+
- `BatchTransform.transform(field, fn)` — Transform field in batch
75+
- `BatchTransform.addIfMissing(field, valueSupplier)` — Add if missing in batch
76+
77+
**Single-Pass Conditionals:**
78+
- `Rules.conditionalTransform(ops, predicate, transform)` — General conditional
79+
- `Rules.ifFieldExists(ops, field, transform)` — Function overload (single-pass)
80+
- `Rules.ifFieldMissing(ops, field, transform)` — Function overload (single-pass)
81+
- `Rules.ifFieldEquals(ops, field, value, transform)` — Function overload (single-pass)
82+
83+
### Performance Optimizations
84+
85+
Internal optimizations with no API changes:
86+
87+
- Path parsing uses character-based parsing with memoization cache
88+
- `DataFixRegistry.getFixes()` pre-allocates result list
89+
- `DataFixerImpl` moves validation to registration time
90+
- Reduced allocations in hot paths
91+
6592
### New How-To Guides
6693

6794
- [Batch Operations](../how-to/batch-operations.md) — Rename/remove multiple fields

docs/getting-started/installation.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Add the core dependency to your `pom.xml`:
2424
<dependency>
2525
<groupId>de.splatgames.aether</groupId>
2626
<artifactId>aether-datafixers-core</artifactId>
27-
<version>0.1.0</version>
27+
<version>0.2.0</version>
2828
</dependency>
2929
```
3030

@@ -35,12 +35,12 @@ Add the core dependency to your `pom.xml`:
3535
<dependency>
3636
<groupId>de.splatgames.aether</groupId>
3737
<artifactId>aether-datafixers-core</artifactId>
38-
<version>0.1.0</version>
38+
<version>0.2.0</version>
3939
</dependency>
4040
<dependency>
4141
<groupId>de.splatgames.aether</groupId>
4242
<artifactId>aether-datafixers-codec</artifactId>
43-
<version>0.1.0</version>
43+
<version>0.2.0</version>
4444
</dependency>
4545
<!-- Gson is optional in codec module, add explicitly -->
4646
<dependency>
@@ -121,16 +121,16 @@ The Bill of Materials (BOM) ensures consistent versions across all modules:
121121

122122
```groovy
123123
dependencies {
124-
implementation 'de.splatgames.aether:aether-datafixers-core:0.1.0'
124+
implementation 'de.splatgames.aether:aether-datafixers-core:0.2.0'
125125
}
126126
```
127127

128128
With JSON support:
129129

130130
```groovy
131131
dependencies {
132-
implementation 'de.splatgames.aether:aether-datafixers-core:0.1.0'
133-
implementation 'de.splatgames.aether:aether-datafixers-codec:0.1.0'
132+
implementation 'de.splatgames.aether:aether-datafixers-core:0.2.0'
133+
implementation 'de.splatgames.aether:aether-datafixers-codec:0.2.0'
134134
implementation 'com.google.code.gson:gson:2.11.0'
135135
}
136136
```
@@ -139,16 +139,16 @@ dependencies {
139139

140140
```kotlin
141141
dependencies {
142-
implementation("de.splatgames.aether:aether-datafixers-core:0.1.0")
142+
implementation("de.splatgames.aether:aether-datafixers-core:0.2.0")
143143
}
144144
```
145145

146146
With JSON support:
147147

148148
```kotlin
149149
dependencies {
150-
implementation("de.splatgames.aether:aether-datafixers-core:0.1.0")
151-
implementation("de.splatgames.aether:aether-datafixers-codec:0.1.0")
150+
implementation("de.splatgames.aether:aether-datafixers-core:0.2.0")
151+
implementation("de.splatgames.aether:aether-datafixers-codec:0.2.0")
152152
implementation("com.google.code.gson:gson:2.11.0")
153153
}
154154
```

docs/tutorials/basic-migration.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@ Add the dependencies to your project:
3030
<dependency>
3131
<groupId>de.splatgames.aether</groupId>
3232
<artifactId>aether-datafixers-core</artifactId>
33-
<version>0.1.0</version>
33+
<version>0.2.0</version>
3434
</dependency>
3535
<dependency>
3636
<groupId>de.splatgames.aether</groupId>
3737
<artifactId>aether-datafixers-codec</artifactId>
38-
<version>0.1.0</version>
38+
<version>0.2.0</version>
3939
</dependency>
4040
<dependency>
4141
<groupId>com.google.code.gson</groupId>
4242
<artifactId>gson</artifactId>
43-
<version>2.11.0</version>
43+
<version>2.13.2</version>
4444
</dependency>
4545
```
4646

pom.xml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@
2424

2525
<!-- definition of versions for dependencies -->
2626
<jetbrains.annotations.version>26.0.2</jetbrains.annotations.version>
27-
<gson.version>2.11.0</gson.version>
28-
<jackson.version>2.18.3</jackson.version>
29-
<guava.version>33.4.8-jre</guava.version>
30-
<junit.jupiter.version>5.12.0</junit.jupiter.version>
31-
<assertj.version>3.25.1</assertj.version>
32-
<slf4j.version>2.0.16</slf4j.version>
27+
<gson.version>2.13.2</gson.version>
28+
<jackson.version>2.19.0</jackson.version>
29+
<guava.version>33.5.0-jre</guava.version>
30+
<junit.jupiter.version>5.13.4</junit.jupiter.version>
31+
<assertj.version>3.27.6</assertj.version>
32+
<slf4j.version>2.0.17</slf4j.version>
3333

3434
<!-- definition of versions for plugins -->
3535
<plugin.compiler.version>3.11.0</plugin.compiler.version>

0 commit comments

Comments
 (0)