{"id":13606685,"url":"https://github.com/PatilShreyas/mutekt","last_synced_at":"2025-04-12T08:31:53.827Z","repository":{"id":50680453,"uuid":"519557649","full_name":"PatilShreyas/mutekt","owner":"PatilShreyas","description":"Simplify mutating \"immutable\" state models (a Kotlin multiplatform library)","archived":false,"fork":false,"pushed_at":"2023-07-27T14:58:53.000Z","size":3079,"stargazers_count":256,"open_issues_count":6,"forks_count":6,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-09T16:21:01.780Z","etag":null,"topics":["android","android-library","coroutines","hacktoberfest","immutable","jetpack-compose","jvm-library","kmm","kmm-library","kotlin","kotlin-library","kotlin-multiplatform","kotlin-multiplatform-library","kotlin-multiplatform-mobile","model","multiplatform","mutable","redux","state-management","stateflow"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PatilShreyas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":"PatilShreyas","otechie":null,"custom":["https://www.paypal.me/PatilShreyas99/","https://github.com/sponsors/PatilShreyas/"]}},"created_at":"2022-07-30T15:50:13.000Z","updated_at":"2025-01-09T13:47:15.000Z","dependencies_parsed_at":"2024-01-16T23:30:37.192Z","dependency_job_id":"d156e524-2935-472e-bd81-8b0db1497eb1","html_url":"https://github.com/PatilShreyas/mutekt","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PatilShreyas%2Fmutekt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PatilShreyas%2Fmutekt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PatilShreyas%2Fmutekt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PatilShreyas%2Fmutekt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PatilShreyas","download_url":"https://codeload.github.com/PatilShreyas/mutekt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248540011,"owners_count":21121273,"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":["android","android-library","coroutines","hacktoberfest","immutable","jetpack-compose","jvm-library","kmm","kmm-library","kotlin","kotlin-library","kotlin-multiplatform","kotlin-multiplatform-library","kotlin-multiplatform-mobile","model","multiplatform","mutable","redux","state-management","stateflow"],"created_at":"2024-08-01T19:01:11.473Z","updated_at":"2025-04-12T08:31:53.797Z","avatar_url":"https://github.com/PatilShreyas.png","language":"Kotlin","funding_links":["https://issuehunt.io/r/PatilShreyas","https://www.paypal.me/PatilShreyas99/","https://github.com/sponsors/PatilShreyas/"],"categories":["Kotlin"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eMutekt\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e(Pronunciation: \u003cb\u003e\u003ci\u003e/mjuːˈteɪt/\u003c/i\u003e\u003c/b\u003e, 'k' is silent)\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003e\u003ci\u003e\"Simplify mutating \"immutable\" state models\"\u003c/i\u003e\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/PatilShreyas/mutekt/actions/workflows/build.yml\"\u003e\u003cimg src=\"https://github.com/PatilShreyas/mutekt/actions/workflows/build.yml/badge.svg\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/PatilShreyas/mutekt/actions/workflows/release.yml\"\u003e\u003cimg src=\"https://github.com/PatilShreyas/mutekt/actions/workflows/release.yml/badge.svg\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://search.maven.org/search?q=g:dev.shreyaspatil.mutekt\"\u003e\u003cimg src=\"https://img.shields.io/maven-central/v/dev.shreyaspatil.mutekt/mutekt-codegen?label=Maven%20Central\u0026logo=android\u0026style=flat-square\"/\u003e\u003c/a\u003e\n    \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/PatilShreyas/mutekt?label=License)\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://codecov.io/gh/PatilShreyas/mutekt\"\u003e\u003cimg src=\"https://codecov.io/gh/PatilShreyas/mutekt/branch/main/graph/badge.svg?token=t5722h7jWn\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nGenerates mutable models from immutable model definitions. It's based on Kotlin's Symbol Processor (KSP).\nThis is inspired from the concept _Redux_ and _Immer_ from JS world that let you write simpler immutable update logic \nusing \"mutating\" syntax which helps simplify most reducer implementations. \n**So you just need to focus on actual development and _Mutekt_ will write boilerplate for you!** 😎\n\n\u003cp align=\"center\"\u003eLike this ⬇️️\u003c/p\u003e\n\n![Mutekt Usage Example](mutekt-usage.gif)\n\n## Usage\n\nTry out the [example app](/example) to see it in action.\n\n### 1. Apply annotation and generate model\n\nDeclare a state model as an `interface` and apply `@GenerateMutableModel` annotation to it.\n\nExample:\n\n```kotlin\n@GenerateMutableModel\ninterface NotesState {\n    val isLoading: Boolean\n    val notes: List\u003cString\u003e\n    val error: String?\n}\n// You can also apply annotation `@Immutable` if using for Jetpack Compose UI model.\n```\n\nOnce done, **🔨Build project** and mutable model will be generated for the immutable definition by KSP.\n\n### 2. Simply mutate and get immutable state\n\nThe mutable model can be created with the factory function which is generated with the name of an interface with prefix\n`Mutable`.\n_For example, if interface name is `ExampleState` then method name for creating mutable model will be\n`MutableExampleState()` and will have parameters in it which are declared as public properties in the interface._\n\n```kotlin\n/**\n * Instance of mutable model [MutableNotesState] which is generated with Mutekt.\n */\nprivate val _state = MutableNotesState(isLoading = true, notes = emptyList(), error = null)\n\nfun setLoading() {\n    _state.isLoading = true\n}\n\nfun setNotes() {\n    _state.update {\n        isLoading = false\n        notes = listOf(\"Lorem Ipsum\")\n    }\n}\n```\n\n\u003e **Note**  \n\u003e Use method `update{}` on Mutable model instance to mutate multiple fields atomically. \n\n### 3. Getting reactive immutable value updates\n\nTo get immutable instance with reactive state updates, use method `asStateFlow()` which returns instance of\n[`StateFlow\u003cT\u003e`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-state-flow/).\nWhenever any field of Mutable model is updated with new value, this StateFlow gets updated with new immutable state value.\n\n```kotlin\nval state: StateFlow\u003cNotesState\u003e = _state.asStateFlow()\n```\n\n#### Properties of immutable instance implemented by Mutekt:\n\n- [x] Immutable model implementation promises to be truly ***Immutable*** i.e. once instance is created, its properties\nwill never change.\n- [x] Implementation is actually a ***data class*** under the hood i.e. having `equals()` and `hashCode()` \nalready overridden.\n\n---\n\n## Setting up _Mutekt_ in the project\n\n### 1.1 Enable KSP in module\n\nIn order to support code generation at compile time, [enable KSP support in the module](https://kotlinlang.org/docs/ksp-quickstart.html#use-your-own-processor-in-a-project).\n\n```groovy\nplugins {\n    id 'com.google.devtools.ksp' version '1.7.10-1.0.6'\n}\n```\n\n### 1.2 Add dependencies\n\n#### 1.2.1 Without Kotlin Multiplatform\n\nIn `build.gradle` of app module, include this dependency\n\n```groovy\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    implementation(\"dev.shreyaspatil.mutekt:mutekt-core:$mutektVersion\")\n    ksp(\"dev.shreyaspatil.mutekt:mutekt-codegen:$mutektVersion\")\n\n    // Include kotlin coroutine to support usage of StateFlow \n    implementation(\"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4\")\n}\n```\n\n#### 1.2.2 With Kotlin Multiplatform\n\nIn `build.gradle.kts` of project module:\n\n```kotlin\nkotlin {\n  sourceSets {\n    val commonMain by getting {\n      dependencies {\n        implementation(\"dev.shreyaspatil.mutekt:mutekt-core:$mutektVersion\")\n      }\n    }\n  }\n}\n\ndependencies {\n  add(\"kspCommonMainMetadata\", \"dev.shreyaspatil.mutekt:mutekt-codegen:$mutektVersion\")\n}\n\ntasks.withType\u003corg.jetbrains.kotlin.gradle.tasks.KotlinCompile\u003e().configureEach {\n  if (name != \"kspCommonMainKotlinMetadata\") {\n    dependsOn(\"kspCommonMainKotlinMetadata\")\n  }\n}\n```\n\n_You can find the latest version and changelogs in the [releases](https://github.com/PatilShreyas/mutekt/releases)_.\n\n### 1.3 Include generated classes in sources\n\nIn order to make IDE aware of generated code, it's important to include KSP generated sources in the project source sets.\n\nInclude generated sources as follows:\n\n#### 1.3.1 Without Kotlin Multiplatform\n\n\u003cdetails open\u003e\n  \u003csummary\u003e\u003cb\u003eGradle (Groovy)\u003c/b\u003e\u003c/summary\u003e\n\n```groovy\nkotlin {\n    sourceSets {\n        main.kotlin.srcDirs += 'build/generated/ksp/main/kotlin'\n        test.kotlin.srcDirs += 'build/generated/ksp/test/kotlin'\n    }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cb\u003eGradle (KTS)\u003c/b\u003e\u003c/summary\u003e\n\n```kotlin\nkotlin {\n    sourceSets.main {\n        kotlin.srcDir(\"build/generated/ksp/main/kotlin\")\n    }\n    sourceSets.test {\n        kotlin.srcDir(\"build/generated/ksp/test/kotlin\")\n    }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cb\u003eAndroid (Gradle - Groovy)\u003c/b\u003e\u003c/summary\u003e\n\n```groovy\nandroid {\n    applicationVariants.all { variant -\u003e\n        kotlin.sourceSets {\n            def name = variant.name\n            getByName(name) {\n                kotlin.srcDir(\"build/generated/ksp/$name/kotlin\")\n            }\n        }\n    }\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cb\u003eAndroid (Gradle - KTS)\u003c/b\u003e\u003c/summary\u003e\n\n```kotlin\nandroid {\n    applicationVariants.all {\n        kotlin.sourceSets {\n            getByName(name) {\n                kotlin.srcDir(\"build/generated/ksp/$name/kotlin\")\n            }\n        }\n    }\n}\n```\n\u003c/details\u003e\n\n#### 1.3.2 With Kotlin Multiplatform\n\n```kotlin\nkotlin {\n  sourceSets {\n    val commonMain by getting {\n      kotlin.srcDirs(\"build/generated/ksp/metadata/commonMain/kotlin\")\n    }\n  }\n}\n```\n\n## See also\n\n- [Why Mutekt?](https://github.com/PatilShreyas/mutekt/wiki/Why-Mutekt%3F)\n- [Generated code with Mutekt](https://github.com/PatilShreyas/mutekt/wiki/Code-generation-with-Mutekt)\n\n## 👨‍💻 Development\n\nClone this repository and import in IntelliJ IDEA (_any edition_) or Android Studio.\n\n### Module details\n\n- `mutekt-core`: Contain core annotation and interface for mutekt\n- `mutekt-codegen`: Includes sources for generating mutekt code with KSP\n- `example`: Example application which demonstrates usage of this library.\n\n### Verify build\n\n- To verify whether project building or not: `./gradlew build`.\n- To verify code formatting: `./gradlew spotlessCheck`.\n- To reformat code with Spotless: `./gradlew spotlessApply`.\n\n## 🙋‍♂️ Contribute \n\nRead [contribution guidelines](CONTRIBUTING.md) for more information regarding contribution.\n\n## 💬 Discuss\n\nHave any questions, doubts or want to present your opinions, views? You're always welcome. You can [start discussions](https://github.com/PatilShreyas/mutekt/discussions).\n\n## 📝 License\n\n```\nCopyright 2022 Shreyas Patil\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\n\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPatilShreyas%2Fmutekt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPatilShreyas%2Fmutekt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPatilShreyas%2Fmutekt/lists"}