{"id":16380351,"url":"https://github.com/sya-ri/ktconfig","last_synced_at":"2026-01-05T02:17:47.971Z","repository":{"id":62599311,"uuid":"557209174","full_name":"sya-ri/ktConfig","owner":"sya-ri","description":"Spigot configuration library using Kotlin data classes.","archived":false,"fork":false,"pushed_at":"2025-02-25T16:20:19.000Z","size":1447,"stargazers_count":10,"open_issues_count":5,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-17T19:46:49.536Z","etag":null,"topics":["kotlin","kotlin-library","kotlin-reflect","minecraft-plugin","minecraft-server","paper-api","paper-library","paper-plugin","paper-server","spigot-api","spigot-library","spigot-plugin","spigot-server"],"latest_commit_sha":null,"homepage":"https://gh.s7a.dev/ktConfig","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sya-ri.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"ko_fi":"sya_ri"}},"created_at":"2022-10-25T09:17:21.000Z","updated_at":"2025-02-25T16:10:19.000Z","dependencies_parsed_at":"2023-02-18T10:17:21.009Z","dependency_job_id":"15d570b5-5454-4af1-b9d8-653decd847de","html_url":"https://github.com/sya-ri/ktConfig","commit_stats":{"total_commits":415,"total_committers":3,"mean_commits":"138.33333333333334","dds":"0.39518072289156625","last_synced_commit":"47066550bec14392147d10c179b298f5c181d906"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sya-ri%2FktConfig","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sya-ri%2FktConfig/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sya-ri%2FktConfig/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sya-ri%2FktConfig/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sya-ri","download_url":"https://codeload.github.com/sya-ri/ktConfig/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244721568,"owners_count":20498978,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kotlin","kotlin-library","kotlin-reflect","minecraft-plugin","minecraft-server","paper-api","paper-library","paper-plugin","paper-server","spigot-api","spigot-library","spigot-plugin","spigot-server"],"created_at":"2024-10-11T03:51:15.010Z","updated_at":"2026-01-05T02:17:47.965Z","avatar_url":"https://github.com/sya-ri.png","language":"Kotlin","funding_links":["https://ko-fi.com/sya_ri"],"categories":[],"sub_categories":[],"readme":"# ktConfig v2\n\nSpigot configuration library for Kotlin using class annotations. The library generates configuration loaders at\nbuild-time, ensuring zero runtime overhead (except for YamlConfiguration operations).\n\n## ⚡ Features\n\n- **Zero Runtime Overhead**: All configuration loaders are generated at build-time (KSP).\n- **Type-Safe**: Fully typed configuration using Kotlin data classes.\n- **Wide Type Support**: Supports primitives, collections, Bukkit types, and more out of the box.\n- **Rich Features**: Built-in support for comments and custom serializers.\n- **Default Values**: Support for default values using Kotlin default values (e.g., `val count: Int = 0`).\n\n## 📦 Installation\n\nAdd the following dependencies to your `build.gradle.kts`\n\n```kotlin\nplugins {\n    kotlin(\"jvm\") version \"2.2.21\"\n    id(\"com.google.devtools.ksp\") version \"2.3.2\"\n}\n\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    implementation(\"dev.s7a:ktConfig:2.0.0\")\n    ksp(\"dev.s7a:ktConfig-ksp:2.0.0\")\n}\n```\n\n- Auto generate configuration loaders on build: `./gradlew build`.\n- Manually generate loaders: `./gradlew kspKotlin` (maybe required)\n\n## 📝 Quick Example\n\nAdd the `@KtConfig` annotation to your data class\n\n```kotlin\n@KtConfig\ndata class ServerConfig(\n    val serverName: String,\n    val maxPlayers: Int\n)\n```\n\nThe loader class will be defined, allowing you to perform loading and saving operations.\n\n```kotlin\noverride fun onEnable() {\n    val file = plugin.dataFolder.resolve(\"config.yml\")\n    val config = ServerConfigLoader.load(file)\n    // config.serverName : \"My Server\"\n    // config.maxPlayers : 100\n}\n```\n\n```yaml\nserverName: \"My Server\"\nmaxPlayers: 100\n```\n\nThe loader class provides the following methods:\n\n- `load(File): T`\n- `loadFromString(String): T`\n- `save(T, File)`\n- `saveToString(T): String`\n\n## 🚀 Usage\n\nktConfig provides various annotations to customize configuration behavior:\n\n- `@KtConfig`: Marks a class as a configuration class. Required for code generation.\n- `@Comment`: Adds comments to configuration headers or properties.\n- `@PathName`: Customizes the YAML path name for a property.\n- `@UseSerializer`: Specifies a custom serializer for a property.\n\n### Adding Comments\n\nYou can add comments to the generated YAML file using the `@Comment` annotation.\n\n```kotlin\n@KtConfig\n@Comment(\"Global settings\")\ndata class AppConfig(\n    @Comment(\"Enable debug mode\")\n    val debug: Boolean\n)\n```\n\n### Change the YAML Path Name\n\nYou can customize the YAML path name using the `@PathName` annotation.\n\n```kotlin\n@KtConfig\ndata class ServerConfig(\n    @PathName(\"server-name\")\n    val serverName: String\n)\n```\n\nThe YAML file will look like this:\n\n```yaml\nserver-name: \"My Server\"\n```\n\n### Default Values\n\nYou can support Kotlin's default values by adding `hasDefault = true` property to your `@KtConfig` annotation.\n\n```kotlin\n@KtConfig(hasDefault = true)\ndata class AppConfig(\n    val message: String = \"Hello\",\n    val count: Int = 10\n)\n```\n\n\u003e [!WARNING]\n\u003e\n\u003e 1. **All properties MUST have default values.**\n\u003e\n\u003e You cannot mix properties with and without default values in a `@KtConfig(hasDefault = true)` annotated class.\n\u003e　\n\u003e ```kotlin\n\u003e // 👌 This is valid\n\u003e @KtConfig(hasDefault = true)\n\u003e data class AppConfig(\n\u003e     val message: String = \"Hello\"\n\u003e )\n\u003e \n\u003e // ❌ This is invalid\n\u003e @KtConfig(hasDefault = true)\n\u003e data class AppConfig(\n\u003e     val message: String,\n\u003e     val count: Int = 10\n\u003e )\n\u003e ```\n\u003e \n\u003e 2. **Default values must be static.**\n\u003e\n\u003e Default values are generated once during construction and reused, so they must be static values.\n\u003e\n\u003e ```kotlin\n\u003e // 👌 This is valid\n\u003e @KtConfig(hasDefault = true)\n\u003e data class AppConfig(\n\u003e     val message: String = \"Hello\",\n\u003e     val count: Int = 10,\n\u003e     val list: List\u003cString\u003e = listOf(\"a\", \"b\")\n\u003e )\n\u003e\n\u003e // ❌ This is invalid\n\u003e @KtConfig(hasDefault = true)\n\u003e data class AppConfig(\n\u003e     val timestamp: Long = System.currentTimeMillis(), // Not static\n\u003e     val random: Int = Random().nextInt(), // Not static\n\u003e     val uuid: UUID = UUID.randomUUID()     // Not static\n\u003e )\n\u003e ```\n\u003e \n\u003e 3. **No Auto-Save for defaults.**\n\u003e\n\u003e If a value is missing in the file and the default value is used during loading, it is **not** automatically written back to the file. You must manually save the configuration if you want to persist the default values.\n\u003e Example of saving manually:\n\u003e\n\u003e ```kotlin\n\u003e // Load configuration (uses default values if keys are missing)\n\u003e val config = AppConfigLoader.load(file)\n\u003e\n\u003e // Manually save to ensure default values are written to the file\n\u003e AppConfigLoader.save(file, config)\n\u003e ```\n\n### Custom Serializers\n\nYou can define custom serialization logic for specific types.\n\n#### 1. Using `TransformSerializer` (Recommended)\n\nThe easiest way is to transform your type into a supported type (like `String` or `Map`).\nExtend `TransformSerializer\u003cYOUR_TYPE, BASE_TYPE\u003e` and pass a base serializer to the constructor.\nClasses implementing `Serializer.Keyable\u003cT\u003e` can be used as Map keys.\n\n```kotlin\n// Example: Serialize a custom Wrapper class as a String\nobject WrapperSerializer : TransformSerializer\u003cWrapper, String\u003e(StringSerializer) {\n    override fun decode(value: String): Wrapper {\n        return Wrapper(value) // Convert String -\u003e Wrapper\n    }\n\n    override fun encode(value: Wrapper): String {\n        return value.data // Convert Wrapper -\u003e String\n    }\n}\n```\n\n#### 2. Implementing `Serializer` Interface\n\nFor full control, implement the `Serializer\u003cT\u003e` interface directly.\nClasses implementing `Serializer.Keyable\u003cT\u003e` can be used as Map keys.\n\n```kotlin\nobject MyTypeSerializer : Serializer\u003cMyType\u003e {\n    override fun deserialize(value: Any): MyType {\n        // Convert raw YAML value (Map, String, Int, etc.) to MyType\n    }\n\n    override fun serialize(value: MyType): Any? {\n        // Convert MyType to a YAML-compatible format\n    }\n}\n```\n\n#### Applying the Serializer\n\nUse the `@UseSerializer` annotation on the property to apply your custom serializer.\n\n```kotlin\n@KtConfig\ndata class CustomConfig(\n    val data: @UseSerializer(WrapperSerializer::class) Wrapper\n)\n```\n\n## 📦 Supported Types\n\nktConfig supports the following types:\n\n### Primitives\n\n- `Boolean`\n- `Byte`\n- `Short`\n- `Int`\n- `Long`\n- `Float`\n- `Double`\n- `Char`\n- `String`\n- `UByte`\n- `UShort`\n- `UInt`\n- `ULong`\n- `BigInteger`\n- `BigDecimal`\n\n### Collections\n\n- `List`\n- `Set`\n- `Map`\n- `ArrayDeque`\n- `Array`\n- `BooleanArray`\n- `ByteArray`\n- `CharArray`\n- `ShortArray`\n- `IntArray`\n- `LongArray`\n- `FloatArray`\n- `DoubleArray`\n- `UByteArray`\n- `UShortArray`\n- `UIntArray`\n- `ULongArray`\n\n### Others\n\n- `org.bukkit.configuration.serialization.ConfigurationSerializable` : ItemStack, Location, ...\n- `java.util.UUID`\n- `java.time.Instant`\n- `java.time.LocalTime`\n- `java.time.LocalDate`\n- `java.time.LocalDateTime`\n- `java.time.Year`\n- `java.time.YearMonth`\n- `java.time.OffsetTime`\n- `java.time.OffsetDateTime`\n- `java.time.ZonedDateTime`\n- `java.time.Duration`\n- `java.time.Period`\n- [Enum classes](https://kotlinlang.org/docs/enum-classes.html)\n- [Inline value classes](https://kotlinlang.org/docs/inline-classes.html)\n\n### Formatted Types\n\nktConfig provides several formatted types for easier string-based serialization:\n\n- `FormattedBlock`: Represents [org.bukkit.Block](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/block/Block.html) (`World, X, Y, Z`)\n- `FormattedBlockVector`: Represents [org.bukkit.util.BlockVector](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/util/BlockVector.html) (`X, Y, Z`)\n- `FormattedColor`: Represents [org.bukkit.Color](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Color.html) (`#AARRGGBB`, `#RRGGBB`, `AARRGGBB`, `RRGGBB`)\n- `FormattedLocation`: Represents [org.bukkit.Location](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Location.html) (`World, X, Y, Z`, `World, X, Y, Z, Yaw, Pitch`)\n- `FormattedVector`: Represents [org.bukkit.Vector](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/util/Vector.html) (`X, Y, Z`)\n- `FormattedWorld`: Represents [org.bukkit.World](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/World.html) by its name (`WorldName`)\n\nThese types are automatically serialized to and from their string representations.\n\n## 🔧 Troubleshooting\n\n### Unsupported type\n\nLog example:\n\n```text\n[ksp] Unsupported type: java.util.Date\n```\n\nIf you encounter an error when using a type that is not supported by ktConfig.\n\n```kotlin\n@KtConfig\nclass InvalidConfig(\n    val date: java.util.Date, // Unsupported type\n)\n```\n\nDefine a custom serializer and specify it using `@UseSerializer` annotation to handle this type.\n\n```kotlin\nobject DateSerializer : Serializer\u003cjava.util.Date\u003e {\n    // ...\n}\n\n@KtConfig\ndata class Config(\n    val date: @UseSerializer(DateSerializer::class) java.util.Date,\n)\n```\n\nAlternatively, handle YAML using supported types and convert them externally.\n\n```kotlin\n@KtConfig\ndata class Config(\n    val instant: java.time.Instant, // Supported type\n) {\n    val date\n        get() = Date.from(instant)\n}\n```\n\n### Unresolve reference properties\n\nLog example:\n\n```\nUnresolved reference 'text'.\n```\n\nIf you encounter unresolved reference errors when using ktConfig, make sure your properties are properly declared.\nProperties in Kotlin must be declared using `val` or `var` to be accessible:\n\n```kotlin\n@KtConfig\nclass InvalidConfig(\n    text: String,\n)\n```\n\nUsing data classes is recommended as they enforce `val`/`var` declarations for all primary constructor properties\nautomatically.\n\n```kotlin\n@KtConfig\ndata class Config(\n    val text: String,\n)\n```\n\n### Unresolved reference using custom serializers\n\nLog example:\n\n```\nUnresolved reference 'getOrThrow'\nUnresolved reference 'set'\nInapplicable candidate(s): fun deserialize(value: Any): Date\nUnresolved reference 'serialize'\n```\n\nIf you encounter unresolved reference errors when using custom serializers, make sure you use objects instead of classes.\n\n```kotlin\nclass DateSerializer : Serializer\u003cjava.util.Date\u003e {\n    // ...\n}\n```\n\nShould be:\n\n```kotlin\nobject DateSerializer : Serializer\u003cjava.util.Date\u003e {\n    // ...\n}\n```\n\n### Mismatched dependency versions\n\nLog example:\n\n```\n'org.gradle.api.provider.Property org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions.getJvmDefault()'\n```\n\nThis error might occur due to version incompatibility between Kotlin and KSP. Please check and ensure that your Kotlin\nand KSP versions are compatible.\n\n## 🔑 License\n\n```\nMIT License\n\nCopyright (c) 2025 sya-ri\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsya-ri%2Fktconfig","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsya-ri%2Fktconfig","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsya-ri%2Fktconfig/lists"}