├── .editorconfig ├── .gitattributes ├── .github ├── actions │ └── setup │ │ └── action.yml └── workflows │ ├── ci.yml │ ├── daily.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── CONTRIBUTING.md ├── LICENSE ├── MODULE.md ├── README.md ├── build.gradle.kts ├── docs ├── docs │ ├── .gitignore │ ├── api │ │ └── index.html │ ├── index.md │ └── stylesheets │ │ └── extra.css └── mkdocs.yml ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── justfile ├── kotlin-js-store └── yarn.lock ├── scripts ├── pre-commit └── test-server ├── settings.gradle.kts └── src ├── appleMain └── kotlin │ └── dev │ └── sargunv │ └── pokekotlin │ └── internal │ └── getDefaultEngine.apple.kt ├── commonMain └── kotlin │ └── dev │ └── sargunv │ └── pokekotlin │ ├── PokeApi.kt │ ├── PokeApiException.kt │ ├── internal │ ├── DelegatingSerializer.kt │ ├── PokeApiConverter.kt │ ├── PokeApiJson.kt │ └── getDefaultEngine.kt │ └── model │ ├── berries.kt │ ├── contests.kt │ ├── encounters.kt │ ├── evolution.kt │ ├── games.kt │ ├── items.kt │ ├── locations.kt │ ├── machines.kt │ ├── moves.kt │ ├── pokemon.kt │ ├── resource.kt │ └── utility.kt ├── commonTest └── kotlin │ └── dev │ └── sargunv │ └── pokekotlin │ ├── example │ └── example.kt │ └── test │ ├── BulkTest.kt │ ├── LiveTest.kt │ ├── LocalPokeApi.kt │ ├── PokeApiExceptionTest.kt │ └── model │ ├── BerryTest.kt │ ├── ContestTest.kt │ ├── EncounterTest.kt │ ├── EvolutionTest.kt │ ├── GameTest.kt │ ├── ItemTest.kt │ ├── LocationTest.kt │ ├── MachineTest.kt │ ├── MoveTest.kt │ ├── PokemonTest.kt │ ├── ResourceListTest.kt │ └── UtilityTest.kt ├── jsMain └── kotlin │ └── dev │ └── sargunv │ └── pokekotlin │ └── internal │ └── getDefaultEngine.js.kt ├── jvmMain └── kotlin │ └── dev │ └── sargunv │ └── pokekotlin │ └── internal │ └── getDefaultEngine.jvm.kt ├── jvmTest └── kotlin │ └── dev │ └── sargunv │ └── pokekotlin │ └── test │ └── EndpointTest.kt ├── linuxMain └── kotlin │ └── dev │ └── sargunv │ └── pokekotlin │ └── internal │ └── getDefaultEngine.linux.kt ├── mingwMain └── kotlin │ └── dev │ └── sargunv │ └── pokekotlin │ └── internal │ └── getDefaultEngine.mingw.kt └── wasmJsMain └── kotlin └── dev └── sargunv └── pokekotlin └── internal └── getDefaultEngine.wasmJs.kt /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 2 8 | 9 | [justfile] 10 | indent_size = 4 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.bat text eol=crlf 2 | src/test/resources/data/**/* linguist-vendored 3 | -------------------------------------------------------------------------------- /.github/actions/setup/action.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Setup" 3 | description: "Set up the build environment, used by most jobs" 4 | runs: 5 | using: "composite" 6 | steps: 7 | - uses: "actions/setup-java@v4" 8 | with: 9 | distribution: "temurin" 10 | java-version: 21 11 | - uses: "gradle/actions/setup-gradle@v4" 12 | with: 13 | build-scan-publish: true 14 | build-scan-terms-of-use-url: "https://gradle.com/terms-of-service" 15 | build-scan-terms-of-use-agree: "yes" 16 | - uses: extractions/setup-just@v3 17 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | test: 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | include: 15 | - target: jvm 16 | os: ubuntu 17 | - target: jsBrowser 18 | os: ubuntu 19 | - target: jsNode 20 | os: ubuntu 21 | - target: wasmJsBrowser 22 | os: ubuntu 23 | - target: wasmJsNode 24 | os: ubuntu 25 | - target: linuxX64 26 | os: ubuntu 27 | - target: macosArm64 28 | os: macos 29 | - target: mingwX64 30 | os: windows 31 | - target: iosSimulatorArm64 32 | os: macos 33 | - target: tvosSimulatorArm64 34 | os: macos 35 | - target: watchosSimulatorArm64 36 | os: macos 37 | runs-on: "${{ matrix.os }}-latest" 38 | name: "test (${{ matrix.target }})" 39 | steps: 40 | - uses: "actions/checkout@v4" 41 | with: 42 | fetch-depth: 0 43 | submodules: recursive 44 | - uses: "./.github/actions/setup" 45 | - run: "just test-server-background" 46 | - run: "./gradlew ${{ matrix.target }}Test" 47 | 48 | build-docs: 49 | runs-on: ubuntu-latest 50 | steps: 51 | - uses: "actions/checkout@v4" 52 | with: 53 | fetch-depth: 0 54 | - uses: "./.github/actions/setup" 55 | - run: "./gradlew generateDocs" 56 | - uses: "actions/upload-pages-artifact@v3" 57 | with: 58 | path: "build/docs" 59 | 60 | check-format: 61 | runs-on: ubuntu-latest 62 | permissions: 63 | checks: write 64 | issues: write 65 | pull-requests: write 66 | steps: 67 | - uses: "actions/checkout@v4" 68 | with: 69 | fetch-depth: 0 70 | - uses: "./.github/actions/setup" 71 | - run: "./gradlew spotlessApply" 72 | - if: "${{ github.event_name == 'pull_request' }}" 73 | uses: reviewdog/action-suggester@v1 74 | with: 75 | tool_name: spotless 76 | cleanup: false 77 | - run: "git diff --exit-code" 78 | 79 | all-good: 80 | needs: 81 | - "test" 82 | - "check-format" 83 | - "build-docs" 84 | runs-on: "ubuntu-latest" 85 | steps: 86 | - run: "echo 'All checks passed!'" 87 | -------------------------------------------------------------------------------- /.github/workflows/daily.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Daily" 3 | 4 | on: 5 | schedule: 6 | - cron: "00 10 * * *" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | check-last-run: 11 | runs-on: "ubuntu-latest" 12 | steps: 13 | - uses: "octokit/request-action@v2.x" 14 | id: "check-last-run" 15 | env: 16 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 17 | with: 18 | route: "GET /repos/${{github.repository}}/actions/workflows/daily.yml/runs?per_page=1&status=completed" 19 | outputs: 20 | last_sha: "${{ fromJson(steps.check-last-run.outputs.data).workflow_runs[0].head_sha }}" 21 | 22 | publish-snapshot: 23 | needs: ["check-last-run"] 24 | if: "${{ needs.check-last-run.outputs.last_sha != github.sha }}" 25 | runs-on: "macos-latest" 26 | permissions: 27 | packages: "write" 28 | steps: 29 | - uses: "actions/checkout@v4" 30 | with: 31 | fetch-depth: 0 32 | - uses: "./.github/actions/setup" 33 | - run: "./gradlew publishAllPublicationsToGitHubPackagesRepository" 34 | env: 35 | ORG_GRADLE_PROJECT_GitHubPackagesPassword: "${{ secrets.GITHUB_TOKEN }}" 36 | ORG_GRADLE_PROJECT_GitHubPackagesUsername: "${{ github.actor }}" 37 | 38 | dependency-submission: 39 | needs: ["check-last-run"] 40 | if: "${{ needs.check-last-run.outputs.last_sha != github.sha }}" 41 | runs-on: "ubuntu-latest" 42 | permissions: 43 | contents: "write" 44 | steps: 45 | - uses: "actions/checkout@v4" 46 | - uses: "actions/setup-java@v4" 47 | with: 48 | distribution: "temurin" 49 | java-version: 21 50 | - uses: "gradle/actions/dependency-submission@v4" 51 | with: 52 | build-scan-publish: true 53 | build-scan-terms-of-use-url: "https://gradle.com/help/legal-terms-of-use" 54 | build-scan-terms-of-use-agree: "yes" 55 | - uses: "advanced-security/cocoapods-dependency-submission-action@v1.1" 56 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Release" 3 | 4 | on: 5 | push: 6 | tags: ["v*.*.*"] 7 | 8 | jobs: 9 | publish-maven: 10 | runs-on: macos-latest 11 | environment: 12 | name: "maven-central" 13 | url: "https://central.sonatype.com/namespace/dev.sargunv.pokekotlin" 14 | steps: 15 | - uses: "actions/checkout@v4" 16 | with: 17 | fetch-depth: 0 18 | - run: "git fetch --tags --force" # https://github.com/actions/checkout/issues/290 19 | - uses: "./.github/actions/setup" 20 | - run: "./gradlew publishAndReleaseToMavenCentral --no-configuration-cache" 21 | env: 22 | ORG_GRADLE_PROJECT_mavenCentralUsername: "${{ secrets.MAVEN_CENTRAL_USERNAME }}" 23 | ORG_GRADLE_PROJECT_mavenCentralPassword: "${{ secrets.MAVEN_CENTRAL_PASSWORD }}" 24 | ORG_GRADLE_PROJECT_signingInMemoryKey: "${{ secrets.GPG_PRIVATE_KEY }}" 25 | ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: "${{ secrets.GPG_PASSPHRASE }}" 26 | 27 | publish-pages: 28 | needs: 29 | - "publish-maven" 30 | runs-on: macos-latest 31 | permissions: 32 | pages: "write" 33 | id-token: "write" 34 | environment: 35 | name: "github-pages" 36 | url: "${{ steps.deploy-pages.outputs.page_url }}" 37 | steps: 38 | - uses: "actions/checkout@v4" 39 | with: 40 | fetch-depth: 0 41 | - run: "git fetch --tags --force" # https://github.com/actions/checkout/issues/290 42 | - uses: "./.github/actions/setup" 43 | - run: "./gradlew generateDocs" 44 | - uses: "actions/upload-pages-artifact@v3" 45 | with: 46 | path: "build/docs" 47 | - uses: "actions/deploy-pages@v4" 48 | id: "deploy-pages" 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .kotlin/ 2 | 3 | # Created by https://www.toptal.com/developers/gitignore/api/kotlin,intellij,gradle 4 | # Edit at https://www.toptal.com/developers/gitignore?templates=kotlin,intellij,gradle 5 | 6 | ### Intellij ### 7 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 8 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 9 | 10 | # User-specific stuff 11 | .idea/**/workspace.xml 12 | .idea/**/tasks.xml 13 | .idea/**/usage.statistics.xml 14 | .idea/**/dictionaries 15 | .idea/**/shelf 16 | 17 | # AWS User-specific 18 | .idea/**/aws.xml 19 | 20 | # Generated files 21 | .idea/**/contentModel.xml 22 | 23 | # Sensitive or high-churn files 24 | .idea/**/dataSources/ 25 | .idea/**/dataSources.ids 26 | .idea/**/dataSources.local.xml 27 | .idea/**/sqlDataSources.xml 28 | .idea/**/dynamic.xml 29 | .idea/**/uiDesigner.xml 30 | .idea/**/dbnavigator.xml 31 | 32 | # Gradle 33 | .idea/**/gradle.xml 34 | .idea/**/libraries 35 | 36 | # Gradle and Maven with auto-import 37 | # When using Gradle or Maven with auto-import, you should exclude module files, 38 | # since they will be recreated, and may cause churn. Uncomment if using 39 | # auto-import. 40 | .idea/ 41 | *.iml 42 | *.ipr 43 | 44 | # CMake 45 | cmake-build-*/ 46 | 47 | # Mongo Explorer plugin 48 | .idea/**/mongoSettings.xml 49 | 50 | # File-based project format 51 | *.iws 52 | 53 | # IntelliJ 54 | out/ 55 | 56 | # mpeltonen/sbt-idea plugin 57 | .idea_modules/ 58 | 59 | # JIRA plugin 60 | atlassian-ide-plugin.xml 61 | 62 | # Cursive Clojure plugin 63 | .idea/replstate.xml 64 | 65 | # SonarLint plugin 66 | .idea/sonarlint/ 67 | 68 | # Crashlytics plugin (for Android Studio and IntelliJ) 69 | com_crashlytics_export_strings.xml 70 | crashlytics.properties 71 | crashlytics-build.properties 72 | fabric.properties 73 | 74 | # Editor-based Rest Client 75 | .idea/httpRequests 76 | 77 | # Android studio 3.1+ serialized cache file 78 | .idea/caches/build_file_checksums.ser 79 | 80 | ### Intellij Patch ### 81 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 82 | 83 | # *.iml 84 | # modules.xml 85 | # .idea/misc.xml 86 | # *.ipr 87 | 88 | # Sonarlint plugin 89 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 90 | .idea/**/sonarlint/ 91 | 92 | # SonarQube Plugin 93 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 94 | .idea/**/sonarIssues.xml 95 | 96 | # Markdown Navigator plugin 97 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 98 | .idea/**/markdown-navigator.xml 99 | .idea/**/markdown-navigator-enh.xml 100 | .idea/**/markdown-navigator/ 101 | 102 | # Cache file creation bug 103 | # See https://youtrack.jetbrains.com/issue/JBR-2257 104 | .idea/$CACHE_FILE$ 105 | 106 | # CodeStream plugin 107 | # https://plugins.jetbrains.com/plugin/12206-codestream 108 | .idea/codestream.xml 109 | 110 | # Azure Toolkit for IntelliJ plugin 111 | # https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij 112 | .idea/**/azureSettings.xml 113 | 114 | ### Kotlin ### 115 | # Compiled class file 116 | *.class 117 | 118 | # Log file 119 | *.log 120 | 121 | # BlueJ files 122 | *.ctxt 123 | 124 | # Mobile Tools for Java (J2ME) 125 | .mtj.tmp/ 126 | 127 | # Package Files # 128 | *.jar 129 | *.war 130 | *.nar 131 | *.ear 132 | *.zip 133 | *.tar.gz 134 | *.rar 135 | 136 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 137 | hs_err_pid* 138 | replay_pid* 139 | 140 | ### Gradle ### 141 | .gradle 142 | **/build/ 143 | !src/**/build/ 144 | 145 | # Ignore Gradle GUI config 146 | gradle-app.setting 147 | 148 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 149 | !gradle-wrapper.jar 150 | 151 | # Avoid ignore Gradle wrappper properties 152 | !gradle-wrapper.properties 153 | 154 | # Cache of project 155 | .gradletasknamecache 156 | 157 | # Eclipse Gradle plugin generated files 158 | # Eclipse Core 159 | .project 160 | # JDT-specific (Eclipse Java Development Tools) 161 | .classpath 162 | 163 | ### Gradle Patch ### 164 | # Java heap dump 165 | *.hprof 166 | 167 | # End of https://www.toptal.com/developers/gitignore/api/kotlin,intellij,gradle 168 | 169 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "api-data"] 2 | path = api-data 3 | url = https://github.com/pokeapi/api-data 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Creating issues 4 | 5 | If you notice a discrepancy between PokeAPI's responses and PokeKotlin's object 6 | models, you should create an issue and I'll fix it as soon as possible. You can 7 | also post questions, feature suggestions, general support issues, or anything 8 | else. 9 | 10 | ## Submitting changes 11 | 12 | Remember to always work in a separate branch, use descriptive commit messages, 13 | and use pull requests to submit your changes. Always create an issue and mention 14 | you're working on something first. Also, make sure that all tests pass. If you 15 | add new fields or types, write the tests to check them against PokeAPI. 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2016 Sargun Vohra 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /MODULE.md: -------------------------------------------------------------------------------- 1 | # Module pokekotlin 2 | 3 | A Kotlin client for PokeAPI. 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Maven Central Version](https://img.shields.io/maven-central/v/dev.sargunv.pokekotlin/pokekotlin?label=Maven)](https://central.sonatype.com/namespace/dev.sargunv.pokekotlin) 2 | [![License](https://img.shields.io/github/license/PokeAPI/pokekotlin?label=License)](https://github.com/PokeAPI/pokekotlin/blob/main/LICENSE) 3 | [![Kotlin Version](https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fraw.githubusercontent.com%2FPokeAPI%2Fpokekotlin%2Frefs%2Fheads%2Fmain%2Fgradle%2Flibs.versions.toml&query=versions.gradle-kotlin&prefix=v&logo=kotlin&label=Kotlin)](./gradle/libs.versions.toml) 4 | [![Documentation](https://img.shields.io/badge/Documentation-blue?logo=MaterialForMkDocs&logoColor=white)](https://pokeapi.github.io/pokekotlin/) 5 | [![API Reference](https://img.shields.io/badge/API_Reference-blue?logo=Kotlin&logoColor=white)](https://pokeapi.github.io/pokekotlin/api/) 6 | 7 | # PokeKotlin 8 | 9 | Maintainer: [@sargunv](https://github.com/sargunv) 10 | 11 | PokeKotlin is a modern [Kotlin Multiplatform] client for [PokéAPI]. It supports 12 | Kotlin JVM, JS, WASM, and Native. Under the hood, it's built on [Ktor], [Kotlin 13 | Serialization], and coroutines. 14 | 15 | ## Usage 16 | 17 | > [!IMPORTANT] 18 | > 19 | > The currently published version is the old JVM-only version based on OkHttp. 20 | > See the snapshot builds on GitHub packages for the KMP build. 21 | 22 | - [Documentation] 23 | - [API Reference] 24 | 25 | [Kotlin Multiplatform]: https://kotlinlang.org/docs/multiplatform.html 26 | [PokéAPI]: https://pokeapi.co/ 27 | [Ktor]: https://ktor.io/ 28 | [Kotlin Serialization]: https://github.com/Kotlin/kotlinx.serialization 29 | [coroutines]: https://kotlinlang.org/docs/coroutines-guide.html 30 | [Documentation]: https://pokeapi.github.io/pokekotlin/ 31 | [API Reference]: https://pokeapi.github.io/pokekotlin/api/ 32 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:OptIn(ExperimentalWasmDsl::class) 2 | 3 | import com.vanniktech.maven.publish.SonatypeHost 4 | import fr.brouillard.oss.jgitver.Strategies 5 | import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl 6 | import ru.vyarus.gradle.plugin.mkdocs.task.MkdocsTask 7 | 8 | plugins { 9 | alias(libs.plugins.kotlin.multiplatform) 10 | alias(libs.plugins.kotlin.serialization) 11 | alias(libs.plugins.mavenPublish) 12 | alias(libs.plugins.spotless) 13 | alias(libs.plugins.dokka) 14 | alias(libs.plugins.mkdocs) 15 | alias(libs.plugins.jgitver) 16 | alias(libs.plugins.ksp) 17 | alias(libs.plugins.ktorfit) 18 | id("maven-publish") 19 | } 20 | 21 | group = "dev.sargunv.pokekotlin" 22 | 23 | jgitver { 24 | strategy(Strategies.MAVEN) 25 | nonQualifierBranches("main") 26 | } 27 | 28 | kotlin { 29 | jvmToolchain(21) 30 | 31 | compilerOptions { allWarningsAsErrors = true } 32 | 33 | jvm() 34 | 35 | js(IR) { 36 | browser() 37 | nodejs() 38 | } 39 | 40 | wasmJs { 41 | browser() 42 | nodejs() 43 | d8 {} 44 | } 45 | 46 | // native tier 1 47 | macosX64() 48 | macosArm64() 49 | iosSimulatorArm64() 50 | iosX64() 51 | iosArm64() 52 | 53 | // native tier 2 54 | linuxX64() 55 | linuxArm64() 56 | watchosSimulatorArm64() 57 | watchosX64() 58 | watchosArm32() 59 | watchosArm64() 60 | tvosSimulatorArm64() 61 | tvosX64() 62 | tvosArm64() 63 | 64 | // native tier 3 65 | // android native platforms aren't supported due to lack of Ktor support 66 | mingwX64() 67 | watchosDeviceArm64() 68 | 69 | applyDefaultHierarchyTemplate() 70 | 71 | sourceSets { 72 | commonMain.dependencies { 73 | implementation(kotlin("stdlib")) 74 | implementation(libs.kotlinx.serialization.json) 75 | implementation(libs.ktor.client.content.negotiation) 76 | implementation(libs.ktor.serialization.kotlinx.json) 77 | implementation(libs.ktorfit) 78 | } 79 | 80 | jvmMain.dependencies { implementation(libs.ktor.client.okhttp) } 81 | appleMain.dependencies { implementation(libs.ktor.client.darwin) } 82 | linuxMain.dependencies { implementation(libs.ktor.client.curl) } 83 | mingwMain.dependencies { implementation(libs.ktor.client.winhttp) } 84 | jsMain.dependencies { implementation(libs.ktor.client.js) } 85 | wasmJsMain.dependencies { implementation(libs.ktor.client.js) } 86 | 87 | commonTest.dependencies { 88 | implementation(kotlin("test")) 89 | implementation(libs.kotlinx.coroutines.test) 90 | implementation(libs.kotlinx.io) 91 | implementation(libs.ktor.client.mock) 92 | } 93 | 94 | jvmTest.dependencies { implementation(kotlin("reflect")) } 95 | } 96 | } 97 | 98 | tasks.getByName("sourcesJar").dependsOn("kspCommonMainKotlinMetadata") 99 | 100 | publishing { 101 | repositories { 102 | maven { 103 | name = "GitHubPackages" 104 | setUrl("https://maven.pkg.github.com/PokeAPI/pokekotlin") 105 | credentials(PasswordCredentials::class) 106 | } 107 | } 108 | } 109 | 110 | mavenPublishing { 111 | publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL, automaticRelease = true) 112 | signAllPublications() 113 | pom { 114 | name = "PokeKotlin" 115 | description = "Kotlin client for The Pokémon API" 116 | url = "https://github.com/PokeAPI/pokekotlin" 117 | licenses { 118 | license { 119 | name.set("The Apache License, Version 2.0") 120 | url.set("https://opensource.org/license/apache-2-0") 121 | distribution.set("repo") 122 | } 123 | } 124 | developers { 125 | developer { 126 | id.set("sargunv") 127 | name.set("Sargun Vohra") 128 | url.set("https://github.com/sargunv") 129 | } 130 | } 131 | scm { 132 | url.set("https://github.com/PokeAPI/pokekotlin") 133 | connection.set("scm:git:git://github.com/PokeAPI/pokekotlin.git") 134 | developerConnection.set("scm:git:ssh://git@github.com/PokeAPI/pokekotlin.git") 135 | } 136 | } 137 | } 138 | 139 | dokka { 140 | moduleName = "PokeKotlin API Reference" 141 | dokkaSourceSets { 142 | configureEach { 143 | includes.from("MODULE.md") 144 | sourceLink { 145 | remoteUrl("https://github.com/PokeAPI/pokekotlin/tree/${project.ext["base_tag"]}/") 146 | localDirectory.set(rootDir) 147 | } 148 | externalDocumentationLinks { create("ktor") { url("https://api.ktor.io/") } } 149 | suppressedFiles.from( 150 | "build/generated/ksp/metadata/commonMain/kotlin/dev/sargunv/pokekotlin/_PokeApiImpl.kt" 151 | ) 152 | } 153 | } 154 | } 155 | 156 | mkdocs { 157 | sourcesDir = "docs" 158 | strict = true 159 | publish { 160 | docPath = null // single version site 161 | } 162 | } 163 | 164 | tasks.withType().configureEach { 165 | val releaseVersion = ext["base_tag"].toString().replace("v", "") 166 | val snapshotVersion = "${ext["next_patch_version"]}-SNAPSHOT" 167 | extras.set(mapOf("release_version" to releaseVersion, "snapshot_version" to snapshotVersion)) 168 | } 169 | 170 | tasks.register("generateDocs") { 171 | dependsOn("dokkaGenerate", "mkdocsBuild") 172 | doLast { 173 | copy { 174 | from(layout.buildDirectory.dir("mkdocs")) 175 | into(layout.buildDirectory.dir("docs")) 176 | } 177 | copy { 178 | from(layout.buildDirectory.dir("dokka/html")) 179 | into(layout.buildDirectory.dir("docs/api")) 180 | } 181 | } 182 | } 183 | 184 | spotless { 185 | kotlinGradle { 186 | target("*.gradle.kts") 187 | ktfmt().googleStyle() 188 | } 189 | kotlin { 190 | target("src/**/*.kt") 191 | ktfmt().googleStyle() 192 | } 193 | format("markdown") { 194 | target("*.md", "docs/**/*.md") 195 | prettier(libs.versions.tool.prettier.get()).config(mapOf("proseWrap" to "always")) 196 | } 197 | yaml { 198 | target(".github/**/*.yml") 199 | prettier(libs.versions.tool.prettier.get()) 200 | } 201 | } 202 | 203 | tasks.register("installGitHooks") { 204 | doLast { 205 | copy { 206 | from("${rootProject.projectDir}/scripts/pre-commit") 207 | into("${rootProject.projectDir}/.git/hooks") 208 | } 209 | } 210 | } 211 | 212 | tasks.named("clean") { doLast { delete("${rootProject.projectDir}/.git/hooks/pre-commit") } } 213 | -------------------------------------------------------------------------------- /docs/docs/.gitignore: -------------------------------------------------------------------------------- 1 | _data/gradle.yml 2 | -------------------------------------------------------------------------------- /docs/docs/api/index.html: -------------------------------------------------------------------------------- 1 | Dokka HTML will replace this file at build time. 2 | -------------------------------------------------------------------------------- /docs/docs/index.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | ## Introduction 4 | 5 | PokeKotlin is a modern [Kotlin Multiplatform] client for [PokéAPI]. You can use 6 | it to integrate all sorts of Pokémon data into your Kotlin projects. 7 | 8 | Under the hood, it's built on [Ktor], [Kotlin Serialization], and coroutines. 9 | 10 | ## Supported platforms 11 | 12 | - Kotlin/JVM, including Android 13 | - Kotlin/JS for browser and Node 14 | - Kotlin/WASM for browser and Node 15 | - Kotlin/Native for Linux, Windows, macOS, iOS, tvOS, and watchOS 16 | 17 | ## Installation 18 | 19 | This library is published via [Maven Central], and snapshot builds of `main` are 20 | additionally available on [GitHub Packages]. 21 | 22 | === "Releases (Maven Central)" 23 | 24 | The latest release is **v{{ gradle.release_version }}**. In your Gradle version catalog, add: 25 | 26 | ```toml title="libs.versions.toml" 27 | [libraries] 28 | pokekotlin = { module = "dev.sargunv.pokekotlin:pokekotlin", version = "{{ gradle.release_version }}" } 29 | ``` 30 | 31 | === "Snapshots (GitHub Packages)" 32 | 33 | !!! warning 34 | 35 | The published documentation is for the latest release, and may not match the snapshot 36 | version. If using snapshots, always refer to the [latest source code][repo] for the most 37 | accurate information. 38 | 39 | First, follow [GitHub's guide][gh-packages-guide] for authenticating to GitHub Packages. Your 40 | settings.gradle.kts should have something like this: 41 | 42 | ```kotlin title="settings.gradle.kts" 43 | repositories { 44 | maven { 45 | url = uri("https://maven.pkg.github.com/pokeapi/pokekotlin") 46 | credentials { 47 | username = project.findProperty("gpr.user") as String? ?: System.getenv("GH_USERNAME") 48 | password = project.findProperty("gpr.key") as String? ?: System.getenv("GH_TOKEN") 49 | } 50 | } 51 | } 52 | ``` 53 | 54 | The latest snapshot is **v{{ gradle.snapshot_version }}**. In your Gradle version catalog, add: 55 | 56 | ```toml title="libs.versions.toml" 57 | [libraries] 58 | pokekotlin = { module = "dev.sargunv.pokekotlin:pokekotlin", version = "{{ gradle.snapshot_version }}" } 59 | ``` 60 | 61 | In your Gradle build script, add: 62 | 63 | ```kotlin title="build.gradle.kts" 64 | commonMain.dependencies { 65 | implementation(libs.maplibre.compose) 66 | } 67 | ``` 68 | 69 | ## Usage 70 | 71 | For basic usage, use the global `PokeApi` instance: 72 | 73 | ```kotlin 74 | -8<- "src/commonTest/kotlin/dev/sargunv/pokekotlin/example/example.kt:simple" 75 | ``` 76 | 77 | By default, the client will connect to the official `https://pokeapi.co/` 78 | instance and cache results in memory. 79 | 80 | If you want to customize the client, create a custom instance of the client: 81 | 82 | ```kotlin 83 | -8<- "src/commonTest/kotlin/dev/sargunv/pokekotlin/example/example.kt:custom" 84 | ``` 85 | 86 | For further details, see the Dokka [API Reference](./api). 87 | 88 | [Kotlin Multiplatform]: https://kotlinlang.org/docs/multiplatform.html 89 | [PokéAPI]: https://pokeapi.co/ 90 | [Maven Central]: https://central.sonatype.com/namespace/dev.sargunv.pokekotlin 91 | [GitHub Packages]: 92 | https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry 93 | [gh-packages-guide]: 94 | https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry#using-a-published-package 95 | [repo]: https://github.com/pokeapi/pokekotlin 96 | [Ktor]: https://ktor.io/ 97 | [Kotlin Serialization]: https://github.com/Kotlin/kotlinx.serialization 98 | [coroutines]: https://kotlinlang.org/docs/coroutines-guide.html 99 | -------------------------------------------------------------------------------- /docs/docs/stylesheets/extra.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokeAPI/pokekotlin/ad18f1e8ef38607ae76fe56823164b1be741ad90/docs/docs/stylesheets/extra.css -------------------------------------------------------------------------------- /docs/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: PokeKotlin 2 | 3 | site_description: PokeKotlin is a Kotlin client for PokeApi. 4 | site_url: https://pokeapi.github.io/pokekotlin 5 | 6 | repo_name: pokekotlin 7 | repo_url: https://github.com/PokeAPI/pokekotlin 8 | edit_uri: "edit/main/docs/docs/" 9 | 10 | copyright: "Copyright © 2025 Sargun Vohra" 11 | 12 | extra_css: 13 | - stylesheets/extra.css 14 | 15 | theme: 16 | name: "material" 17 | icon: 18 | repo: "fontawesome/brands/github" 19 | palette: 20 | - media: "(prefers-color-scheme)" 21 | toggle: 22 | icon: material/brightness-auto 23 | name: Switch to light mode 24 | - media: "(prefers-color-scheme: light)" 25 | scheme: default 26 | toggle: 27 | icon: material/brightness-7 28 | name: Switch to dark mode 29 | - media: "(prefers-color-scheme: dark)" 30 | scheme: slate 31 | toggle: 32 | icon: material/brightness-4 33 | name: Switch to system preference 34 | features: 35 | - content.code.copy 36 | - content.code.annotate 37 | - navigation.instant 38 | - navigation.instant.prefetch 39 | - navigation.instant.progress 40 | - navigation.instant.preview 41 | - navigation.tracking 42 | - navigation.expand 43 | - navigation.path 44 | - navigation.indexes 45 | - toc.follow 46 | - content.action.edit 47 | - content.tabs.link 48 | 49 | plugins: 50 | - search 51 | - markdownextradata 52 | 53 | markdown_extensions: 54 | # Python Markdown 55 | - abbr 56 | - admonition 57 | - attr_list 58 | - def_list 59 | - footnotes 60 | - meta 61 | - md_in_html 62 | - toc: 63 | permalink: true 64 | - tables 65 | 66 | # Python Markdown Extensions 67 | - pymdownx.arithmatex: 68 | generic: true 69 | - pymdownx.betterem: 70 | smart_enable: all 71 | - pymdownx.caret 72 | - pymdownx.details 73 | - pymdownx.emoji: 74 | emoji_index: !!python/name:material.extensions.emoji.twemoji 75 | emoji_generator: !!python/name:material.extensions.emoji.to_svg 76 | - pymdownx.highlight 77 | - pymdownx.inlinehilite 78 | - pymdownx.keys 79 | - pymdownx.mark 80 | - pymdownx.smartsymbols 81 | - pymdownx.snippets: 82 | base_path: ../ 83 | dedent_subsections: true 84 | - pymdownx.superfences 85 | - pymdownx.tabbed: 86 | alternate_style: true 87 | - pymdownx.tasklist: 88 | custom_checkbox: true 89 | - pymdownx.tilde 90 | 91 | nav: 92 | - index.md 93 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | kotlin.incremental.wasm=true 3 | kotlin.daemon.jvmargs=-Xmx4096M 4 | org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled 5 | org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true 6 | org.gradle.configuration-cache=false 7 | org.gradle.jvmargs=-Xmx4096M -Dfile.encoding=UTF-8 8 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | # Regular libraries: keep as up to date as possible. 3 | kotlinx-coroutines-test = "1.10.2" 4 | kotlinx-io = "0.7.0" 5 | kotlinx-serialization = "1.8.1" 6 | ktor = "3.1.3" 7 | 8 | # Regular tools: keep as up to date as possible 9 | gradle-kotlin = "2.1.21" 10 | gradle-ksp = "2.1.21-2.0.1" # first part is Kotlin version 11 | gradle-ktorfit = "2.5.2" 12 | gradle-dokka = "2.0.0" 13 | gradle-jgitver = "0.10.0-rc03" 14 | gradle-mavenPublish = "0.32.0" 15 | gradle-mkdocs = "4.0.1" 16 | gradle-spotless = "7.0.4" 17 | tool-prettier = "3.5.3" 18 | 19 | [libraries] 20 | kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines-test" } 21 | kotlinx-io = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinx-io" } 22 | kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } 23 | ktorfit = { module = "de.jensklingenberg.ktorfit:ktorfit-lib", version.ref = "gradle-ktorfit" } 24 | ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } 25 | ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" } 26 | ktor-client-winhttp = { module = "io.ktor:ktor-client-winhttp", version.ref = "ktor" } 27 | ktor-client-curl = { module = "io.ktor:ktor-client-curl", version.ref = "ktor" } 28 | ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" } 29 | ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor" } 30 | ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } 31 | ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } 32 | 33 | [plugins] 34 | dokka = { id = "org.jetbrains.dokka", version.ref = "gradle-dokka" } 35 | jgitver = { id = "fr.brouillard.oss.gradle.jgitver", version.ref = "gradle-jgitver" } 36 | kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "gradle-kotlin" } 37 | kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "gradle-kotlin" } 38 | ksp = { id = "com.google.devtools.ksp", version.ref = "gradle-ksp" } 39 | ktorfit = { id = "de.jensklingenberg.ktorfit", version.ref = "gradle-ktorfit" } 40 | mavenPublish = { id = "com.vanniktech.maven.publish", version.ref = "gradle-mavenPublish" } 41 | mkdocs = { id = "ru.vyarus.mkdocs-build", version.ref = "gradle-mkdocs" } 42 | spotless = { id = "com.diffplug.spotless", version.ref = "gradle-spotless" } 43 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PokeAPI/pokekotlin/ad18f1e8ef38607ae76fe56823164b1be741ad90/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC2039,SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC2039,SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command: 206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 | # and any embedded shellness will be escaped. 208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 | # treated as '${Hostname}' itself on the command line. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | set windows-shell := ["C:\\Program Files\\Git\\bin\\sh.exe", "-c"] 2 | 3 | _default: 4 | just --list 5 | 6 | # Serve PokeAPI data from static files 7 | test-server: 8 | ./scripts/test-server 9 | 10 | # Spawn a background job serving PokeAPI data from static files 11 | test-server-background: 12 | ./scripts/test-server & 13 | 14 | format: 15 | ./gradlew spotlessApply 16 | 17 | test-jvm: 18 | ./gradlew jvmTest 19 | 20 | test-js-browser: 21 | ./gradlew jsBrowserTest 22 | 23 | test-js-node: 24 | ./gradlew jsNodeTest 25 | 26 | test-wasm-browser: 27 | ./gradlew wasmBrowserTest 28 | 29 | test-wasm-node: 30 | ./gradlew wasmNodeTest 31 | 32 | native-desktop-task := ( 33 | if os() == "macos" { "macosArm64Test" } 34 | else if os() == "linux" { "linuxX64Test" } 35 | else if os() == "windows" { "mingwX64Test" } 36 | else { error("Unrecognized OS: " + os()) } 37 | ) 38 | 39 | test-native-desktop: 40 | ./gradlew {{ native-desktop-task }} 41 | 42 | test-native-ios: 43 | ./gradlew iosSimulatorArm64Test 44 | 45 | test-native-tvos: 46 | ./gradlew tvosSimulatorArm64Test 47 | 48 | test-native-watchos: 49 | ./gradlew watchosSimulatorArm64Test 50 | -------------------------------------------------------------------------------- /scripts/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Run Spotless 4 | ./gradlew -q spotlessApply 5 | 6 | # Add any modified files back to the staging area 7 | git add . 8 | -------------------------------------------------------------------------------- /scripts/test-server: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | npx -y http-server ./api-data/data -e json -p 8080 --cors 3 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "pokekotlin" 2 | 3 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") 4 | 5 | pluginManagement { 6 | repositories { 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } 11 | 12 | dependencyResolutionManagement { repositories { mavenCentral() } } 13 | 14 | plugins { id("org.gradle.toolchains.foojay-resolver-convention") version ("0.10.0") } 15 | -------------------------------------------------------------------------------- /src/appleMain/kotlin/dev/sargunv/pokekotlin/internal/getDefaultEngine.apple.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.internal 2 | 3 | import io.ktor.client.engine.darwin.Darwin 4 | 5 | internal actual fun getDefaultEngine() = Darwin.create() 6 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/PokeApi.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin 2 | 3 | import de.jensklingenberg.ktorfit.Ktorfit.Builder 4 | import de.jensklingenberg.ktorfit.http.GET 5 | import de.jensklingenberg.ktorfit.http.Path 6 | import de.jensklingenberg.ktorfit.http.Query 7 | import dev.sargunv.pokekotlin.internal.PokeApiConverter 8 | import dev.sargunv.pokekotlin.internal.PokeApiJson 9 | import dev.sargunv.pokekotlin.internal.getDefaultEngine 10 | import dev.sargunv.pokekotlin.model.Ability 11 | import dev.sargunv.pokekotlin.model.ApiResourceList 12 | import dev.sargunv.pokekotlin.model.Berry 13 | import dev.sargunv.pokekotlin.model.BerryFirmness 14 | import dev.sargunv.pokekotlin.model.BerryFlavor 15 | import dev.sargunv.pokekotlin.model.Characteristic 16 | import dev.sargunv.pokekotlin.model.ContestEffect 17 | import dev.sargunv.pokekotlin.model.ContestType 18 | import dev.sargunv.pokekotlin.model.EggGroup 19 | import dev.sargunv.pokekotlin.model.EncounterCondition 20 | import dev.sargunv.pokekotlin.model.EncounterConditionValue 21 | import dev.sargunv.pokekotlin.model.EncounterMethod 22 | import dev.sargunv.pokekotlin.model.EvolutionChain 23 | import dev.sargunv.pokekotlin.model.EvolutionTrigger 24 | import dev.sargunv.pokekotlin.model.Gender 25 | import dev.sargunv.pokekotlin.model.Generation 26 | import dev.sargunv.pokekotlin.model.GrowthRate 27 | import dev.sargunv.pokekotlin.model.Item 28 | import dev.sargunv.pokekotlin.model.ItemAttribute 29 | import dev.sargunv.pokekotlin.model.ItemCategory 30 | import dev.sargunv.pokekotlin.model.ItemFlingEffect 31 | import dev.sargunv.pokekotlin.model.ItemPocket 32 | import dev.sargunv.pokekotlin.model.Language 33 | import dev.sargunv.pokekotlin.model.Location 34 | import dev.sargunv.pokekotlin.model.LocationArea 35 | import dev.sargunv.pokekotlin.model.LocationAreaEncounter 36 | import dev.sargunv.pokekotlin.model.Machine 37 | import dev.sargunv.pokekotlin.model.Move 38 | import dev.sargunv.pokekotlin.model.MoveAilment 39 | import dev.sargunv.pokekotlin.model.MoveBattleStyle 40 | import dev.sargunv.pokekotlin.model.MoveCategory 41 | import dev.sargunv.pokekotlin.model.MoveDamageClass 42 | import dev.sargunv.pokekotlin.model.MoveLearnMethod 43 | import dev.sargunv.pokekotlin.model.MoveTarget 44 | import dev.sargunv.pokekotlin.model.NamedApiResourceList 45 | import dev.sargunv.pokekotlin.model.Nature 46 | import dev.sargunv.pokekotlin.model.PalParkArea 47 | import dev.sargunv.pokekotlin.model.PokeathlonStat 48 | import dev.sargunv.pokekotlin.model.Pokedex 49 | import dev.sargunv.pokekotlin.model.Pokemon 50 | import dev.sargunv.pokekotlin.model.PokemonColor 51 | import dev.sargunv.pokekotlin.model.PokemonForm 52 | import dev.sargunv.pokekotlin.model.PokemonHabitat 53 | import dev.sargunv.pokekotlin.model.PokemonShape 54 | import dev.sargunv.pokekotlin.model.PokemonSpecies 55 | import dev.sargunv.pokekotlin.model.Region 56 | import dev.sargunv.pokekotlin.model.Stat 57 | import dev.sargunv.pokekotlin.model.SuperContestEffect 58 | import dev.sargunv.pokekotlin.model.Type 59 | import dev.sargunv.pokekotlin.model.Version 60 | import dev.sargunv.pokekotlin.model.VersionGroup 61 | import io.ktor.client.HttpClient 62 | import io.ktor.client.HttpClientConfig 63 | import io.ktor.client.engine.HttpClientEngine 64 | import io.ktor.client.plugins.cache.HttpCache 65 | import io.ktor.client.plugins.cache.storage.CacheStorage 66 | import io.ktor.client.plugins.contentnegotiation.ContentNegotiation 67 | import io.ktor.http.ContentType 68 | import io.ktor.serialization.kotlinx.json.json 69 | 70 | interface PokeApi { 71 | 72 | // region Resource Lists 73 | 74 | // region Berries 75 | 76 | @GET("berry/") 77 | suspend fun getBerryList( 78 | @Query("offset") offset: Int, 79 | @Query("limit") limit: Int, 80 | ): NamedApiResourceList 81 | 82 | @GET("berry-firmness/") 83 | suspend fun getBerryFirmnessList( 84 | @Query("offset") offset: Int, 85 | @Query("limit") limit: Int, 86 | ): NamedApiResourceList 87 | 88 | @GET("berry-flavor/") 89 | suspend fun getBerryFlavorList( 90 | @Query("offset") offset: Int, 91 | @Query("limit") limit: Int, 92 | ): NamedApiResourceList 93 | 94 | // endregion Berries 95 | 96 | // region Contests 97 | 98 | @GET("contest-type/") 99 | suspend fun getContestTypeList( 100 | @Query("offset") offset: Int, 101 | @Query("limit") limit: Int, 102 | ): NamedApiResourceList 103 | 104 | @GET("contest-effect/") 105 | suspend fun getContestEffectList( 106 | @Query("offset") offset: Int, 107 | @Query("limit") limit: Int, 108 | ): ApiResourceList 109 | 110 | @GET("super-contest-effect/") 111 | suspend fun getSuperContestEffectList( 112 | @Query("offset") offset: Int, 113 | @Query("limit") limit: Int, 114 | ): ApiResourceList 115 | 116 | // endregion Contests 117 | 118 | // region Encounters 119 | 120 | @GET("encounter-method/") 121 | suspend fun getEncounterMethodList( 122 | @Query("offset") offset: Int, 123 | @Query("limit") limit: Int, 124 | ): NamedApiResourceList 125 | 126 | @GET("encounter-condition/") 127 | suspend fun getEncounterConditionList( 128 | @Query("offset") offset: Int, 129 | @Query("limit") limit: Int, 130 | ): NamedApiResourceList 131 | 132 | @GET("encounter-condition-value/") 133 | suspend fun getEncounterConditionValueList( 134 | @Query("offset") offset: Int, 135 | @Query("limit") limit: Int, 136 | ): NamedApiResourceList 137 | 138 | // endregion 139 | 140 | // region Evolution 141 | 142 | @GET("evolution-chain/") 143 | suspend fun getEvolutionChainList( 144 | @Query("offset") offset: Int, 145 | @Query("limit") limit: Int, 146 | ): ApiResourceList 147 | 148 | @GET("evolution-trigger/") 149 | suspend fun getEvolutionTriggerList( 150 | @Query("offset") offset: Int, 151 | @Query("limit") limit: Int, 152 | ): NamedApiResourceList 153 | 154 | // endregion 155 | 156 | // region Games 157 | 158 | @GET("generation/") 159 | suspend fun getGenerationList( 160 | @Query("offset") offset: Int, 161 | @Query("limit") limit: Int, 162 | ): NamedApiResourceList 163 | 164 | @GET("pokedex/") 165 | suspend fun getPokedexList( 166 | @Query("offset") offset: Int, 167 | @Query("limit") limit: Int, 168 | ): NamedApiResourceList 169 | 170 | @GET("version/") 171 | suspend fun getVersionList( 172 | @Query("offset") offset: Int, 173 | @Query("limit") limit: Int, 174 | ): NamedApiResourceList 175 | 176 | @GET("version-group/") 177 | suspend fun getVersionGroupList( 178 | @Query("offset") offset: Int, 179 | @Query("limit") limit: Int, 180 | ): NamedApiResourceList 181 | 182 | // endregion 183 | 184 | // region Items 185 | 186 | @GET("item/") 187 | suspend fun getItemList( 188 | @Query("offset") offset: Int, 189 | @Query("limit") limit: Int, 190 | ): NamedApiResourceList 191 | 192 | @GET("item-attribute/") 193 | suspend fun getItemAttributeList( 194 | @Query("offset") offset: Int, 195 | @Query("limit") limit: Int, 196 | ): NamedApiResourceList 197 | 198 | @GET("item-category/") 199 | suspend fun getItemCategoryList( 200 | @Query("offset") offset: Int, 201 | @Query("limit") limit: Int, 202 | ): NamedApiResourceList 203 | 204 | @GET("item-fling-effect/") 205 | suspend fun getItemFlingEffectList( 206 | @Query("offset") offset: Int, 207 | @Query("limit") limit: Int, 208 | ): NamedApiResourceList 209 | 210 | @GET("item-pocket/") 211 | suspend fun getItemPocketList( 212 | @Query("offset") offset: Int, 213 | @Query("limit") limit: Int, 214 | ): NamedApiResourceList 215 | 216 | // endregion 217 | 218 | // region Moves 219 | 220 | @GET("move/") 221 | suspend fun getMoveList( 222 | @Query("offset") offset: Int, 223 | @Query("limit") limit: Int, 224 | ): NamedApiResourceList 225 | 226 | @GET("move-ailment/") 227 | suspend fun getMoveAilmentList( 228 | @Query("offset") offset: Int, 229 | @Query("limit") limit: Int, 230 | ): NamedApiResourceList 231 | 232 | @GET("move-battle-style/") 233 | suspend fun getMoveBattleStyleList( 234 | @Query("offset") offset: Int, 235 | @Query("limit") limit: Int, 236 | ): NamedApiResourceList 237 | 238 | @GET("move-category/") 239 | suspend fun getMoveCategoryList( 240 | @Query("offset") offset: Int, 241 | @Query("limit") limit: Int, 242 | ): NamedApiResourceList 243 | 244 | @GET("move-damage-class/") 245 | suspend fun getMoveDamageClassList( 246 | @Query("offset") offset: Int, 247 | @Query("limit") limit: Int, 248 | ): NamedApiResourceList 249 | 250 | @GET("move-learn-method/") 251 | suspend fun getMoveLearnMethodList( 252 | @Query("offset") offset: Int, 253 | @Query("limit") limit: Int, 254 | ): NamedApiResourceList 255 | 256 | @GET("move-target/") 257 | suspend fun getMoveTargetList( 258 | @Query("offset") offset: Int, 259 | @Query("limit") limit: Int, 260 | ): NamedApiResourceList 261 | 262 | // endregion 263 | 264 | // region Locations 265 | 266 | @GET("location/") 267 | suspend fun getLocationList( 268 | @Query("offset") offset: Int, 269 | @Query("limit") limit: Int, 270 | ): NamedApiResourceList 271 | 272 | @GET("location-area/") 273 | suspend fun getLocationAreaList( 274 | @Query("offset") offset: Int, 275 | @Query("limit") limit: Int, 276 | ): NamedApiResourceList 277 | 278 | @GET("pal-park-area/") 279 | suspend fun getPalParkAreaList( 280 | @Query("offset") offset: Int, 281 | @Query("limit") limit: Int, 282 | ): NamedApiResourceList 283 | 284 | @GET("region/") 285 | suspend fun getRegionList( 286 | @Query("offset") offset: Int, 287 | @Query("limit") limit: Int, 288 | ): NamedApiResourceList 289 | 290 | // endregion 291 | 292 | // region Machines 293 | 294 | @GET("machine/") 295 | suspend fun getMachineList( 296 | @Query("offset") offset: Int, 297 | @Query("limit") limit: Int, 298 | ): ApiResourceList 299 | 300 | // endregion 301 | 302 | // region Pokemon 303 | 304 | @GET("ability/") 305 | suspend fun getAbilityList( 306 | @Query("offset") offset: Int, 307 | @Query("limit") limit: Int, 308 | ): NamedApiResourceList 309 | 310 | @GET("characteristic/") 311 | suspend fun getCharacteristicList( 312 | @Query("offset") offset: Int, 313 | @Query("limit") limit: Int, 314 | ): ApiResourceList 315 | 316 | @GET("egg-group/") 317 | suspend fun getEggGroupList( 318 | @Query("offset") offset: Int, 319 | @Query("limit") limit: Int, 320 | ): NamedApiResourceList 321 | 322 | @GET("gender/") 323 | suspend fun getGenderList( 324 | @Query("offset") offset: Int, 325 | @Query("limit") limit: Int, 326 | ): NamedApiResourceList 327 | 328 | @GET("growth-rate/") 329 | suspend fun getGrowthRateList( 330 | @Query("offset") offset: Int, 331 | @Query("limit") limit: Int, 332 | ): NamedApiResourceList 333 | 334 | @GET("nature/") 335 | suspend fun getNatureList( 336 | @Query("offset") offset: Int, 337 | @Query("limit") limit: Int, 338 | ): NamedApiResourceList 339 | 340 | @GET("pokeathlon-stat/") 341 | suspend fun getPokeathlonStatList( 342 | @Query("offset") offset: Int, 343 | @Query("limit") limit: Int, 344 | ): NamedApiResourceList 345 | 346 | @GET("pokemon/") 347 | suspend fun getPokemonList( 348 | @Query("offset") offset: Int, 349 | @Query("limit") limit: Int, 350 | ): NamedApiResourceList 351 | 352 | @GET("pokemon-color/") 353 | suspend fun getPokemonColorList( 354 | @Query("offset") offset: Int, 355 | @Query("limit") limit: Int, 356 | ): NamedApiResourceList 357 | 358 | @GET("pokemon-form/") 359 | suspend fun getPokemonFormList( 360 | @Query("offset") offset: Int, 361 | @Query("limit") limit: Int, 362 | ): NamedApiResourceList 363 | 364 | @GET("pokemon-habitat/") 365 | suspend fun getPokemonHabitatList( 366 | @Query("offset") offset: Int, 367 | @Query("limit") limit: Int, 368 | ): NamedApiResourceList 369 | 370 | @GET("pokemon-shape/") 371 | suspend fun getPokemonShapeList( 372 | @Query("offset") offset: Int, 373 | @Query("limit") limit: Int, 374 | ): NamedApiResourceList 375 | 376 | @GET("pokemon-species/") 377 | suspend fun getPokemonSpeciesList( 378 | @Query("offset") offset: Int, 379 | @Query("limit") limit: Int, 380 | ): NamedApiResourceList 381 | 382 | @GET("stat/") 383 | suspend fun getStatList( 384 | @Query("offset") offset: Int, 385 | @Query("limit") limit: Int, 386 | ): NamedApiResourceList 387 | 388 | @GET("type/") 389 | suspend fun getTypeList( 390 | @Query("offset") offset: Int, 391 | @Query("limit") limit: Int, 392 | ): NamedApiResourceList 393 | 394 | // endregion 395 | 396 | // region Utility 397 | 398 | @GET("language/") 399 | suspend fun getLanguageList( 400 | @Query("offset") offset: Int, 401 | @Query("limit") limit: Int, 402 | ): NamedApiResourceList 403 | 404 | // endregion 405 | 406 | // endregion 407 | 408 | // region Berries 409 | 410 | @GET("berry/{id}/") suspend fun getBerry(@Path("id") id: Int): Berry 411 | 412 | @GET("berry-firmness/{id}/") suspend fun getBerryFirmness(@Path("id") id: Int): BerryFirmness 413 | 414 | @GET("berry-flavor/{id}/") suspend fun getBerryFlavor(@Path("id") id: Int): BerryFlavor 415 | 416 | // endregion Berries 417 | 418 | // region Contests 419 | 420 | @GET("contest-type/{id}/") suspend fun getContestType(@Path("id") id: Int): ContestType 421 | 422 | @GET("contest-effect/{id}/") suspend fun getContestEffect(@Path("id") id: Int): ContestEffect 423 | 424 | @GET("super-contest-effect/{id}/") 425 | suspend fun getSuperContestEffect(@Path("id") id: Int): SuperContestEffect 426 | 427 | // endregion Contests 428 | 429 | // region Encounters 430 | 431 | @GET("encounter-method/{id}/") 432 | suspend fun getEncounterMethod(@Path("id") id: Int): EncounterMethod 433 | 434 | @GET("encounter-condition/{id}/") 435 | suspend fun getEncounterCondition(@Path("id") id: Int): EncounterCondition 436 | 437 | @GET("encounter-condition-value/{id}/") 438 | suspend fun getEncounterConditionValue(@Path("id") id: Int): EncounterConditionValue 439 | 440 | // endregion Contests 441 | 442 | // region Evolution 443 | 444 | @GET("evolution-chain/{id}/") suspend fun getEvolutionChain(@Path("id") id: Int): EvolutionChain 445 | 446 | @GET("evolution-trigger/{id}/") 447 | suspend fun getEvolutionTrigger(@Path("id") id: Int): EvolutionTrigger 448 | 449 | // endregion Evolution 450 | 451 | // region Games 452 | 453 | @GET("generation/{id}/") suspend fun getGeneration(@Path("id") id: Int): Generation 454 | 455 | @GET("pokedex/{id}/") suspend fun getPokedex(@Path("id") id: Int): Pokedex 456 | 457 | @GET("version/{id}/") suspend fun getVersion(@Path("id") id: Int): Version 458 | 459 | @GET("version-group/{id}/") suspend fun getVersionGroup(@Path("id") id: Int): VersionGroup 460 | 461 | // endregion Games 462 | 463 | // region Items 464 | 465 | @GET("item/{id}/") suspend fun getItem(@Path("id") id: Int): Item 466 | 467 | @GET("item-attribute/{id}/") suspend fun getItemAttribute(@Path("id") id: Int): ItemAttribute 468 | 469 | @GET("item-category/{id}/") suspend fun getItemCategory(@Path("id") id: Int): ItemCategory 470 | 471 | @GET("item-fling-effect/{id}/") 472 | suspend fun getItemFlingEffect(@Path("id") id: Int): ItemFlingEffect 473 | 474 | @GET("item-pocket/{id}/") suspend fun getItemPocket(@Path("id") id: Int): ItemPocket 475 | 476 | // endregion Items 477 | 478 | // region Moves 479 | 480 | @GET("move/{id}/") suspend fun getMove(@Path("id") id: Int): Move 481 | 482 | @GET("move-ailment/{id}/") suspend fun getMoveAilment(@Path("id") id: Int): MoveAilment 483 | 484 | @GET("move-battle-style/{id}/") 485 | suspend fun getMoveBattleStyle(@Path("id") id: Int): MoveBattleStyle 486 | 487 | @GET("move-category/{id}/") suspend fun getMoveCategory(@Path("id") id: Int): MoveCategory 488 | 489 | @GET("move-damage-class/{id}/") 490 | suspend fun getMoveDamageClass(@Path("id") id: Int): MoveDamageClass 491 | 492 | @GET("move-learn-method/{id}/") 493 | suspend fun getMoveLearnMethod(@Path("id") id: Int): MoveLearnMethod 494 | 495 | @GET("move-target/{id}/") suspend fun getMoveTarget(@Path("id") id: Int): MoveTarget 496 | 497 | // endregion Moves 498 | 499 | // region Locations 500 | 501 | @GET("location/{id}/") suspend fun getLocation(@Path("id") id: Int): Location 502 | 503 | @GET("location-area/{id}/") suspend fun getLocationArea(@Path("id") id: Int): LocationArea 504 | 505 | @GET("pal-park-area/{id}/") suspend fun getPalParkArea(@Path("id") id: Int): PalParkArea 506 | 507 | @GET("region/{id}/") suspend fun getRegion(@Path("id") id: Int): Region 508 | 509 | // endregion Locations 510 | 511 | // region Machines 512 | 513 | @GET("machine/{id}/") suspend fun getMachine(@Path("id") id: Int): Machine 514 | 515 | // endregion 516 | 517 | // region Pokemon 518 | 519 | @GET("ability/{id}/") suspend fun getAbility(@Path("id") id: Int): Ability 520 | 521 | @GET("characteristic/{id}/") suspend fun getCharacteristic(@Path("id") id: Int): Characteristic 522 | 523 | @GET("egg-group/{id}/") suspend fun getEggGroup(@Path("id") id: Int): EggGroup 524 | 525 | @GET("gender/{id}/") suspend fun getGender(@Path("id") id: Int): Gender 526 | 527 | @GET("growth-rate/{id}/") suspend fun getGrowthRate(@Path("id") id: Int): GrowthRate 528 | 529 | @GET("nature/{id}/") suspend fun getNature(@Path("id") id: Int): Nature 530 | 531 | @GET("pokeathlon-stat/{id}/") suspend fun getPokeathlonStat(@Path("id") id: Int): PokeathlonStat 532 | 533 | @GET("pokemon/{id}/") suspend fun getPokemon(@Path("id") id: Int): Pokemon 534 | 535 | @GET("pokemon/{id}/encounters/") 536 | suspend fun getPokemonEncounterList(@Path("id") id: Int): List 537 | 538 | @GET("pokemon-color/{id}/") suspend fun getPokemonColor(@Path("id") id: Int): PokemonColor 539 | 540 | @GET("pokemon-form/{id}/") suspend fun getPokemonForm(@Path("id") id: Int): PokemonForm 541 | 542 | @GET("pokemon-habitat/{id}/") suspend fun getPokemonHabitat(@Path("id") id: Int): PokemonHabitat 543 | 544 | @GET("pokemon-shape/{id}/") suspend fun getPokemonShape(@Path("id") id: Int): PokemonShape 545 | 546 | @GET("pokemon-species/{id}/") suspend fun getPokemonSpecies(@Path("id") id: Int): PokemonSpecies 547 | 548 | @GET("stat/{id}/") suspend fun getStat(@Path("id") id: Int): Stat 549 | 550 | @GET("type/{id}/") suspend fun getType(@Path("id") id: Int): Type 551 | 552 | // endregion Pokemon 553 | 554 | // region Utility 555 | 556 | @GET("language/{id}/") suspend fun getLanguage(@Path("id") id: Int): Language 557 | 558 | // endregion Utility 559 | 560 | companion object : PokeApi by PokeApi() 561 | } 562 | 563 | fun PokeApi( 564 | baseUrl: String = "https://pokeapi.co/api/v2/", 565 | engine: HttpClientEngine = getDefaultEngine(), 566 | cacheStorage: CacheStorage? = null, 567 | configure: HttpClientConfig<*>.() -> Unit = {}, 568 | ) = 569 | Builder() 570 | .baseUrl(baseUrl) 571 | .httpClient( 572 | HttpClient(engine) { 573 | configure() 574 | install(HttpCache) { cacheStorage?.let { privateStorage(it) } } 575 | install(ContentNegotiation) { json(PokeApiJson, ContentType.Any) } 576 | } 577 | ) 578 | .converterFactories(PokeApiConverter.Factory) 579 | .build() 580 | .createPokeApi() 581 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/PokeApiException.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin 2 | 3 | import io.ktor.http.HttpStatusCode 4 | 5 | sealed class PokeApiException : Throwable { 6 | constructor(message: String) : super(message) 7 | 8 | constructor(cause: Throwable) : super(cause) 9 | 10 | class HttpStatus(val status: HttpStatusCode) : PokeApiException(status.toString()) 11 | 12 | class UnknownException(cause: Throwable) : PokeApiException(cause) 13 | } 14 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/internal/DelegatingSerializer.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.internal 2 | 3 | import kotlinx.serialization.KSerializer 4 | import kotlinx.serialization.descriptors.SerialDescriptor 5 | import kotlinx.serialization.encoding.Decoder 6 | import kotlinx.serialization.encoding.Encoder 7 | 8 | internal class DelegatingSerializer( 9 | serialName: String, 10 | private val delegate: KSerializer, 11 | private val fromDelegate: (D) -> T, 12 | private val toDelegate: (T) -> D, 13 | ) : KSerializer { 14 | 15 | override val descriptor = SerialDescriptor(serialName, delegate.descriptor) 16 | 17 | override fun serialize(encoder: Encoder, value: T) = 18 | encoder.encodeSerializableValue(delegate, toDelegate(value)) 19 | 20 | override fun deserialize(decoder: Decoder): T = 21 | fromDelegate(decoder.decodeSerializableValue(delegate)) 22 | } 23 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/internal/PokeApiConverter.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.internal 2 | 3 | import de.jensklingenberg.ktorfit.Ktorfit 4 | import de.jensklingenberg.ktorfit.converter.Converter 5 | import de.jensklingenberg.ktorfit.converter.KtorfitResult 6 | import de.jensklingenberg.ktorfit.converter.TypeData 7 | import dev.sargunv.pokekotlin.PokeApiException 8 | import io.ktor.client.call.body 9 | import io.ktor.client.statement.HttpResponse 10 | import io.ktor.http.isSuccess 11 | 12 | internal class PokeApiConverter(private val typeData: TypeData) : 13 | Converter.SuspendResponseConverter { 14 | override suspend fun convert(result: KtorfitResult): Any { 15 | return when (result) { 16 | is KtorfitResult.Failure -> throw PokeApiException.UnknownException(result.throwable) 17 | is KtorfitResult.Success -> { 18 | val status = result.response.status 19 | when { 20 | status.isSuccess() -> result.response.body(typeData.typeInfo) 21 | else -> throw PokeApiException.HttpStatus(status) 22 | } 23 | } 24 | } 25 | } 26 | 27 | internal object Factory : Converter.Factory { 28 | override fun suspendResponseConverter( 29 | typeData: TypeData, 30 | ktorfit: Ktorfit, 31 | ): Converter.SuspendResponseConverter = PokeApiConverter(typeData) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/internal/PokeApiJson.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.internal 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | import kotlinx.serialization.json.Json 5 | import kotlinx.serialization.json.JsonNamingStrategy 6 | 7 | @OptIn(ExperimentalSerializationApi::class) 8 | internal val PokeApiJson = Json { 9 | prettyPrint = true 10 | ignoreUnknownKeys = true 11 | namingStrategy = JsonNamingStrategy.SnakeCase 12 | } 13 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/internal/getDefaultEngine.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.internal 2 | 3 | import io.ktor.client.engine.HttpClientEngine 4 | 5 | internal expect fun getDefaultEngine(): HttpClientEngine 6 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/berries.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class Berry( 7 | val id: Int, 8 | val name: String, 9 | val growthTime: Int, 10 | val maxHarvest: Int, 11 | val naturalGiftPower: Int, 12 | val size: Int, 13 | val smoothness: Int, 14 | val soilDryness: Int, 15 | val firmness: NamedApiResource, 16 | val flavors: List, 17 | val item: NamedApiResource, 18 | val naturalGiftType: NamedApiResource, 19 | ) 20 | 21 | @Serializable data class BerryFlavorMap(val potency: Int, val flavor: NamedApiResource) 22 | 23 | @Serializable 24 | data class BerryFirmness( 25 | val id: Int, 26 | val name: String, 27 | val berries: List, 28 | val names: List, 29 | ) 30 | 31 | @Serializable 32 | data class BerryFlavor( 33 | val id: Int, 34 | val name: String, 35 | val berries: List, 36 | val contestType: NamedApiResource, 37 | val names: List, 38 | ) 39 | 40 | @Serializable data class FlavorBerryMap(val potency: Int, val berry: NamedApiResource) 41 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/contests.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class ContestType( 7 | val id: Int, 8 | val name: String, 9 | val berryFlavor: NamedApiResource, 10 | val names: List, 11 | ) 12 | 13 | @Serializable 14 | data class ContestName(val name: String, val color: String, val language: NamedApiResource) 15 | 16 | @Serializable 17 | data class ContestEffect( 18 | val id: Int, 19 | val appeal: Int, 20 | val jam: Int, 21 | val effectEntries: List, 22 | val flavorTextEntries: List, 23 | ) 24 | 25 | @Serializable 26 | data class SuperContestEffect( 27 | val id: Int, 28 | val appeal: Int, 29 | val flavorTextEntries: List, 30 | val moves: List, 31 | ) 32 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/encounters.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class EncounterMethod(val id: Int, val name: String, val order: Int, val names: List) 7 | 8 | @Serializable 9 | data class EncounterCondition( 10 | val id: Int, 11 | val name: String, 12 | val names: List, 13 | val values: List, 14 | ) 15 | 16 | @Serializable 17 | data class EncounterConditionValue( 18 | val id: Int, 19 | val name: String, 20 | val condition: NamedApiResource, 21 | val names: List, 22 | ) 23 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/evolution.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class EvolutionChain( 7 | val id: Int, 8 | val babyTriggerItem: NamedApiResource?, 9 | val chain: ChainLink, 10 | ) 11 | 12 | @Serializable 13 | data class ChainLink( 14 | val isBaby: Boolean, 15 | val species: NamedApiResource, 16 | val evolutionDetails: List, 17 | val evolvesTo: List, 18 | ) 19 | 20 | @Serializable 21 | data class EvolutionDetail( 22 | val trigger: NamedApiResource, 23 | val item: NamedApiResource? = null, 24 | val gender: Int? = null, 25 | val heldItem: NamedApiResource? = null, 26 | val knownMove: NamedApiResource? = null, 27 | val knownMoveType: NamedApiResource? = null, 28 | val location: NamedApiResource? = null, 29 | val minLevel: Int? = null, 30 | val minHappiness: Int? = null, 31 | val minBeauty: Int? = null, 32 | val minAffection: Int? = null, 33 | val partySpecies: NamedApiResource? = null, 34 | val partyType: NamedApiResource? = null, 35 | val relativePhysicalStats: Int? = null, 36 | val timeOfDay: String = "", 37 | val tradeSpecies: NamedApiResource? = null, 38 | val needsOverworldRain: Boolean = false, 39 | val turnUpsideDown: Boolean = false, 40 | ) 41 | 42 | @Serializable 43 | data class EvolutionTrigger( 44 | val id: Int, 45 | val name: String, 46 | val names: List, 47 | val pokemonSpecies: List, 48 | ) 49 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/games.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class Generation( 7 | val id: Int, 8 | val name: String, 9 | val abilities: List, 10 | val names: List, 11 | val mainRegion: NamedApiResource, 12 | val moves: List, 13 | val pokemonSpecies: List, 14 | val types: List, 15 | val versionGroups: List, 16 | ) 17 | 18 | @Serializable 19 | data class Pokedex( 20 | val id: Int, 21 | val name: String, 22 | val isMainSeries: Boolean, 23 | val descriptions: List, 24 | val names: List, 25 | val pokemonEntries: List, 26 | val region: NamedApiResource?, 27 | val versionGroups: List, 28 | ) 29 | 30 | @Serializable data class PokemonEntry(val entryNumber: Int, val pokemonSpecies: NamedApiResource) 31 | 32 | @Serializable 33 | data class Version( 34 | val id: Int, 35 | val name: String, 36 | val names: List, 37 | val versionGroup: NamedApiResource, 38 | ) 39 | 40 | @Serializable 41 | data class VersionGroup( 42 | val id: Int, 43 | val name: String, 44 | val order: Int, 45 | val generation: NamedApiResource, 46 | val moveLearnMethods: List, 47 | val pokedexes: List, 48 | val regions: List, 49 | val versions: List, 50 | ) 51 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/items.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class Item( 7 | val id: Int, 8 | val name: String, 9 | val cost: Int, 10 | val flingPower: Int?, 11 | val flingEffect: NamedApiResource?, 12 | val attributes: List, 13 | val category: NamedApiResource, 14 | val effectEntries: List, 15 | val flavorTextEntries: List, 16 | val gameIndices: List, 17 | val names: List, 18 | val heldByPokemon: List, 19 | val babyTriggerFor: ApiResource?, 20 | val sprites: ItemSprites, 21 | val machines: List, 22 | ) 23 | 24 | @Serializable data class ItemSprites(val default: String?) 25 | 26 | @Serializable 27 | data class ItemHolderPokemon( 28 | val pokemon: NamedApiResource, 29 | val versionDetails: List, 30 | ) 31 | 32 | @Serializable 33 | data class ItemHolderPokemonVersionDetail(val rarity: Int, val version: NamedApiResource) 34 | 35 | @Serializable 36 | data class ItemAttribute( 37 | val id: Int, 38 | val name: String, 39 | val items: List, 40 | val names: List, 41 | val descriptions: List, 42 | ) 43 | 44 | @Serializable 45 | data class ItemCategory( 46 | val id: Int, 47 | val name: String, 48 | val items: List, 49 | val names: List, 50 | val pocket: NamedApiResource, 51 | ) 52 | 53 | @Serializable 54 | data class ItemFlingEffect( 55 | val id: Int, 56 | val name: String, 57 | val effectEntries: List, 58 | val items: List, 59 | ) 60 | 61 | @Serializable 62 | data class ItemPocket( 63 | val id: Int, 64 | val name: String, 65 | val categories: List, 66 | val names: List, 67 | ) 68 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/locations.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class Location( 7 | val id: Int, 8 | val name: String, 9 | val region: NamedApiResource?, 10 | val names: List, 11 | val gameIndices: List, 12 | val areas: List, 13 | ) 14 | 15 | @Serializable 16 | data class LocationArea( 17 | val id: Int, 18 | val name: String, 19 | val gameIndex: Int, 20 | val encounterMethodRates: List, 21 | val location: NamedApiResource, 22 | val names: List, 23 | val pokemonEncounters: List, 24 | ) 25 | 26 | @Serializable 27 | data class EncounterMethodRate( 28 | val encounterMethod: NamedApiResource, 29 | val versionDetails: List, 30 | ) 31 | 32 | @Serializable 33 | data class EncounterMethodRateVersionDetail(val rate: Int, val version: NamedApiResource) 34 | 35 | @Serializable 36 | data class PokemonEncounter( 37 | val pokemon: NamedApiResource, 38 | val versionDetails: List, 39 | ) 40 | 41 | @Serializable 42 | data class PalParkArea( 43 | val id: Int, 44 | val name: String, 45 | val names: List, 46 | val pokemonEncounters: List, 47 | ) 48 | 49 | @Serializable 50 | data class PalParkEncounterSpecies( 51 | val baseScore: Int, 52 | val rate: Int, 53 | val pokemonSpecies: NamedApiResource, 54 | ) 55 | 56 | @Serializable 57 | data class Region( 58 | val id: Int, 59 | val name: String, 60 | val locations: List, 61 | val mainGeneration: NamedApiResource?, 62 | val names: List, 63 | val pokedexes: List, 64 | val versionGroups: List, 65 | ) 66 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/machines.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class Machine( 7 | val id: Int, 8 | val item: NamedApiResource, 9 | val move: NamedApiResource, 10 | val versionGroup: NamedApiResource, 11 | ) 12 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/moves.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class Move( 8 | val id: Int, 9 | val name: String, 10 | val accuracy: Int?, 11 | val effectChance: Int?, 12 | val pp: Int?, 13 | val priority: Int, 14 | val power: Int?, 15 | val contestCombos: ContestComboSets?, 16 | val contestType: NamedApiResource?, 17 | val contestEffect: ApiResource?, 18 | val superContestEffect: ApiResource?, 19 | val damageClass: NamedApiResource, 20 | val effectEntries: List, 21 | val effectChanges: List, 22 | val generation: NamedApiResource, 23 | val meta: MoveMetaData?, 24 | val names: List, 25 | val pastValues: List, 26 | val statChanges: List, 27 | val target: NamedApiResource, 28 | val type: NamedApiResource, 29 | val machines: List, 30 | val flavorTextEntries: List, 31 | ) 32 | 33 | @Serializable 34 | data class ContestComboSets( 35 | @SerialName("normal") val normalSet: ContestComboDetail, 36 | @SerialName("super") val superSet: ContestComboDetail, 37 | ) 38 | 39 | @Serializable 40 | data class ContestComboDetail( 41 | val useBefore: List?, 42 | val useAfter: List?, 43 | ) 44 | 45 | @Serializable 46 | data class MoveMetaData( 47 | val ailment: NamedApiResource, 48 | val category: NamedApiResource, 49 | val minHits: Int?, 50 | val maxHits: Int?, 51 | val minTurns: Int?, 52 | val maxTurns: Int?, 53 | val drain: Int, 54 | val healing: Int, 55 | val critRate: Int, 56 | val ailmentChance: Int, 57 | val flinchChance: Int, 58 | val statChance: Int, 59 | ) 60 | 61 | @Serializable data class MoveStatChange(val change: Int, val stat: NamedApiResource) 62 | 63 | @Serializable 64 | data class PastMoveStatValues( 65 | val accuracy: Int?, 66 | val effectChance: Int?, 67 | val power: Int?, 68 | val pp: Int?, 69 | val effectEntries: List, 70 | val type: NamedApiResource?, 71 | val versionGroup: NamedApiResource, 72 | ) 73 | 74 | @Serializable 75 | data class MoveAilment( 76 | val id: Int, 77 | val name: String, 78 | val moves: List, 79 | val names: List, 80 | ) 81 | 82 | @Serializable data class MoveBattleStyle(val id: Int, val name: String, val names: List) 83 | 84 | @Serializable 85 | data class MoveCategory( 86 | val id: Int, 87 | val name: String, 88 | val moves: List, 89 | val descriptions: List, 90 | ) 91 | 92 | @Serializable 93 | data class MoveDamageClass( 94 | val id: Int, 95 | val name: String, 96 | val descriptions: List, 97 | val moves: List, 98 | val names: List, 99 | ) 100 | 101 | @Serializable 102 | data class MoveLearnMethod( 103 | val id: Int, 104 | val name: String, 105 | val descriptions: List, 106 | val names: List, 107 | val versionGroups: List, 108 | ) 109 | 110 | @Serializable 111 | data class MoveTarget( 112 | val id: Int, 113 | val name: String, 114 | val descriptions: List, 115 | val moves: List, 116 | val names: List, 117 | ) 118 | 119 | @Serializable 120 | data class MoveFlavorText( 121 | val flavorText: String, 122 | val language: NamedApiResource, 123 | val versionGroup: NamedApiResource, 124 | ) 125 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/pokemon.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class Ability( 7 | val id: Int, 8 | val name: String, 9 | val isMainSeries: Boolean, 10 | val generation: NamedApiResource, 11 | val names: List, 12 | val effectEntries: List, 13 | val effectChanges: List, 14 | val flavorTextEntries: List, 15 | val pokemon: List, 16 | ) 17 | 18 | @Serializable 19 | data class AbilityEffectChange(val effectEntries: List, val versionGroup: NamedApiResource) 20 | 21 | @Serializable 22 | data class AbilityFlavorText( 23 | val flavorText: String, 24 | val language: NamedApiResource, 25 | val versionGroup: NamedApiResource, 26 | ) 27 | 28 | @Serializable 29 | data class AbilityPokemon(val isHidden: Boolean, val slot: Int, val pokemon: NamedApiResource) 30 | 31 | @Serializable 32 | data class Characteristic( 33 | val id: Int, 34 | val geneModulo: Int, 35 | val possibleValues: List, 36 | val descriptions: List, 37 | ) 38 | 39 | @Serializable 40 | data class EggGroup( 41 | val id: Int, 42 | val name: String, 43 | val names: List, 44 | val pokemonSpecies: List, 45 | ) 46 | 47 | @Serializable 48 | data class Gender( 49 | val id: Int, 50 | val name: String, 51 | val pokemonSpeciesDetails: List, 52 | val requiredForEvolution: List, 53 | ) 54 | 55 | @Serializable data class PokemonSpeciesGender(val rate: Int, val pokemonSpecies: NamedApiResource) 56 | 57 | @Serializable 58 | data class GrowthRate( 59 | val id: Int, 60 | val name: String, 61 | val formula: String, 62 | val descriptions: List, 63 | val levels: List, 64 | val pokemonSpecies: List, 65 | ) 66 | 67 | @Serializable data class GrowthRateExperienceLevel(val level: Int, val experience: Int) 68 | 69 | @Serializable 70 | data class Nature( 71 | val id: Int, 72 | val name: String, 73 | val decreasedStat: NamedApiResource?, 74 | val increasedStat: NamedApiResource?, 75 | val hatesFlavor: NamedApiResource?, 76 | val likesFlavor: NamedApiResource?, 77 | val pokeathlonStatChanges: List, 78 | val moveBattleStylePreferences: List, 79 | val names: List, 80 | ) 81 | 82 | @Serializable data class NatureStatChange(val maxChange: Int, val pokeathlonStat: NamedApiResource) 83 | 84 | @Serializable 85 | data class MoveBattleStylePreference( 86 | val lowHpPreference: Int, 87 | val highHpPreference: Int, 88 | val moveBattleStyle: NamedApiResource, 89 | ) 90 | 91 | @Serializable 92 | data class PokeathlonStat( 93 | val id: Int, 94 | val name: String, 95 | val names: List, 96 | val affectingNatures: NaturePokeathlonStatAffectSets, 97 | ) 98 | 99 | @Serializable 100 | data class NaturePokeathlonStatAffectSets( 101 | val increase: List, 102 | val decrease: List, 103 | ) 104 | 105 | @Serializable 106 | data class NaturePokeathlonStatAffect(val maxChange: Int, val nature: NamedApiResource) 107 | 108 | @Serializable 109 | data class Pokemon( 110 | val id: Int, 111 | val name: String, 112 | val baseExperience: Int, 113 | val height: Int, 114 | val isDefault: Boolean, 115 | val order: Int, 116 | val weight: Int, 117 | val species: NamedApiResource, 118 | val abilities: List, 119 | val forms: List, 120 | val gameIndices: List, 121 | val heldItems: List, 122 | val moves: List, 123 | val stats: List, 124 | val types: List, 125 | val sprites: PokemonSprites, 126 | ) 127 | 128 | @Serializable 129 | data class PokemonSprites( 130 | val backDefault: String?, 131 | val backShiny: String?, 132 | val frontDefault: String?, 133 | val frontShiny: String?, 134 | val backFemale: String?, 135 | val backShinyFemale: String?, 136 | val frontFemale: String?, 137 | val frontShinyFemale: String?, 138 | ) 139 | 140 | @Serializable 141 | data class PokemonAbility(val isHidden: Boolean, val slot: Int, val ability: NamedApiResource) 142 | 143 | @Serializable 144 | data class PokemonHeldItem( 145 | val item: NamedApiResource, 146 | val versionDetails: List, 147 | ) 148 | 149 | @Serializable data class PokemonHeldItemVersion(val version: NamedApiResource, val rarity: Int) 150 | 151 | @Serializable 152 | data class PokemonMove( 153 | val move: NamedApiResource, 154 | val versionGroupDetails: List, 155 | ) 156 | 157 | @Serializable 158 | data class PokemonMoveVersion( 159 | val moveLearnMethod: NamedApiResource, 160 | val versionGroup: NamedApiResource, 161 | val levelLearnedAt: Int, 162 | ) 163 | 164 | @Serializable 165 | data class PokemonStat(val stat: NamedApiResource, val effort: Int, val baseStat: Int) 166 | 167 | @Serializable data class PokemonType(val slot: Int, val type: NamedApiResource) 168 | 169 | @Serializable 170 | data class LocationAreaEncounter( 171 | val locationArea: NamedApiResource, 172 | val versionDetails: List, 173 | ) 174 | 175 | @Serializable 176 | data class PokemonColor( 177 | val id: Int, 178 | val name: String, 179 | val names: List, 180 | val pokemonSpecies: List, 181 | ) 182 | 183 | @Serializable 184 | data class PokemonForm( 185 | val id: Int, 186 | val name: String, 187 | val order: Int, 188 | val formOrder: Int, 189 | val isDefault: Boolean, 190 | val isBattleOnly: Boolean, 191 | val isMega: Boolean, 192 | val formName: String, 193 | val pokemon: NamedApiResource, 194 | val versionGroup: NamedApiResource, 195 | val sprites: PokemonFormSprites, 196 | val formNames: List, 197 | ) 198 | 199 | @Serializable 200 | data class PokemonFormSprites( 201 | val backDefault: String?, 202 | val backShiny: String?, 203 | val frontDefault: String?, 204 | val frontShiny: String?, 205 | ) 206 | 207 | @Serializable 208 | data class PokemonHabitat( 209 | val id: Int, 210 | val name: String, 211 | val names: List, 212 | val pokemonSpecies: List, 213 | ) 214 | 215 | @Serializable 216 | data class PokemonShape( 217 | val id: Int, 218 | val name: String, 219 | val awesomeNames: List, 220 | val names: List, 221 | val pokemonSpecies: List, 222 | ) 223 | 224 | @Serializable data class AwesomeName(val awesomeName: String, val language: NamedApiResource) 225 | 226 | @Serializable 227 | data class PokemonSpecies( 228 | val id: Int, 229 | val name: String, 230 | val order: Int, 231 | val genderRate: Int, 232 | val captureRate: Int, 233 | val baseHappiness: Int, 234 | val isBaby: Boolean, 235 | val isLegendary: Boolean? = null, 236 | val isMythical: Boolean? = null, 237 | val hatchCounter: Int, 238 | val hasGenderDifferences: Boolean, 239 | val formsSwitchable: Boolean, 240 | val growthRate: NamedApiResource, 241 | val pokedexNumbers: List, 242 | val eggGroups: List, 243 | val color: NamedApiResource, 244 | val shape: NamedApiResource, 245 | val evolvesFromSpecies: NamedApiResource?, 246 | val evolutionChain: ApiResource, 247 | val habitat: NamedApiResource?, 248 | val generation: NamedApiResource, 249 | val names: List, 250 | val palParkEncounters: List, 251 | val formDescriptions: List, 252 | val genera: List, 253 | val varieties: List, 254 | val flavorTextEntries: List, 255 | ) 256 | 257 | @Serializable 258 | data class PokemonSpeciesFlavorText( 259 | val flavorText: String, 260 | val language: NamedApiResource, 261 | val version: NamedApiResource, 262 | ) 263 | 264 | @Serializable data class Genus(val genus: String, val language: NamedApiResource) 265 | 266 | @Serializable 267 | data class PokemonSpeciesDexEntry(val entryNumber: Int, val pokedex: NamedApiResource) 268 | 269 | @Serializable 270 | data class PalParkEncounterArea(val baseScore: Int, val rate: Int, val area: NamedApiResource) 271 | 272 | @Serializable 273 | data class PokemonSpeciesVariety(val isDefault: Boolean, val pokemon: NamedApiResource) 274 | 275 | @Serializable 276 | data class Stat( 277 | val id: Int, 278 | val name: String, 279 | val gameIndex: Int, 280 | val isBattleOnly: Boolean, 281 | val affectingMoves: MoveStatAffectSets, 282 | val affectingNatures: NatureStatAffectSets, 283 | val characteristics: List, 284 | val moveDamageClass: NamedApiResource?, 285 | val names: List, 286 | ) 287 | 288 | @Serializable 289 | data class MoveStatAffectSets( 290 | val increase: List, 291 | val decrease: List, 292 | ) 293 | 294 | @Serializable data class MoveStatAffect(val change: Int, val move: NamedApiResource) 295 | 296 | @Serializable 297 | data class NatureStatAffectSets( 298 | val increase: List, 299 | val decrease: List, 300 | ) 301 | 302 | @Serializable 303 | data class Type( 304 | val id: Int, 305 | val name: String, 306 | val damageRelations: TypeRelations, 307 | val gameIndices: List, 308 | val generation: NamedApiResource, 309 | val moveDamageClass: NamedApiResource?, 310 | val names: List, 311 | val pokemon: List, 312 | val moves: List, 313 | ) 314 | 315 | @Serializable data class TypePokemon(val slot: Int, val pokemon: NamedApiResource) 316 | 317 | @Serializable 318 | data class TypeRelations( 319 | val noDamageTo: List, 320 | val halfDamageTo: List, 321 | val doubleDamageTo: List, 322 | val noDamageFrom: List, 323 | val halfDamageFrom: List, 324 | val doubleDamageFrom: List, 325 | ) 326 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/resource.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import dev.sargunv.pokekotlin.internal.DelegatingSerializer 4 | import kotlinx.serialization.KSerializer 5 | import kotlinx.serialization.Serializable 6 | 7 | private fun urlToId(url: String): Int { 8 | return "/-?[0-9]+/$".toRegex().find(url)!!.value.filter { it.isDigit() || it == '-' }.toInt() 9 | } 10 | 11 | private fun urlToCat(url: String): String { 12 | return "/[a-z\\-]+/-?[0-9]+/$".toRegex().find(url)!!.value.filter { it.isLetter() || it == '-' } 13 | } 14 | 15 | private fun resourceUrl(id: Int, category: String): String { 16 | return "/api/v2/$category/$id/" 17 | } 18 | 19 | interface ResourceSummary { 20 | val id: Int 21 | val category: String 22 | } 23 | 24 | @Serializable(with = ApiResource.Serializer::class) 25 | data class ApiResource(val url: String) : ResourceSummary { 26 | constructor(category: String, id: Int) : this(resourceUrl(id, category)) 27 | 28 | override val category by lazy { urlToCat(url) } 29 | override val id by lazy { urlToId(url) } 30 | 31 | internal class Serializer : 32 | KSerializer by DelegatingSerializer( 33 | serialName = "dev.sargunv.pokekotlin.model.ApiResource", 34 | delegate = Delegate.serializer(), 35 | fromDelegate = { ApiResource(url = it.url) }, 36 | toDelegate = { Delegate(url = it.url) }, 37 | ) { 38 | @Serializable internal data class Delegate(val url: String) 39 | } 40 | } 41 | 42 | @Serializable(with = NamedApiResource.Serializer::class) 43 | data class NamedApiResource(val name: String, val url: String) : ResourceSummary { 44 | constructor(name: String, category: String, id: Int) : this(name, resourceUrl(id, category)) 45 | 46 | override val category by lazy { urlToCat(url) } 47 | override val id by lazy { urlToId(url) } 48 | 49 | internal class Serializer : 50 | KSerializer by DelegatingSerializer( 51 | serialName = "dev.sargunv.pokekotlin.model.NamedApiResource", 52 | delegate = Delegate.serializer(), 53 | fromDelegate = { NamedApiResource(name = it.name, url = it.url) }, 54 | toDelegate = { Delegate(name = it.name, url = it.url) }, 55 | ) { 56 | @Serializable internal data class Delegate(val name: String, val url: String) 57 | } 58 | } 59 | 60 | interface ResourceSummaryList { 61 | val count: Int 62 | val next: String? 63 | val previous: String? 64 | val results: List 65 | } 66 | 67 | @Serializable 68 | data class ApiResourceList( 69 | override val count: Int, 70 | override val next: String?, 71 | override val previous: String?, 72 | override val results: List, 73 | ) : ResourceSummaryList 74 | 75 | @Serializable 76 | data class NamedApiResourceList( 77 | override val count: Int, 78 | override val next: String?, 79 | override val previous: String?, 80 | override val results: List, 81 | ) : ResourceSummaryList 82 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/dev/sargunv/pokekotlin/model/utility.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class Language( 7 | val id: Int, 8 | val name: String, 9 | val official: Boolean, 10 | val iso639: String, 11 | val iso3166: String, 12 | val names: List, 13 | ) 14 | 15 | @Serializable data class Description(val description: String, val language: NamedApiResource) 16 | 17 | @Serializable data class Effect(val effect: String, val language: NamedApiResource) 18 | 19 | @Serializable 20 | data class Encounter( 21 | val minLevel: Int, 22 | val maxLevel: Int, 23 | val conditionValues: List, 24 | val chance: Int, 25 | val method: NamedApiResource, 26 | ) 27 | 28 | @Serializable data class FlavorText(val flavorText: String, val language: NamedApiResource) 29 | 30 | @Serializable data class GenerationGameIndex(val gameIndex: Int, val generation: NamedApiResource) 31 | 32 | @Serializable 33 | data class MachineVersionDetail(val machine: ApiResource, val versionGroup: NamedApiResource) 34 | 35 | @Serializable data class Name(val name: String, val language: NamedApiResource) 36 | 37 | @Serializable 38 | data class VerboseEffect( 39 | val effect: String, 40 | val shortEffect: String, 41 | val language: NamedApiResource, 42 | ) 43 | 44 | @Serializable 45 | data class VersionEncounterDetail( 46 | val version: NamedApiResource, 47 | val maxChance: Int, 48 | val encounterDetails: List, 49 | ) 50 | 51 | @Serializable data class VersionGameIndex(val gameIndex: Int, val version: NamedApiResource) 52 | 53 | @Serializable 54 | data class VersionGroupFlavorText( 55 | val text: String, 56 | val language: NamedApiResource, 57 | val versionGroup: NamedApiResource, 58 | ) 59 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/example/example.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.example 2 | 3 | import dev.sargunv.pokekotlin.PokeApi 4 | 5 | suspend fun simple() { 6 | // -8<- [start:simple] 7 | val bulbasaur = PokeApi.getPokemon(1) 8 | println(bulbasaur) 9 | // -8<- [end:simple] 10 | } 11 | 12 | suspend fun custom() { 13 | // -8<- [start:custom] 14 | val client = PokeApi(baseUrl = "https://localhost:8080") 15 | val bulbasaur = client.getPokemon(1) 16 | println(bulbasaur) 17 | // -8<- [end:custom] 18 | } 19 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/BulkTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test 2 | 3 | import dev.sargunv.pokekotlin.model.ResourceSummary 4 | import dev.sargunv.pokekotlin.model.ResourceSummaryList 5 | import kotlin.test.Ignore 6 | import kotlin.test.Test 7 | import kotlin.test.fail 8 | import kotlinx.coroutines.test.runTest 9 | 10 | @Ignore 11 | class BulkTest { 12 | 13 | private suspend fun testCase(cat: String, id: Int, getObject: suspend (Int) -> Any) { 14 | println("$cat (id=$id)") 15 | try { 16 | getObject(id) 17 | } catch (e: Throwable) { 18 | println("ERROR: ${e::class.simpleName}: ${e.message}") 19 | fail() 20 | } 21 | } 22 | 23 | private suspend fun testEach( 24 | getList: suspend (Int, Int) -> ResourceSummaryList, 25 | getObject: suspend (Int) -> Any, 26 | ) { 27 | val list = getList(0, getList(0, 0).count).results 28 | list.forEach { testCase(list[0].category, it.id, getObject) } 29 | } 30 | 31 | @Test 32 | fun bulkBerry() = runTest { 33 | testEach({ o, l -> LocalPokeApi.getBerryList(o, l) }, { i -> LocalPokeApi.getBerry(i) }) 34 | } 35 | 36 | @Test 37 | fun bulkBerryFirmness() = runTest { 38 | testEach( 39 | { o, l -> LocalPokeApi.getBerryFirmnessList(o, l) }, 40 | { i -> LocalPokeApi.getBerryFirmness(i) }, 41 | ) 42 | } 43 | 44 | @Test 45 | fun bulkBerryFlavor() = runTest { 46 | testEach( 47 | { o, l -> LocalPokeApi.getBerryFlavorList(o, l) }, 48 | { i -> LocalPokeApi.getBerryFlavor(i) }, 49 | ) 50 | } 51 | 52 | @Test 53 | fun bulkContestType() = runTest { 54 | testEach( 55 | { o, l -> LocalPokeApi.getContestTypeList(o, l) }, 56 | { i -> LocalPokeApi.getContestType(i) }, 57 | ) 58 | } 59 | 60 | @Test 61 | fun bulkContestEffect() = runTest { 62 | testEach( 63 | { o, l -> LocalPokeApi.getContestEffectList(o, l) }, 64 | { i -> LocalPokeApi.getContestEffect(i) }, 65 | ) 66 | } 67 | 68 | @Test 69 | fun bulkSuperContestEffect() = runTest { 70 | testEach( 71 | { o, l -> LocalPokeApi.getSuperContestEffectList(o, l) }, 72 | { i -> LocalPokeApi.getSuperContestEffect(i) }, 73 | ) 74 | } 75 | 76 | @Test 77 | fun bulkEncounterMethod() = runTest { 78 | testEach( 79 | { o, l -> LocalPokeApi.getEncounterMethodList(o, l) }, 80 | { i -> LocalPokeApi.getEncounterMethod(i) }, 81 | ) 82 | } 83 | 84 | @Test 85 | fun bulkEncounterCondition() = runTest { 86 | testEach( 87 | { o, l -> LocalPokeApi.getEncounterConditionList(o, l) }, 88 | { i -> LocalPokeApi.getEncounterCondition(i) }, 89 | ) 90 | } 91 | 92 | @Test 93 | fun bulkEncounterConditionValue() = runTest { 94 | testEach( 95 | { o, l -> LocalPokeApi.getEncounterConditionValueList(o, l) }, 96 | { i -> LocalPokeApi.getEncounterConditionValue(i) }, 97 | ) 98 | } 99 | 100 | @Test 101 | fun bulkEvolutionChain() = runTest { 102 | testEach( 103 | { o, l -> LocalPokeApi.getEvolutionChainList(o, l) }, 104 | { i -> LocalPokeApi.getEvolutionChain(i) }, 105 | ) 106 | } 107 | 108 | @Test 109 | fun bulkEvolutionTrigger() = runTest { 110 | testEach( 111 | { o, l -> LocalPokeApi.getEvolutionTriggerList(o, l) }, 112 | { i -> LocalPokeApi.getEvolutionTrigger(i) }, 113 | ) 114 | } 115 | 116 | @Test 117 | fun bulkGeneration() = runTest { 118 | testEach( 119 | { o, l -> LocalPokeApi.getGenerationList(o, l) }, 120 | { i -> LocalPokeApi.getGeneration(i) }, 121 | ) 122 | } 123 | 124 | @Test 125 | fun bulkPokedex() = runTest { 126 | testEach({ o, l -> LocalPokeApi.getPokedexList(o, l) }, { i -> LocalPokeApi.getPokedex(i) }) 127 | } 128 | 129 | @Test 130 | fun bulkVersion() = runTest { 131 | testEach({ o, l -> LocalPokeApi.getVersionList(o, l) }, { i -> LocalPokeApi.getVersion(i) }) 132 | } 133 | 134 | @Test 135 | fun bulkVersionGroup() = runTest { 136 | testEach( 137 | { o, l -> LocalPokeApi.getVersionGroupList(o, l) }, 138 | { i -> LocalPokeApi.getVersionGroup(i) }, 139 | ) 140 | } 141 | 142 | @Test 143 | fun bulkItem() = runTest { 144 | testEach({ o, l -> LocalPokeApi.getItemList(o, l) }, { i -> LocalPokeApi.getItem(i) }) 145 | } 146 | 147 | @Test 148 | fun bulkItemAttribute() = runTest { 149 | testEach( 150 | { o, l -> LocalPokeApi.getItemAttributeList(o, l) }, 151 | { i -> LocalPokeApi.getItemAttribute(i) }, 152 | ) 153 | } 154 | 155 | @Test 156 | fun bulkItemCategory() = runTest { 157 | testEach( 158 | { o, l -> LocalPokeApi.getItemCategoryList(o, l) }, 159 | { i -> LocalPokeApi.getItemCategory(i) }, 160 | ) 161 | } 162 | 163 | @Test 164 | fun bulkItemFlingEffect() = runTest { 165 | testEach( 166 | { o, l -> LocalPokeApi.getItemFlingEffectList(o, l) }, 167 | { i -> LocalPokeApi.getItemFlingEffect(i) }, 168 | ) 169 | } 170 | 171 | @Test 172 | fun bulkItemPocket() = runTest { 173 | testEach( 174 | { o, l -> LocalPokeApi.getItemPocketList(o, l) }, 175 | { i -> LocalPokeApi.getItemPocket(i) }, 176 | ) 177 | } 178 | 179 | @Test 180 | fun bulkMove() = runTest { 181 | testEach({ o, l -> LocalPokeApi.getMoveList(o, l) }, { i -> LocalPokeApi.getMove(i) }) 182 | } 183 | 184 | @Test 185 | fun bulkMoveAilment() = runTest { 186 | testEach( 187 | { o, l -> LocalPokeApi.getMoveAilmentList(o, l) }, 188 | { i -> LocalPokeApi.getMoveAilment(i) }, 189 | ) 190 | } 191 | 192 | @Test 193 | fun bulkMoveBattleStyle() = runTest { 194 | testEach( 195 | { o, l -> LocalPokeApi.getMoveBattleStyleList(o, l) }, 196 | { i -> LocalPokeApi.getMoveBattleStyle(i) }, 197 | ) 198 | } 199 | 200 | @Test 201 | fun bulkMoveCategory() = runTest { 202 | testEach( 203 | { o, l -> LocalPokeApi.getMoveCategoryList(o, l) }, 204 | { i -> LocalPokeApi.getMoveCategory(i) }, 205 | ) 206 | } 207 | 208 | @Test 209 | fun bulkMoveDamageClass() = runTest { 210 | testEach( 211 | { o, l -> LocalPokeApi.getMoveDamageClassList(o, l) }, 212 | { i -> LocalPokeApi.getMoveDamageClass(i) }, 213 | ) 214 | } 215 | 216 | @Test 217 | fun bulkMoveLearnMethod() = runTest { 218 | testEach( 219 | { o, l -> LocalPokeApi.getMoveLearnMethodList(o, l) }, 220 | { i -> LocalPokeApi.getMoveLearnMethod(i) }, 221 | ) 222 | } 223 | 224 | @Test 225 | fun bulkMoveTarget() = runTest { 226 | testEach( 227 | { o, l -> LocalPokeApi.getMoveTargetList(o, l) }, 228 | { i -> LocalPokeApi.getMoveTarget(i) }, 229 | ) 230 | } 231 | 232 | @Test 233 | fun bulkLocation() = runTest { 234 | testEach({ o, l -> LocalPokeApi.getLocationList(o, l) }, { i -> LocalPokeApi.getLocation(i) }) 235 | } 236 | 237 | @Test 238 | fun bulkLocationArea() = runTest { 239 | testEach( 240 | { o, l -> LocalPokeApi.getLocationAreaList(o, l) }, 241 | { i -> LocalPokeApi.getLocationArea(i) }, 242 | ) 243 | } 244 | 245 | @Test 246 | fun bulkPalParkArea() = runTest { 247 | testEach( 248 | { o, l -> LocalPokeApi.getPalParkAreaList(o, l) }, 249 | { i -> LocalPokeApi.getPalParkArea(i) }, 250 | ) 251 | } 252 | 253 | @Test 254 | fun bulkRegion() = runTest { 255 | testEach({ o, l -> LocalPokeApi.getRegionList(o, l) }, { i -> LocalPokeApi.getRegion(i) }) 256 | } 257 | 258 | @Test 259 | fun bulkMachine() = runTest { 260 | testEach({ o, l -> LocalPokeApi.getMachineList(o, l) }, { i -> LocalPokeApi.getMachine(i) }) 261 | } 262 | 263 | @Test 264 | fun bulkAbility() = runTest { 265 | testEach({ o, l -> LocalPokeApi.getAbilityList(o, l) }, { i -> LocalPokeApi.getAbility(i) }) 266 | } 267 | 268 | @Test 269 | fun bulkCharacteristic() = runTest { 270 | testEach( 271 | { o, l -> LocalPokeApi.getCharacteristicList(o, l) }, 272 | { i -> LocalPokeApi.getCharacteristic(i) }, 273 | ) 274 | } 275 | 276 | @Test 277 | fun bulkEggGroup() = runTest { 278 | testEach({ o, l -> LocalPokeApi.getEggGroupList(o, l) }, { i -> LocalPokeApi.getEggGroup(i) }) 279 | } 280 | 281 | @Test 282 | fun bulkGender() = runTest { 283 | testEach({ o, l -> LocalPokeApi.getGenderList(o, l) }, { i -> LocalPokeApi.getGender(i) }) 284 | } 285 | 286 | @Test 287 | fun bulkGrowthRate() = runTest { 288 | testEach( 289 | { o, l -> LocalPokeApi.getGrowthRateList(o, l) }, 290 | { i -> LocalPokeApi.getGrowthRate(i) }, 291 | ) 292 | } 293 | 294 | @Test 295 | fun bulkNature() = runTest { 296 | testEach({ o, l -> LocalPokeApi.getNatureList(o, l) }, { i -> LocalPokeApi.getNature(i) }) 297 | } 298 | 299 | @Test 300 | fun bulkPokeathlonStat() = runTest { 301 | testEach( 302 | { o, l -> LocalPokeApi.getPokeathlonStatList(o, l) }, 303 | { i -> LocalPokeApi.getPokeathlonStat(i) }, 304 | ) 305 | } 306 | 307 | @Test 308 | fun bulkPokemon() = runTest { 309 | testEach({ o, l -> LocalPokeApi.getPokemonList(o, l) }, { i -> LocalPokeApi.getPokemon(i) }) 310 | } 311 | 312 | @Test 313 | fun bulkPokemonEncounters() = runTest { 314 | testEach( 315 | { o, l -> LocalPokeApi.getPokemonList(o, l) }, 316 | { i -> LocalPokeApi.getPokemonEncounterList(i) }, 317 | ) 318 | } 319 | 320 | @Test 321 | fun bulkPokemonColor() = runTest { 322 | testEach( 323 | { o, l -> LocalPokeApi.getPokemonColorList(o, l) }, 324 | { i -> LocalPokeApi.getPokemonColor(i) }, 325 | ) 326 | } 327 | 328 | @Test 329 | fun bulkPokemonForm() = runTest { 330 | testEach( 331 | { o, l -> LocalPokeApi.getPokemonFormList(o, l) }, 332 | { i -> LocalPokeApi.getPokemonForm(i) }, 333 | ) 334 | } 335 | 336 | @Test 337 | fun bulkPokemonHabitat() = runTest { 338 | testEach( 339 | { o, l -> LocalPokeApi.getPokemonHabitatList(o, l) }, 340 | { i -> LocalPokeApi.getPokemonHabitat(i) }, 341 | ) 342 | } 343 | 344 | @Test 345 | fun bulkPokemonShape() = runTest { 346 | testEach( 347 | { o, l -> LocalPokeApi.getPokemonShapeList(o, l) }, 348 | { i -> LocalPokeApi.getPokemonShape(i) }, 349 | ) 350 | } 351 | 352 | @Test 353 | fun bulkPokemonSpecies() = runTest { 354 | testEach( 355 | { o, l -> LocalPokeApi.getPokemonSpeciesList(o, l) }, 356 | { i -> LocalPokeApi.getPokemonSpecies(i) }, 357 | ) 358 | } 359 | 360 | @Test 361 | fun bulkStat() = runTest { 362 | testEach({ o, l -> LocalPokeApi.getStatList(o, l) }, { i -> LocalPokeApi.getStat(i) }) 363 | } 364 | 365 | @Test 366 | fun bulkType() = runTest { 367 | testEach({ o, l -> LocalPokeApi.getTypeList(o, l) }, { i -> LocalPokeApi.getType(i) }) 368 | } 369 | 370 | @Test 371 | fun bulkLanguage() = runTest { 372 | testEach({ o, l -> LocalPokeApi.getLanguageList(o, l) }, { i -> LocalPokeApi.getLanguage(i) }) 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/LiveTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test 2 | 3 | import dev.sargunv.pokekotlin.PokeApi 4 | import dev.sargunv.pokekotlin.PokeApiException 5 | import io.ktor.http.HttpStatusCode.Companion.NotFound 6 | import kotlin.test.Ignore 7 | import kotlin.test.Test 8 | import kotlin.test.assertEquals 9 | import kotlin.test.assertFailsWith 10 | import kotlinx.coroutines.test.runTest 11 | 12 | @Ignore 13 | class LiveTest { 14 | 15 | @Test fun resource() = runTest { assertEquals("sitrus", PokeApi.getBerry(10).name) } 16 | 17 | @Test 18 | fun list() = runTest { 19 | assertEquals(PokeApi.getMoveList(0, 50).results[25], PokeApi.getMoveList(25, 50).results[0]) 20 | } 21 | 22 | @Test 23 | fun notFound() = runTest { 24 | val e = assertFailsWith(PokeApiException.HttpStatus::class) { PokeApi.getMove(-1) } 25 | assertEquals(NotFound, e.status) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/LocalPokeApi.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test 2 | 3 | import dev.sargunv.pokekotlin.PokeApi 4 | import dev.sargunv.pokekotlin.internal.PokeApiJson 5 | import dev.sargunv.pokekotlin.model.ApiResourceList 6 | import dev.sargunv.pokekotlin.model.NamedApiResourceList 7 | import io.ktor.client.plugins.api.createClientPlugin 8 | import io.ktor.client.statement.request 9 | import io.ktor.utils.io.readBuffer 10 | import kotlin.math.min 11 | import kotlinx.serialization.ExperimentalSerializationApi 12 | import kotlinx.serialization.json.io.decodeFromSource 13 | 14 | @OptIn(ExperimentalSerializationApi::class) 15 | private val OffsetLimitPlugin = 16 | createClientPlugin("OffsetLimit") { 17 | transformResponseBody { response, content, requestedType -> 18 | val offset = response.request.url.parameters["offset"]?.toIntOrNull() ?: 0 19 | val limit = response.request.url.parameters["limit"]?.toIntOrNull() ?: 20 20 | val endIndex = offset + limit 21 | 22 | when (requestedType.type) { 23 | ApiResourceList::class -> { 24 | val fullList = PokeApiJson.decodeFromSource(content.readBuffer()) 25 | fullList.copy( 26 | results = fullList.results.subList(offset, min(endIndex, fullList.count)), 27 | previous = if (offset == 0) null else "TODO", 28 | next = if (endIndex < fullList.count) "TODO" else null, 29 | ) 30 | } 31 | NamedApiResourceList::class -> { 32 | val fullList = PokeApiJson.decodeFromSource(content.readBuffer()) 33 | fullList.copy( 34 | results = fullList.results.subList(offset, min(endIndex, fullList.count)), 35 | previous = if (offset == 0) null else "TODO", 36 | next = if (endIndex < fullList.count) "TODO" else null, 37 | ) 38 | } 39 | else -> null 40 | } 41 | } 42 | } 43 | 44 | object LocalPokeApi : 45 | PokeApi by (PokeApi(baseUrl = "http://localhost:8080/api/v2/") { install(OffsetLimitPlugin) }) 46 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/PokeApiExceptionTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test 2 | 3 | import dev.sargunv.pokekotlin.PokeApi 4 | import dev.sargunv.pokekotlin.PokeApiException 5 | import io.ktor.http.HttpStatusCode.Companion.NotFound 6 | import kotlin.test.Test 7 | import kotlin.test.assertEquals 8 | import kotlin.test.assertFailsWith 9 | import kotlinx.coroutines.test.runTest 10 | 11 | class PokeApiExceptionTest { 12 | @Test 13 | fun notFoundError() = runTest { 14 | val e = assertFailsWith(PokeApiException.HttpStatus::class) { LocalPokeApi.getMove(-1) } 15 | assertEquals(NotFound, e.status) 16 | } 17 | 18 | @Test 19 | fun badUrlError() = runTest { 20 | assertFailsWith(PokeApiException.UnknownException::class) { 21 | PokeApi("https://localhost:12345/").getBerry(10) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/BerryTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.FlavorBerryMap 4 | import dev.sargunv.pokekotlin.model.Name 5 | import dev.sargunv.pokekotlin.model.NamedApiResource 6 | import dev.sargunv.pokekotlin.test.LocalPokeApi 7 | import kotlin.test.Test 8 | import kotlin.test.assertContains 9 | import kotlin.test.assertEquals 10 | import kotlin.test.assertNotEquals 11 | import kotlinx.coroutines.test.runTest 12 | 13 | class BerryTest { 14 | 15 | @Test 16 | fun getBerry() = runTest { 17 | LocalPokeApi.getBerry(34).apply { 18 | assertEquals(34, id) 19 | assertEquals("durin", name) 20 | assertEquals(15, growthTime) 21 | assertEquals(15, maxHarvest) 22 | assertEquals(80, naturalGiftPower) 23 | assertEquals(280, size) 24 | assertEquals(35, smoothness) 25 | assertEquals(8, soilDryness) 26 | assertEquals(NamedApiResource("hard", "berry-firmness", 3), firmness) 27 | assertNotEquals(0, flavors.size) 28 | assertEquals(NamedApiResource("durin-berry", "item", 159), item) 29 | assertEquals(NamedApiResource("water", "type", 11), naturalGiftType) 30 | } 31 | } 32 | 33 | @Test 34 | fun getBerryFirmness() = runTest { 35 | LocalPokeApi.getBerryFirmness(3).apply { 36 | assertEquals(3, id) 37 | assertEquals("hard", name) 38 | assertContains(berries, NamedApiResource("rawst", "berry", 4)) 39 | assertContains(names, Name(name = "Hard", language = NamedApiResource("en", "language", 9))) 40 | } 41 | } 42 | 43 | @Test 44 | fun getBerryFlavor() = runTest { 45 | LocalPokeApi.getBerryFlavor(3).apply { 46 | assertEquals(3, id) 47 | assertEquals("sweet", name) 48 | assertEquals(NamedApiResource("cute", "contest-type", 3), contestType) 49 | assertContains( 50 | berries, 51 | FlavorBerryMap(potency = 10, berry = NamedApiResource("leppa", "berry", 6)), 52 | ) 53 | assertContains(names, Name(name = "Sweet", language = NamedApiResource("en", "language", 9))) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/ContestTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.ContestName 4 | import dev.sargunv.pokekotlin.model.Effect 5 | import dev.sargunv.pokekotlin.model.FlavorText 6 | import dev.sargunv.pokekotlin.model.NamedApiResource 7 | import dev.sargunv.pokekotlin.test.LocalPokeApi 8 | import kotlin.test.Test 9 | import kotlin.test.assertContains 10 | import kotlin.test.assertEquals 11 | import kotlinx.coroutines.test.runTest 12 | 13 | class ContestTest { 14 | 15 | @Test 16 | fun getContestType() = runTest { 17 | LocalPokeApi.getContestType(4).apply { 18 | assertEquals(4, id) 19 | assertEquals("smart", name) 20 | assertEquals(NamedApiResource("bitter", "berry-flavor", 4), berryFlavor) 21 | assertContains( 22 | names, 23 | ContestName( 24 | name = "Smart", 25 | color = "Green", 26 | language = NamedApiResource("en", "language", 9), 27 | ), 28 | ) 29 | } 30 | } 31 | 32 | @Test 33 | fun getContestEffect() = runTest { 34 | LocalPokeApi.getContestEffect(27).apply { 35 | assertEquals(27, id) 36 | assertEquals(2, appeal) 37 | assertEquals(0, jam) 38 | assertContains( 39 | effectEntries, 40 | Effect( 41 | effect = "If user appeals first this turn, earns six points instead of two.", 42 | language = NamedApiResource("en", "language", 9), 43 | ), 44 | ) 45 | assertContains( 46 | flavorTextEntries, 47 | FlavorText( 48 | flavorText = "The appeal works great if performed first.", 49 | language = NamedApiResource("en", "language", 9), 50 | ), 51 | ) 52 | } 53 | } 54 | 55 | @Test 56 | fun getSuperContestEffect() = runTest { 57 | LocalPokeApi.getSuperContestEffect(14).apply { 58 | assertEquals(14, id) 59 | assertEquals(2, appeal) 60 | assertContains( 61 | flavorTextEntries, 62 | FlavorText( 63 | flavorText = "Makes the order of contestants random in the next turn.", 64 | language = NamedApiResource("en", "language", 9), 65 | ), 66 | ) 67 | assertContains(moves, NamedApiResource("assist", "move", 274)) 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/EncounterTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.Name 4 | import dev.sargunv.pokekotlin.model.NamedApiResource 5 | import dev.sargunv.pokekotlin.test.LocalPokeApi 6 | import kotlin.test.Test 7 | import kotlin.test.assertContains 8 | import kotlin.test.assertEquals 9 | import kotlinx.coroutines.test.runTest 10 | 11 | class EncounterTest { 12 | 13 | @Test 14 | fun getEncounterMethod() = runTest { 15 | LocalPokeApi.getEncounterMethod(5).apply { 16 | assertEquals(5, id) 17 | assertEquals("surf", name) 18 | assertEquals(14, order) 19 | assertContains( 20 | names, 21 | Name(name = "Surfing", language = NamedApiResource("en", "language", 9)), 22 | ) 23 | } 24 | } 25 | 26 | @Test 27 | fun getEncounterCondition() = runTest { 28 | LocalPokeApi.getEncounterCondition(5).apply { 29 | assertEquals(5, id) 30 | assertEquals("radio", name) 31 | assertContains(values, NamedApiResource("radio-hoenn", "encounter-condition-value", 15)) 32 | assertContains(names, Name(name = "Radio", language = NamedApiResource("en", "language", 9))) 33 | } 34 | } 35 | 36 | @Test 37 | fun getEncounterConditionValue() = runTest { 38 | LocalPokeApi.getEncounterConditionValue(5).apply { 39 | assertEquals(5, id) 40 | assertEquals("time-night", name) 41 | assertEquals(NamedApiResource("time", "encounter-condition", 2), condition) 42 | assertContains( 43 | names, 44 | Name(name = "At night", language = NamedApiResource("en", "language", 9)), 45 | ) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/EvolutionTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.ChainLink 4 | import dev.sargunv.pokekotlin.model.EvolutionDetail 5 | import dev.sargunv.pokekotlin.model.Name 6 | import dev.sargunv.pokekotlin.model.NamedApiResource 7 | import dev.sargunv.pokekotlin.test.LocalPokeApi 8 | import kotlin.test.Test 9 | import kotlin.test.assertContains 10 | import kotlin.test.assertEquals 11 | import kotlin.test.assertNotNull 12 | import kotlinx.coroutines.test.runTest 13 | 14 | class EvolutionTest { 15 | 16 | @Test 17 | fun getEvolutionChain1() = runTest { 18 | LocalPokeApi.getEvolutionChain(1).apply { 19 | assertEquals(1, id) 20 | assertEquals(null, babyTriggerItem) 21 | assertEquals( 22 | ChainLink( 23 | isBaby = false, 24 | species = NamedApiResource("bulbasaur", "pokemon-species", 1), 25 | evolutionDetails = emptyList(), 26 | evolvesTo = 27 | listOf( 28 | ChainLink( 29 | isBaby = false, 30 | species = NamedApiResource("ivysaur", "pokemon-species", 2), 31 | evolutionDetails = 32 | listOf( 33 | EvolutionDetail( 34 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 35 | minLevel = 16, 36 | ) 37 | ), 38 | evolvesTo = 39 | listOf( 40 | ChainLink( 41 | isBaby = false, 42 | species = NamedApiResource("venusaur", "pokemon-species", 3), 43 | evolutionDetails = 44 | listOf( 45 | EvolutionDetail( 46 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 47 | minLevel = 32, 48 | ) 49 | ), 50 | evolvesTo = emptyList(), 51 | ) 52 | ), 53 | ) 54 | ), 55 | ), 56 | chain, 57 | ) 58 | } 59 | } 60 | 61 | @Test 62 | fun getEvolutionChain2() = runTest { 63 | LocalPokeApi.getEvolutionChain(109).apply { 64 | assertNotNull( 65 | chain.evolvesTo.find { 66 | it.evolutionDetails.contains( 67 | EvolutionDetail( 68 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 69 | heldItem = NamedApiResource("razor-claw", "item", 303), 70 | timeOfDay = "night", 71 | ) 72 | ) 73 | } 74 | ) 75 | } 76 | } 77 | 78 | @Test 79 | fun getEvolutionChain3() = runTest { 80 | LocalPokeApi.getEvolutionChain(67).apply { 81 | assertNotNull( 82 | chain.evolvesTo.find { 83 | it.evolutionDetails.contains( 84 | EvolutionDetail( 85 | trigger = NamedApiResource("use-item", "evolution-trigger", 3), 86 | item = NamedApiResource("water-stone", "item", 84), 87 | ) 88 | ) 89 | } 90 | ) 91 | } 92 | } 93 | 94 | @Test 95 | fun getEvolutionChain4() = runTest { 96 | LocalPokeApi.getEvolutionChain(67).apply { 97 | assertNotNull( 98 | chain.evolvesTo.find { 99 | it.evolutionDetails.contains( 100 | EvolutionDetail( 101 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 102 | location = NamedApiResource("eterna-forest", "location", 8), 103 | ) 104 | ) 105 | } 106 | ) 107 | } 108 | } 109 | 110 | @Test 111 | fun getEvolutionChain5() = runTest { 112 | LocalPokeApi.getEvolutionChain(67).apply { 113 | assertNotNull( 114 | chain.evolvesTo.find { 115 | it.evolutionDetails.contains( 116 | EvolutionDetail( 117 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 118 | minHappiness = 160, 119 | timeOfDay = "day", 120 | ) 121 | ) 122 | } 123 | ) 124 | } 125 | } 126 | 127 | @Test 128 | fun getEvolutionChain6() = runTest { 129 | LocalPokeApi.getEvolutionChain(67).apply { 130 | assertNotNull( 131 | chain.evolvesTo.find { 132 | it.evolutionDetails.contains( 133 | EvolutionDetail( 134 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 135 | knownMoveType = NamedApiResource("fairy", "type", 18), 136 | minAffection = 2, 137 | ) 138 | ) 139 | } 140 | ) 141 | } 142 | } 143 | 144 | @Test 145 | fun getEvolutionChain7() = runTest { 146 | LocalPokeApi.getEvolutionChain(112).apply { 147 | assertContains( 148 | chain.evolvesTo[0].evolvesTo[0].evolutionDetails, 149 | EvolutionDetail( 150 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 151 | knownMove = NamedApiResource("ancient-power", "move", 246), 152 | ), 153 | ) 154 | } 155 | } 156 | 157 | @Test 158 | fun getEvolutionChain8() = runTest { 159 | LocalPokeApi.getEvolutionChain(213).apply { 160 | assertNotNull( 161 | chain.evolvesTo.find { 162 | it.evolutionDetails.contains( 163 | EvolutionDetail( 164 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 165 | gender = 1, 166 | minLevel = 20, 167 | ) 168 | ) 169 | } 170 | ) 171 | } 172 | } 173 | 174 | @Test 175 | fun getEvolutionChain9() = runTest { 176 | LocalPokeApi.getEvolutionChain(178).apply { 177 | assertNotNull( 178 | chain.evolvesTo.find { 179 | it.evolutionDetails.contains( 180 | EvolutionDetail( 181 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 182 | minBeauty = 171, 183 | ) 184 | ) 185 | } 186 | ) 187 | } 188 | } 189 | 190 | @Test 191 | fun getEvolutionChain10() = runTest { 192 | LocalPokeApi.getEvolutionChain(346).apply { 193 | assertNotNull( 194 | chain.evolvesTo.find { 195 | it.evolutionDetails.contains( 196 | EvolutionDetail( 197 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 198 | minLevel = 32, 199 | partyType = NamedApiResource("dark", "type", 17), 200 | ) 201 | ) 202 | } 203 | ) 204 | } 205 | } 206 | 207 | @Test 208 | fun getEvolutionChain11() = runTest { 209 | LocalPokeApi.getEvolutionChain(47).apply { 210 | assertNotNull( 211 | chain.evolvesTo.find { 212 | it.evolutionDetails.contains( 213 | EvolutionDetail( 214 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 215 | minLevel = 20, 216 | relativePhysicalStats = 1, 217 | ) 218 | ) 219 | } 220 | ) 221 | } 222 | } 223 | 224 | @Test 225 | fun getEvolutionChain12() = runTest { 226 | LocalPokeApi.getEvolutionChain(362).apply { 227 | assertNotNull( 228 | chain.evolvesTo[0].evolvesTo.find { 229 | it.evolutionDetails.contains( 230 | EvolutionDetail( 231 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 232 | minLevel = 50, 233 | needsOverworldRain = true, 234 | ) 235 | ) 236 | } 237 | ) 238 | } 239 | } 240 | 241 | @Test 242 | fun getEvolutionChain13() = runTest { 243 | LocalPokeApi.getEvolutionChain(352).apply { 244 | assertNotNull( 245 | chain.evolvesTo.find { 246 | it.evolutionDetails.contains( 247 | EvolutionDetail( 248 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 249 | minLevel = 30, 250 | turnUpsideDown = true, 251 | ) 252 | ) 253 | } 254 | ) 255 | } 256 | } 257 | 258 | @Test 259 | fun getEvolutionChain14() = runTest { 260 | LocalPokeApi.getEvolutionChain(116).apply { 261 | assertNotNull( 262 | chain.evolvesTo.find { 263 | it.evolutionDetails.contains( 264 | EvolutionDetail( 265 | trigger = NamedApiResource("level-up", "evolution-trigger", 1), 266 | partySpecies = NamedApiResource("remoraid", "pokemon-species", 223), 267 | ) 268 | ) 269 | } 270 | ) 271 | } 272 | } 273 | 274 | @Test 275 | fun getEvolutionChain15() = runTest { 276 | LocalPokeApi.getEvolutionChain(312).apply { 277 | assertNotNull( 278 | chain.evolvesTo.find { 279 | it.evolutionDetails.contains( 280 | EvolutionDetail( 281 | trigger = NamedApiResource("trade", "evolution-trigger", 2), 282 | tradeSpecies = NamedApiResource("karrablast", "pokemon-species", 588), 283 | ) 284 | ) 285 | } 286 | ) 287 | } 288 | } 289 | 290 | @Test 291 | fun getEvolutionChain16() = runTest { 292 | LocalPokeApi.getEvolutionChain(72).apply { 293 | assertEquals(NamedApiResource("full-incense", "item", 293), babyTriggerItem) 294 | assertEquals(true, chain.isBaby) 295 | } 296 | } 297 | 298 | @Test 299 | fun getEvolutionTrigger() = runTest { 300 | LocalPokeApi.getEvolutionTrigger(1).apply { 301 | assertEquals(1, id) 302 | assertEquals("level-up", name) 303 | assertContains( 304 | names, 305 | Name(name = "Level up", language = NamedApiResource("en", "language", 9)), 306 | ) 307 | assertContains(pokemonSpecies, NamedApiResource("fletchinder", "pokemon-species", 662)) 308 | } 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/GameTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.Description 4 | import dev.sargunv.pokekotlin.model.Name 5 | import dev.sargunv.pokekotlin.model.NamedApiResource 6 | import dev.sargunv.pokekotlin.model.PokemonEntry 7 | import dev.sargunv.pokekotlin.test.LocalPokeApi 8 | import kotlin.test.Test 9 | import kotlin.test.assertContains 10 | import kotlin.test.assertEquals 11 | import kotlinx.coroutines.test.runTest 12 | 13 | class GameTest { 14 | 15 | @Test 16 | fun getGeneration() = runTest { 17 | LocalPokeApi.getGeneration(6).apply { 18 | assertEquals(6, id) 19 | assertEquals("generation-vi", name) 20 | assertContains(abilities, NamedApiResource("primordial-sea", "ability", 189)) 21 | assertContains( 22 | names, 23 | Name(name = "Generation VI", language = NamedApiResource("en", "language", 9)), 24 | ) 25 | assertEquals(NamedApiResource("kalos", "region", 6), mainRegion) 26 | assertContains(moves, NamedApiResource("belch", "move", 562)) 27 | assertContains(pokemonSpecies, NamedApiResource("froakie", "pokemon-species", 656)) 28 | assertContains(types, NamedApiResource("fairy", "type", 18)) 29 | assertContains(versionGroups, NamedApiResource("x-y", "version-group", 15)) 30 | } 31 | } 32 | 33 | @Test 34 | fun getPokedex() = runTest { 35 | LocalPokeApi.getPokedex(12).apply { 36 | assertEquals(12, id) 37 | assertEquals("kalos-central", name) 38 | assertEquals(true, isMainSeries) 39 | assertContains( 40 | descriptions, 41 | Description(description = "", language = NamedApiResource("en", "language", 9)), 42 | ) 43 | assertContains( 44 | names, 45 | Name(name = "Central Kalos", language = NamedApiResource("en", "language", 9)), 46 | ) 47 | assertContains( 48 | pokemonEntries, 49 | PokemonEntry( 50 | entryNumber = 150, 51 | pokemonSpecies = NamedApiResource("haxorus", "pokemon-species", 612), 52 | ), 53 | ) 54 | assertEquals(NamedApiResource("kalos", "region", 6), region) 55 | assertContains(versionGroups, NamedApiResource("x-y", "version-group", 15)) 56 | } 57 | } 58 | 59 | @Test 60 | fun getVersion() = runTest { 61 | LocalPokeApi.getVersion(9).apply { 62 | assertEquals(9, id) 63 | assertEquals("emerald", name) 64 | assertContains( 65 | names, 66 | Name(name = "Emerald", language = NamedApiResource("en", "language", 9)), 67 | ) 68 | assertEquals(NamedApiResource("emerald", "version-group", 6), versionGroup) 69 | } 70 | } 71 | 72 | @Test 73 | fun getVersionGroup() = runTest { 74 | LocalPokeApi.getVersionGroup(1).apply { 75 | assertEquals(1, id) 76 | assertEquals("red-blue", name) 77 | assertEquals(3, order) 78 | assertEquals(NamedApiResource("generation-i", "generation", 1), generation) 79 | assertContains(moveLearnMethods, NamedApiResource("machine", "move-learn-method", 4)) 80 | assertContains(pokedexes, NamedApiResource("kanto", "pokedex", 2)) 81 | assertContains(regions, NamedApiResource("kanto", "region", 1)) 82 | assertContains(versions, NamedApiResource("red", "version", 1)) 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/ItemTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.ApiResource 4 | import dev.sargunv.pokekotlin.model.Description 5 | import dev.sargunv.pokekotlin.model.Effect 6 | import dev.sargunv.pokekotlin.model.GenerationGameIndex 7 | import dev.sargunv.pokekotlin.model.ItemHolderPokemonVersionDetail 8 | import dev.sargunv.pokekotlin.model.Name 9 | import dev.sargunv.pokekotlin.model.NamedApiResource 10 | import dev.sargunv.pokekotlin.model.VerboseEffect 11 | import dev.sargunv.pokekotlin.model.VersionGroupFlavorText 12 | import dev.sargunv.pokekotlin.test.LocalPokeApi 13 | import kotlin.test.Test 14 | import kotlin.test.assertContains 15 | import kotlin.test.assertEquals 16 | import kotlin.test.assertNotEquals 17 | import kotlin.test.assertNotNull 18 | import kotlin.test.assertTrue 19 | import kotlinx.coroutines.test.runTest 20 | 21 | class ItemTest { 22 | 23 | @Test 24 | fun getItem1() = runTest { 25 | LocalPokeApi.getItem(20).apply { 26 | assertEquals(20, id) 27 | assertEquals("ice-heal", name) 28 | assertEquals(200, cost) 29 | assertEquals(30, flingPower) 30 | assertContains(attributes, NamedApiResource("holdable", "item-attribute", 5)) 31 | assertEquals(NamedApiResource("status-cures", "item-category", 30), category) 32 | assertContains( 33 | effectEntries, 34 | VerboseEffect( 35 | effect = "Used on a party Pokémon\n: Cures freezing.", 36 | shortEffect = "Cures freezing.", 37 | language = NamedApiResource("en", "language", 9), 38 | ), 39 | ) 40 | assertContains( 41 | flavorTextEntries, 42 | VersionGroupFlavorText( 43 | text = "Defrosts a frozen\nPOKéMON.", 44 | versionGroup = NamedApiResource("ruby-sapphire", "version-group", 5), 45 | language = NamedApiResource("en", "language", 9), 46 | ), 47 | ) 48 | assertContains( 49 | gameIndices, 50 | GenerationGameIndex( 51 | gameIndex = 20, 52 | generation = NamedApiResource("generation-vi", "generation", 6), 53 | ), 54 | ) 55 | assertContains( 56 | names, 57 | Name(name = "Ice Heal", language = NamedApiResource("en", "language", 9)), 58 | ) 59 | 60 | assertEquals(emptyList(), heldByPokemon) 61 | assertEquals(null, flingEffect) 62 | assertEquals(null, babyTriggerFor) 63 | assertTrue(sprites.default!!.endsWith("/sprites/items/ice-heal.png")) 64 | } 65 | } 66 | 67 | @Test 68 | fun getItem2() = runTest { 69 | LocalPokeApi.getItem(33).apply { 70 | assertNotEquals( 71 | null, 72 | heldByPokemon.find { 73 | it.pokemon == NamedApiResource("miltank", "pokemon", 241) && 74 | it.versionDetails.contains( 75 | ItemHolderPokemonVersionDetail( 76 | rarity = 100, 77 | version = NamedApiResource("y", "version", 24), 78 | ) 79 | ) 80 | }, 81 | ) 82 | } 83 | } 84 | 85 | @Test 86 | fun getItem3() = runTest { 87 | LocalPokeApi.getItem(249).apply { 88 | assertEquals(NamedApiResource("badly-poison", "item-fling-effect", 1), flingEffect) 89 | } 90 | } 91 | 92 | @Test 93 | fun getItem4() = runTest { 94 | LocalPokeApi.getItem(231).apply { 95 | assertEquals(ApiResource("evolution-chain", 90), babyTriggerFor) 96 | } 97 | } 98 | 99 | @Test fun getItem5() = runTest { LocalPokeApi.getItem(967) } 100 | 101 | @Test 102 | fun getItem6() = runTest { 103 | LocalPokeApi.getItem(305).apply { 104 | assertNotNull( 105 | machines.find { machineVersionDetail -> 106 | machineVersionDetail.machine == ApiResource("machine", 2) && 107 | machineVersionDetail.versionGroup == NamedApiResource("red-blue", "version-group", 1) 108 | } 109 | ) 110 | } 111 | } 112 | 113 | @Test 114 | fun getItemAttribute() = runTest { 115 | LocalPokeApi.getItemAttribute(3).apply { 116 | assertEquals(3, id) 117 | assertEquals("usable-overworld", name) 118 | assertContains( 119 | descriptions, 120 | Description( 121 | description = "Usable outside battle", 122 | language = NamedApiResource("en", "language", 9), 123 | ), 124 | ) 125 | assertContains(items, NamedApiResource("potion", "item", 17)) 126 | assertContains( 127 | names, 128 | Name(name = "Usable_overworld", language = NamedApiResource("en", "language", 9)), 129 | ) 130 | } 131 | } 132 | 133 | @Test 134 | fun getItemCategory() = runTest { 135 | LocalPokeApi.getItemCategory(34).apply { 136 | assertEquals(34, id) 137 | assertEquals("standard-balls", name) 138 | assertEquals(NamedApiResource("pokeballs", "item-pocket", 3), pocket) 139 | assertContains(items, NamedApiResource("poke-ball", "item", 4)) 140 | assertContains( 141 | names, 142 | Name(name = "Standard balls", language = NamedApiResource("en", "language", 9)), 143 | ) 144 | } 145 | } 146 | 147 | @Test 148 | fun getItemFlingEffect() = runTest { 149 | LocalPokeApi.getItemFlingEffect(1).apply { 150 | assertEquals(1, id) 151 | assertEquals("badly-poison", name) 152 | assertContains( 153 | effectEntries, 154 | Effect( 155 | effect = "Badly poisons the target.", 156 | language = NamedApiResource("en", "language", 9), 157 | ), 158 | ) 159 | assertContains(items, NamedApiResource("toxic-orb", "item", 249)) 160 | } 161 | } 162 | 163 | @Test 164 | fun getItemPocket() = runTest { 165 | LocalPokeApi.getItemPocket(4).apply { 166 | assertEquals(4, id) 167 | assertEquals("machines", name) 168 | assertContains(categories, NamedApiResource("all-machines", "item-category", 37)) 169 | assertContains( 170 | names, 171 | Name(name = "TMs and HMs", language = NamedApiResource("en", "language", 9)), 172 | ) 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/LocationTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.EncounterMethodRateVersionDetail 4 | import dev.sargunv.pokekotlin.model.GenerationGameIndex 5 | import dev.sargunv.pokekotlin.model.Name 6 | import dev.sargunv.pokekotlin.model.NamedApiResource 7 | import dev.sargunv.pokekotlin.model.PalParkEncounterSpecies 8 | import dev.sargunv.pokekotlin.test.LocalPokeApi 9 | import kotlin.test.Test 10 | import kotlin.test.assertContains 11 | import kotlin.test.assertEquals 12 | import kotlin.test.assertNotNull 13 | import kotlinx.coroutines.test.runTest 14 | 15 | class LocationTest { 16 | 17 | @Test 18 | fun getLocation() = runTest { 19 | LocalPokeApi.getLocation(20).apply { 20 | assertEquals(20, id) 21 | assertEquals("wayward-cave", name) 22 | assertEquals(NamedApiResource("sinnoh", "region", 4), region) 23 | assertContains( 24 | names, 25 | Name(name = "Wayward Cave", language = NamedApiResource("en", "language", 9)), 26 | ) 27 | assertContains( 28 | gameIndices, 29 | GenerationGameIndex( 30 | gameIndex = 65, 31 | generation = NamedApiResource("generation-iv", "generation", 4), 32 | ), 33 | ) 34 | assertContains(areas, NamedApiResource("wayward-cave-1f", "location-area", 113)) 35 | } 36 | } 37 | 38 | @Test 39 | fun getLocationArea() = runTest { 40 | LocalPokeApi.getLocationArea(20).apply { 41 | assertEquals(20, id) 42 | assertEquals("mt-coronet-1f-from-exterior", name) 43 | assertEquals(20, gameIndex) 44 | assertEquals(NamedApiResource("mt-coronet", "location", 10), location) 45 | assertContains( 46 | names, 47 | Name( 48 | name = "Mount Coronet (1F from exterior)", 49 | language = NamedApiResource("en", "language", 9), 50 | ), 51 | ) 52 | assertNotNull( 53 | encounterMethodRates.find { 54 | it.encounterMethod == NamedApiResource("walk", "encounter-method", 1) && 55 | EncounterMethodRateVersionDetail(10, NamedApiResource("platinum", "version", 14)) in 56 | it.versionDetails 57 | } 58 | ) 59 | assertNotNull( 60 | pokemonEncounters.find { pokemonEncounter -> 61 | pokemonEncounter.pokemon == NamedApiResource("clefairy", "pokemon", 35) && 62 | pokemonEncounter.versionDetails.find { encounterDetail -> 63 | encounterDetail.version == NamedApiResource("diamond", "version", 12) && 64 | encounterDetail.maxChance == 27 && 65 | encounterDetail.encounterDetails.find { encounter -> 66 | encounter.minLevel == 39 && 67 | encounter.maxLevel == 39 && 68 | encounter.chance == 4 && 69 | encounter.method == NamedApiResource("walk", "encounter-method", 1) && 70 | NamedApiResource("slot2-none", "encounter-condition-value", 8) in 71 | encounter.conditionValues 72 | } != null 73 | } != null 74 | } 75 | ) 76 | } 77 | } 78 | 79 | @Test 80 | fun getPalParkArea() = runTest { 81 | LocalPokeApi.getPalParkArea(2).apply { 82 | assertEquals(2, id) 83 | assertEquals("field", name) 84 | assertContains(names, Name(name = "Field", language = NamedApiResource("en", "language", 9))) 85 | assertContains( 86 | pokemonEncounters, 87 | PalParkEncounterSpecies( 88 | baseScore = 100, 89 | rate = 1, 90 | pokemonSpecies = NamedApiResource("shaymin", "pokemon-species", 492), 91 | ), 92 | ) 93 | } 94 | } 95 | 96 | @Test 97 | fun getRegion() = runTest { 98 | LocalPokeApi.getRegion(1).apply { 99 | assertEquals(1, id) 100 | assertEquals("kanto", name) 101 | assertEquals(NamedApiResource("generation-i", "generation", 1), mainGeneration) 102 | assertContains(locations, NamedApiResource("celadon-city", "location", 67)) 103 | assertContains(names, Name(name = "Kanto", language = NamedApiResource("en", "language", 9))) 104 | assertContains(pokedexes, NamedApiResource("kanto", "pokedex", 2)) 105 | assertContains(versionGroups, NamedApiResource("red-blue", "version-group", 1)) 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/MachineTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.NamedApiResource 4 | import dev.sargunv.pokekotlin.test.LocalPokeApi 5 | import kotlin.test.Test 6 | import kotlin.test.assertEquals 7 | import kotlinx.coroutines.test.runTest 8 | 9 | class MachineTest { 10 | 11 | @Test 12 | fun getMachine() = runTest { 13 | LocalPokeApi.getMachine(18).apply { 14 | assertEquals(18, id) 15 | assertEquals(NamedApiResource("tm01", "item", 305), item) 16 | assertEquals(NamedApiResource("work-up", "move", 526), move) 17 | assertEquals(NamedApiResource("sun-moon", "version-group", 17), versionGroup) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/MoveTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.* 4 | import dev.sargunv.pokekotlin.test.LocalPokeApi 5 | import kotlin.test.Test 6 | import kotlin.test.assertContains 7 | import kotlin.test.assertEquals 8 | import kotlin.test.assertNotNull 9 | import kotlinx.coroutines.test.runTest 10 | 11 | class MoveTest { 12 | 13 | @Test 14 | fun getMove1() = runTest { 15 | LocalPokeApi.getMove(34).apply { 16 | assertEquals(34, id) 17 | assertEquals("body-slam", name) 18 | assertEquals(100, accuracy) 19 | assertEquals(30, effectChance) 20 | assertEquals(15, pp) 21 | assertEquals(0, priority) 22 | assertEquals(85, power) 23 | assertEquals(null, contestCombos) 24 | assertEquals(NamedApiResource("tough", "contest-type", 5), contestType) 25 | assertEquals(ApiResource("contest-effect", 4), contestEffect) 26 | assertEquals(ApiResource("super-contest-effect", 5), superContestEffect) 27 | assertEquals(NamedApiResource("physical", "move-damage-class", 2), damageClass) 28 | assertContains( 29 | effectEntries, 30 | VerboseEffect( 31 | effect = "Inflicts regular damage. Has a 30% chance to paralyze the target.", 32 | shortEffect = "Has a 30% chance to paralyze the target.", 33 | language = NamedApiResource("en", "language", 9), 34 | ), 35 | ) 36 | assertEquals(emptyList(), effectChanges) 37 | assertEquals(NamedApiResource("generation-i", "generation", 1), generation) 38 | assertEquals( 39 | MoveMetaData( 40 | ailment = NamedApiResource("paralysis", "move-ailment", 1), 41 | category = NamedApiResource("damage+ailment", "move-category", 4), 42 | minHits = null, 43 | maxHits = null, 44 | minTurns = null, 45 | maxTurns = null, 46 | drain = 0, 47 | healing = 0, 48 | critRate = 0, 49 | ailmentChance = 30, 50 | flinchChance = 0, 51 | statChance = 0, 52 | ), 53 | meta, 54 | ) 55 | assertContains( 56 | names, 57 | Name(name = "Body Slam", language = NamedApiResource("en", "language", 9)), 58 | ) 59 | assertEquals(emptyList(), pastValues) 60 | assertEquals(emptyList(), statChanges) 61 | assertEquals(NamedApiResource("selected-pokemon", "move-target", 10), target) 62 | assertEquals(NamedApiResource("normal", "type", 1), type) 63 | assertContains( 64 | machines, 65 | MachineVersionDetail( 66 | machine = ApiResource("machine", 142), 67 | versionGroup = NamedApiResource("red-blue", "version-group", 1), 68 | ), 69 | ) 70 | assertContains( 71 | flavorTextEntries, 72 | MoveFlavorText( 73 | flavorText = "An attack that may\ncause paralysis.", 74 | language = NamedApiResource("en", "language", 9), 75 | versionGroup = NamedApiResource("gold-silver", "version-group", 3), 76 | ), 77 | ) 78 | } 79 | } 80 | 81 | @Test 82 | fun getMove2() = runTest { 83 | LocalPokeApi.getMove(400).apply { 84 | assertEquals( 85 | ContestComboSets( 86 | normalSet = ContestComboDetail(null, null), 87 | superSet = ContestComboDetail(null, listOf(NamedApiResource("focus-energy", "move", 116))), 88 | ), 89 | contestCombos, 90 | ) 91 | } 92 | } 93 | 94 | @Test 95 | fun getMove3() = runTest { 96 | LocalPokeApi.getMove(16).apply { 97 | assertNotNull( 98 | effectChanges.find { 99 | it.versionGroup == NamedApiResource("gold-silver", "version-group", 3) && 100 | Effect( 101 | effect = "Does not hit Pokémon under the effects of fly.", 102 | language = NamedApiResource("en", "language", 9), 103 | ) in it.effectEntries 104 | } 105 | ) 106 | } 107 | } 108 | 109 | @Test 110 | fun getMove4() = runTest { 111 | LocalPokeApi.getMove(14).apply { 112 | assertContains( 113 | statChanges, 114 | MoveStatChange(change = 2, stat = NamedApiResource("attack", "stat", 2)), 115 | ) 116 | } 117 | } 118 | 119 | @Test 120 | fun getMove5() = runTest { 121 | LocalPokeApi.getMove(2).apply { 122 | assertContains( 123 | pastValues, 124 | PastMoveStatValues( 125 | accuracy = null, 126 | power = null, 127 | pp = null, 128 | effectChance = null, 129 | effectEntries = emptyList(), 130 | type = NamedApiResource("normal", "type", 1), 131 | versionGroup = NamedApiResource("gold-silver", "version-group", 3), 132 | ), 133 | ) 134 | } 135 | } 136 | 137 | @Test 138 | fun getMoveAilment() = runTest { 139 | LocalPokeApi.getMoveAilment(1).apply { 140 | assertEquals(1, id) 141 | assertEquals("paralysis", name) 142 | assertContains( 143 | names, 144 | Name(name = "Paralysis", language = NamedApiResource("en", "language", 9)), 145 | ) 146 | assertContains(moves, NamedApiResource("stun-spore", "move", 78)) 147 | } 148 | } 149 | 150 | @Test 151 | fun getMoveBattleStyle() = runTest { 152 | LocalPokeApi.getMoveBattleStyle(1).apply { 153 | assertEquals(1, id) 154 | assertEquals("attack", name) 155 | assertContains(names, Name(name = "Attack", language = NamedApiResource("en", "language", 9))) 156 | } 157 | } 158 | 159 | @Test 160 | fun getMoveCategory() = runTest { 161 | LocalPokeApi.getMoveCategory(1).apply { 162 | assertEquals(1, id) 163 | assertEquals("ailment", name) 164 | assertContains( 165 | descriptions, 166 | Description( 167 | description = "No damage; inflicts status ailment", 168 | language = NamedApiResource("en", "language", 9), 169 | ), 170 | ) 171 | assertContains(moves, NamedApiResource("sing", "move", 47)) 172 | } 173 | } 174 | 175 | @Test 176 | fun getMoveDamageClass() = runTest { 177 | LocalPokeApi.getMoveDamageClass(1).apply { 178 | assertEquals(1, id) 179 | assertEquals("status", name) 180 | assertContains(names, Name(name = "status", language = NamedApiResource("en", "language", 9))) 181 | assertContains( 182 | descriptions, 183 | Description(description = "No damage", language = NamedApiResource("en", "language", 9)), 184 | ) 185 | assertContains(moves, NamedApiResource("snatch", "move", 289)) 186 | } 187 | } 188 | 189 | @Test 190 | fun getMoveLearnMethod() = runTest { 191 | LocalPokeApi.getMoveLearnMethod(10).apply { 192 | assertEquals(10, id) 193 | assertEquals("form-change", name) 194 | assertContains( 195 | names, 196 | Name(name = "Form Change", language = NamedApiResource("en", "language", 9)), 197 | ) 198 | assertContains( 199 | descriptions, 200 | Description( 201 | description = 202 | "Appears when Rotom or Cosplay Pikachu changes form. " + 203 | "Disappears if the Pokémon becomes another form and this move can only " + 204 | "be learned by form change.", 205 | language = NamedApiResource("en", "language", 9), 206 | ), 207 | ) 208 | assertContains(versionGroups, NamedApiResource("x-y", "version-group", 15)) 209 | } 210 | } 211 | 212 | @Test 213 | fun getMoveTarget() = runTest { 214 | LocalPokeApi.getMoveTarget(8).apply { 215 | assertEquals(8, id) 216 | assertEquals("random-opponent", name) 217 | assertContains( 218 | names, 219 | Name(name = "Random opponent", language = NamedApiResource("en", "language", 9)), 220 | ) 221 | assertContains( 222 | descriptions, 223 | Description( 224 | description = "One opposing Pokémon, selected at random.", 225 | language = NamedApiResource("en", "language", 9), 226 | ), 227 | ) 228 | assertContains(moves, NamedApiResource("uproar", "move", 253)) 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/PokemonTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.AbilityPokemon 4 | import dev.sargunv.pokekotlin.model.ApiResource 5 | import dev.sargunv.pokekotlin.model.AwesomeName 6 | import dev.sargunv.pokekotlin.model.Description 7 | import dev.sargunv.pokekotlin.model.Effect 8 | import dev.sargunv.pokekotlin.model.GenerationGameIndex 9 | import dev.sargunv.pokekotlin.model.Genus 10 | import dev.sargunv.pokekotlin.model.GrowthRateExperienceLevel 11 | import dev.sargunv.pokekotlin.model.MoveBattleStylePreference 12 | import dev.sargunv.pokekotlin.model.MoveStatAffect 13 | import dev.sargunv.pokekotlin.model.Name 14 | import dev.sargunv.pokekotlin.model.NamedApiResource 15 | import dev.sargunv.pokekotlin.model.NaturePokeathlonStatAffect 16 | import dev.sargunv.pokekotlin.model.NatureStatChange 17 | import dev.sargunv.pokekotlin.model.PalParkEncounterArea 18 | import dev.sargunv.pokekotlin.model.PokemonAbility 19 | import dev.sargunv.pokekotlin.model.PokemonHeldItemVersion 20 | import dev.sargunv.pokekotlin.model.PokemonMoveVersion 21 | import dev.sargunv.pokekotlin.model.PokemonSpeciesDexEntry 22 | import dev.sargunv.pokekotlin.model.PokemonSpeciesFlavorText 23 | import dev.sargunv.pokekotlin.model.PokemonSpeciesGender 24 | import dev.sargunv.pokekotlin.model.PokemonSpeciesVariety 25 | import dev.sargunv.pokekotlin.model.PokemonStat 26 | import dev.sargunv.pokekotlin.model.PokemonType 27 | import dev.sargunv.pokekotlin.model.TypePokemon 28 | import dev.sargunv.pokekotlin.model.VerboseEffect 29 | import dev.sargunv.pokekotlin.model.VersionGameIndex 30 | import dev.sargunv.pokekotlin.test.LocalPokeApi 31 | import kotlin.test.Test 32 | import kotlin.test.assertContains 33 | import kotlin.test.assertEquals 34 | import kotlin.test.assertNotNull 35 | import kotlin.test.assertTrue 36 | import kotlinx.coroutines.test.runTest 37 | 38 | class PokemonTest { 39 | 40 | @Test 41 | fun getAbility() = runTest { 42 | LocalPokeApi.getAbility(1).apply { 43 | assertEquals(1, id) 44 | assertEquals("stench", name) 45 | assertEquals(true, isMainSeries) 46 | assertEquals(NamedApiResource("generation-iii", "generation", 3), generation) 47 | assertContains(names, Name(name = "Stench", language = NamedApiResource("en", "language", 9))) 48 | assertContains( 49 | effectEntries, 50 | VerboseEffect( 51 | effect = 52 | "This Pokémon's damaging moves have a 10% chance to make the target " + 53 | "flinch with each hit if they do not already cause flinching as a " + 54 | "secondary effect.\n\nThis ability does not stack with a held item.\n\n" + 55 | "Overworld: The wild encounter rate is halved while this Pokémon is " + 56 | "first in the party.", 57 | shortEffect = "Has a 10% chance of making target Pokémon flinch with each hit.", 58 | language = NamedApiResource("en", "language", 9), 59 | ), 60 | ) 61 | assertNotNull( 62 | effectChanges.find { 63 | it.versionGroup == NamedApiResource("black-white", "version-group", 11) && 64 | it.effectEntries.contains( 65 | Effect( 66 | effect = "Has no effect in battle.", 67 | language = NamedApiResource("en", "language", 9), 68 | ) 69 | ) 70 | } 71 | ) 72 | assertContains( 73 | pokemon, 74 | AbilityPokemon( 75 | isHidden = true, 76 | slot = 3, 77 | pokemon = NamedApiResource("gloom", "pokemon", 44), 78 | ), 79 | ) 80 | } 81 | } 82 | 83 | @Test 84 | fun getCharacteristic() = runTest { 85 | LocalPokeApi.getCharacteristic(1).apply { 86 | assertEquals(1, id) 87 | assertEquals(0, geneModulo) 88 | assertEquals((0..6).map { it * 5 }.toList(), possibleValues) 89 | assertContains( 90 | descriptions, 91 | Description(description = "Loves to eat", language = NamedApiResource("en", "language", 9)), 92 | ) 93 | } 94 | } 95 | 96 | @Test 97 | fun getEggGroup() = runTest { 98 | LocalPokeApi.getEggGroup(1).apply { 99 | assertEquals(1, id) 100 | assertEquals("monster", name) 101 | assertContains( 102 | names, 103 | Name(name = "Monster", language = NamedApiResource("en", "language", 9)), 104 | ) 105 | assertContains(pokemonSpecies, NamedApiResource("avalugg", "pokemon-species", 713)) 106 | } 107 | } 108 | 109 | @Test 110 | fun getGender() = runTest { 111 | LocalPokeApi.getGender(1).apply { 112 | assertEquals(1, id) 113 | assertEquals("female", name) 114 | assertContains( 115 | pokemonSpeciesDetails, 116 | PokemonSpeciesGender( 117 | rate = 4, 118 | pokemonSpecies = NamedApiResource("noivern", "pokemon-species", 715), 119 | ), 120 | ) 121 | assertContains(requiredForEvolution, NamedApiResource("froslass", "pokemon-species", 478)) 122 | } 123 | } 124 | 125 | @Test 126 | fun getGrowthRate() = runTest { 127 | LocalPokeApi.getGrowthRate(1).apply { 128 | assertEquals(1, id) 129 | assertEquals("slow", name) 130 | assertEquals("\\frac{5x^3}{4}", formula) 131 | assertContains( 132 | descriptions, 133 | Description(description = "slow", language = NamedApiResource("en", "language", 9)), 134 | ) 135 | assertContains(levels, GrowthRateExperienceLevel(experience = 1250000, level = 100)) 136 | assertContains(pokemonSpecies, NamedApiResource("volcanion", "pokemon-species", 721)) 137 | } 138 | } 139 | 140 | @Test 141 | fun getNature() = runTest { 142 | LocalPokeApi.getNature(10).apply { 143 | assertEquals(10, id) 144 | assertEquals("hasty", name) 145 | assertEquals(NamedApiResource("speed", "stat", 6), increasedStat) 146 | assertEquals(NamedApiResource("defense", "stat", 3), decreasedStat) 147 | assertEquals(NamedApiResource("sweet", "berry-flavor", 3), likesFlavor) 148 | assertEquals(NamedApiResource("sour", "berry-flavor", 5), hatesFlavor) 149 | assertContains( 150 | pokeathlonStatChanges, 151 | NatureStatChange( 152 | pokeathlonStat = NamedApiResource("speed", "pokeathlon-stat", 1), 153 | maxChange = 2, 154 | ), 155 | ) 156 | assertContains( 157 | moveBattleStylePreferences, 158 | MoveBattleStylePreference( 159 | highHpPreference = 58, 160 | lowHpPreference = 88, 161 | moveBattleStyle = NamedApiResource("attack", "move-battle-style", 1), 162 | ), 163 | ) 164 | assertContains(names, Name(name = "Hasty", language = NamedApiResource("en", "language", 9))) 165 | } 166 | } 167 | 168 | @Test 169 | fun getPokeathlonStat() = runTest { 170 | LocalPokeApi.getPokeathlonStat(1).apply { 171 | assertEquals(1, id) 172 | assertEquals("speed", name) 173 | assertContains(names, Name(name = "Speed", language = NamedApiResource("en", "language", 9))) 174 | assertContains( 175 | affectingNatures.decrease, 176 | NaturePokeathlonStatAffect(nature = NamedApiResource("sassy", "nature", 24), maxChange = -2), 177 | ) 178 | assertContains( 179 | affectingNatures.increase, 180 | NaturePokeathlonStatAffect( 181 | nature = NamedApiResource("serious", "nature", 25), 182 | maxChange = 1, 183 | ), 184 | ) 185 | } 186 | } 187 | 188 | @Test 189 | fun getPokemon1() = runTest { 190 | LocalPokeApi.getPokemon(1).apply { 191 | assertEquals(1, id) 192 | assertEquals("bulbasaur", name) 193 | assertEquals(64, baseExperience) 194 | assertEquals(7, height) 195 | assertEquals(true, isDefault) 196 | assertEquals(1, order) 197 | assertEquals(69, weight) 198 | assertEquals(NamedApiResource("bulbasaur", "pokemon-species", 1), species) 199 | assertContains( 200 | abilities, 201 | PokemonAbility( 202 | slot = 1, 203 | isHidden = false, 204 | ability = NamedApiResource("overgrow", "ability", 65), 205 | ), 206 | ) 207 | assertContains(forms, NamedApiResource("bulbasaur", "pokemon-form", 1)) 208 | assertContains( 209 | gameIndices, 210 | VersionGameIndex(version = NamedApiResource("white-2", "version", 22), gameIndex = 1), 211 | ) 212 | assertEquals(emptyList(), heldItems) 213 | assertNotNull( 214 | moves.find { 215 | it.move == NamedApiResource("razor-wind", "move", 13) && 216 | PokemonMoveVersion( 217 | levelLearnedAt = 0, 218 | versionGroup = NamedApiResource("gold-silver", "version-group", 3), 219 | moveLearnMethod = NamedApiResource("egg", "move-learn-method", 2), 220 | ) in it.versionGroupDetails 221 | } 222 | ) 223 | assertContains( 224 | stats, 225 | PokemonStat(effort = 0, baseStat = 45, stat = NamedApiResource("hp", "stat", 1)), 226 | ) 227 | assertContains(types, PokemonType(slot = 1, type = NamedApiResource("grass", "type", 12))) 228 | } 229 | } 230 | 231 | @Test 232 | fun getPokemon2() = runTest { 233 | LocalPokeApi.getPokemon(12).apply { 234 | assertNotNull( 235 | heldItems.find { 236 | it.item == NamedApiResource("silver-powder", "item", 199) && 237 | PokemonHeldItemVersion(version = NamedApiResource("ruby", "version", 7), rarity = 5) in 238 | it.versionDetails 239 | } 240 | ) 241 | } 242 | } 243 | 244 | @Test 245 | fun getPokemon3() = runTest { 246 | LocalPokeApi.getPokemonEncounterList(12).apply { 247 | assertNotNull( 248 | find { locAreaEncounter -> 249 | locAreaEncounter.locationArea == 250 | NamedApiResource("kanto-route-2-south-towards-viridian-city", "location-area", 296) && 251 | locAreaEncounter.versionDetails.find { detail -> 252 | detail.maxChance == 10 253 | detail.version == NamedApiResource("heartgold", "version", 15) 254 | detail.encounterDetails.find { encounter -> 255 | encounter.minLevel == 8 && 256 | encounter.maxLevel == 8 && 257 | encounter.chance == 5 && 258 | encounter.method == NamedApiResource("walk", "encounter-method", 1) && 259 | NamedApiResource("time-morning", "encounter-condition-value", 3) in 260 | encounter.conditionValues 261 | } != null 262 | } != null 263 | } 264 | ) 265 | } 266 | } 267 | 268 | @Test 269 | fun getPokemon4() = runTest { 270 | LocalPokeApi.getPokemon(399).apply { 271 | sprites.apply { 272 | assertTrue(backFemale!!.endsWith("/sprites/pokemon/back/female/399.png")) 273 | assertTrue(backShinyFemale!!.endsWith("/sprites/pokemon/back/shiny/female/399.png")) 274 | assertTrue(backDefault!!.endsWith("/sprites/pokemon/back/399.png")) 275 | assertTrue(frontFemale!!.endsWith("/sprites/pokemon/female/399.png")) 276 | assertTrue(frontShinyFemale!!.endsWith("/sprites/pokemon/shiny/female/399.png")) 277 | assertTrue(backShiny!!.endsWith("/sprites/pokemon/back/shiny/399.png")) 278 | assertTrue(frontDefault!!.endsWith("/sprites/pokemon/399.png")) 279 | assertTrue(frontShiny!!.endsWith("/sprites/pokemon/shiny/399.png")) 280 | } 281 | } 282 | } 283 | 284 | @Test 285 | fun getPokemonColor() = runTest { 286 | LocalPokeApi.getPokemonColor(1).apply { 287 | assertEquals(1, id) 288 | assertEquals("black", name) 289 | assertContains(names, Name(name = "Black", language = NamedApiResource("en", "language", 9))) 290 | assertContains(pokemonSpecies, NamedApiResource("snorlax", "pokemon-species", 143)) 291 | } 292 | } 293 | 294 | @Test 295 | fun getPokemonForm() = runTest { 296 | LocalPokeApi.getPokemonForm(1).apply { 297 | assertEquals(1, id) 298 | assertEquals("bulbasaur", name) 299 | assertEquals(1, order) 300 | assertEquals(1, formOrder) 301 | assertEquals(true, isDefault) 302 | assertEquals(false, isBattleOnly) 303 | assertEquals(false, isMega) 304 | assertEquals("", formName) 305 | assertEquals(NamedApiResource("bulbasaur", "pokemon", 1), pokemon) 306 | assertEquals(NamedApiResource("red-blue", "version-group", 1), versionGroup) 307 | sprites.apply { 308 | assertTrue(frontDefault!!.endsWith("/sprites/pokemon/1.png")) 309 | assertTrue(backDefault!!.endsWith("/sprites/pokemon/back/1.png")) 310 | assertTrue(frontShiny!!.endsWith("/sprites/pokemon/shiny/1.png")) 311 | assertTrue(backShiny!!.endsWith("/sprites/pokemon/back/shiny/1.png")) 312 | } 313 | } 314 | } 315 | 316 | @Test 317 | fun getPokemonForm2() = runTest { 318 | LocalPokeApi.getPokemonForm(10266).apply { 319 | assertContains( 320 | formNames, 321 | Name(name = "Original Color", language = NamedApiResource("en", "language", 9)), 322 | ) 323 | } 324 | } 325 | 326 | @Test 327 | fun getPokemonHabitat() = runTest { 328 | LocalPokeApi.getPokemonHabitat(1).apply { 329 | assertEquals(1, id) 330 | assertEquals("cave", name) 331 | assertContains(names, Name(name = "cave", language = NamedApiResource("en", "language", 9))) 332 | assertContains(pokemonSpecies, NamedApiResource("registeel", "pokemon-species", 379)) 333 | } 334 | } 335 | 336 | @Test 337 | fun getPokemonShape() = runTest { 338 | LocalPokeApi.getPokemonShape(1).apply { 339 | assertEquals(1, id) 340 | assertEquals("ball", name) 341 | assertContains(names, Name(name = "Ball", language = NamedApiResource("en", "language", 9))) 342 | assertContains( 343 | awesomeNames, 344 | AwesomeName(awesomeName = "Pomaceous", language = NamedApiResource("en", "language", 9)), 345 | ) 346 | assertContains(pokemonSpecies, NamedApiResource("shellder", "pokemon-species", 90)) 347 | } 348 | } 349 | 350 | @Test 351 | fun getPokemonSpecies1() = runTest { 352 | LocalPokeApi.getPokemonSpecies(1).apply { 353 | assertEquals(1, id) 354 | assertEquals("bulbasaur", name) 355 | assertEquals(1, order) 356 | assertEquals(1, genderRate) 357 | assertEquals(45, captureRate) 358 | assertEquals(70, baseHappiness) 359 | assertEquals(false, isBaby) 360 | assertEquals(false, isMythical) 361 | assertEquals(false, isLegendary) 362 | assertEquals(20, hatchCounter) 363 | assertEquals(false, hasGenderDifferences) 364 | assertEquals(false, formsSwitchable) 365 | assertEquals(NamedApiResource("medium-slow", "growth-rate", 4), growthRate) 366 | assertContains( 367 | pokedexNumbers, 368 | PokemonSpeciesDexEntry( 369 | entryNumber = 80, 370 | pokedex = NamedApiResource("kalos-central", "pokedex", 12), 371 | ), 372 | ) 373 | assertContains(eggGroups, NamedApiResource("plant", "egg-group", 7)) 374 | assertEquals(NamedApiResource("green", "pokemon-color", 5), color) 375 | assertEquals(NamedApiResource("quadruped", "pokemon-shape", 8), shape) 376 | assertEquals(null, evolvesFromSpecies) 377 | assertEquals(ApiResource("evolution-chain", 1), evolutionChain) 378 | assertEquals(NamedApiResource("grassland", "pokemon-habitat", 3), habitat) 379 | assertEquals(NamedApiResource("generation-i", "generation", 1), generation) 380 | assertContains( 381 | names, 382 | Name(name = "Bulbasaur", language = NamedApiResource("en", "language", 9)), 383 | ) 384 | assertContains( 385 | palParkEncounters, 386 | PalParkEncounterArea( 387 | rate = 30, 388 | baseScore = 50, 389 | area = NamedApiResource("field", "pal-park-area", 2), 390 | ), 391 | ) 392 | assertEquals(emptyList(), formDescriptions) 393 | assertContains( 394 | genera, 395 | Genus(genus = "Seed Pokémon", language = NamedApiResource("en", "language", 9)), 396 | ) 397 | assertContains( 398 | varieties, 399 | PokemonSpeciesVariety( 400 | isDefault = true, 401 | pokemon = NamedApiResource("bulbasaur", "pokemon", 1), 402 | ), 403 | ) 404 | assertContains( 405 | flavorTextEntries, 406 | PokemonSpeciesFlavorText( 407 | flavorText = 408 | "Bulbasaur can be seen napping in bright sunlight.\n" + 409 | "There is a seed on its back. By soaking up the sun’s rays,\n" + 410 | "the seed grows progressively larger.", 411 | language = NamedApiResource("en", "language", 9), 412 | version = NamedApiResource("alpha-sapphire", "version", 26), 413 | ), 414 | ) 415 | } 416 | } 417 | 418 | @Test 419 | fun getPokemonSpecies2() = runTest { 420 | LocalPokeApi.getPokemonSpecies(2).apply { 421 | assertEquals(NamedApiResource("bulbasaur", "pokemon-species", 1), evolvesFromSpecies) 422 | } 423 | } 424 | 425 | @Test 426 | fun getPokemonSpecies3() = runTest { 427 | LocalPokeApi.getPokemonSpecies(351).apply { 428 | assertContains( 429 | formDescriptions, 430 | Description( 431 | description = 432 | "Form changes along with type to match the weather in battle, " + 433 | "due to forecast. Castform is always in its normal form outside of " + 434 | "battle, regardless of weather.", 435 | language = NamedApiResource("en", "language", 9), 436 | ), 437 | ) 438 | } 439 | } 440 | 441 | @Test 442 | fun getStat() = runTest { 443 | LocalPokeApi.getStat(2).apply { 444 | assertEquals(2, id) 445 | assertEquals("attack", name) 446 | assertEquals(2, gameIndex) 447 | assertEquals(false, isBattleOnly) 448 | assertContains( 449 | affectingMoves.increase, 450 | MoveStatAffect(change = 2, move = NamedApiResource("swords-dance", "move", 14)), 451 | ) 452 | assertContains( 453 | affectingMoves.decrease, 454 | MoveStatAffect(change = -1, move = NamedApiResource("growl", "move", 45)), 455 | ) 456 | assertContains(affectingNatures.increase, NamedApiResource("lonely", "nature", 6)) 457 | assertContains(affectingNatures.decrease, NamedApiResource("bold", "nature", 2)) 458 | assertEquals(NamedApiResource("physical", "move-damage-class", 2), moveDamageClass) 459 | assertContains(names, Name(name = "Attack", language = NamedApiResource("en", "language", 9))) 460 | } 461 | } 462 | 463 | @Test 464 | fun getType() = runTest { 465 | LocalPokeApi.getType(8).apply { 466 | assertEquals(8, id) 467 | assertEquals("ghost", name) 468 | damageRelations.apply { 469 | assertContains(halfDamageFrom, NamedApiResource("poison", "type", 4)) 470 | assertContains(noDamageFrom, NamedApiResource("normal", "type", 1)) 471 | assertContains(halfDamageTo, NamedApiResource("dark", "type", 17)) 472 | assertContains(doubleDamageFrom, NamedApiResource("ghost", "type", 8)) 473 | assertContains(noDamageTo, NamedApiResource("normal", "type", 1)) 474 | assertContains(doubleDamageTo, NamedApiResource("psychic", "type", 14)) 475 | } 476 | assertContains( 477 | gameIndices, 478 | GenerationGameIndex( 479 | gameIndex = 7, 480 | generation = NamedApiResource("generation-vi", "generation", 6), 481 | ), 482 | ) 483 | assertEquals(NamedApiResource("physical", "move-damage-class", 2), moveDamageClass) 484 | assertContains(names, Name(name = "Ghost", language = NamedApiResource("en", "language", 9))) 485 | assertContains( 486 | pokemon, 487 | TypePokemon(slot = 1, pokemon = NamedApiResource("litwick", "pokemon", 607)), 488 | ) 489 | assertContains(moves, NamedApiResource("hex", "move", 506)) 490 | } 491 | } 492 | } 493 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/ResourceListTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.ApiResource 4 | import dev.sargunv.pokekotlin.model.ApiResourceList 5 | import dev.sargunv.pokekotlin.model.NamedApiResource 6 | import dev.sargunv.pokekotlin.model.NamedApiResourceList 7 | import dev.sargunv.pokekotlin.test.LocalPokeApi 8 | import kotlin.test.Test 9 | import kotlin.test.assertContains 10 | import kotlin.test.assertEquals 11 | import kotlin.test.assertNotEquals 12 | import kotlin.test.assertTrue 13 | import kotlinx.coroutines.test.runTest 14 | 15 | class ResourceListTest { 16 | 17 | val pageSize = 50 18 | 19 | private suspend fun testCase( 20 | category: String, 21 | id: Int, 22 | name: String, 23 | call: suspend () -> NamedApiResourceList, 24 | ) { 25 | call().apply { 26 | assertTrue(results.size <= pageSize, "Actual count: ${results.size}, pageSize: $pageSize") 27 | if (pageSize >= count) { 28 | assertEquals(count, results.size) 29 | assertEquals(null, next) 30 | } else { 31 | assertEquals(pageSize, results.size) 32 | assertNotEquals(null, next) 33 | } 34 | 35 | results.forEach { 36 | assertNotEquals("", it.name) 37 | assertNotEquals("", it.category) 38 | it.id 39 | } 40 | 41 | assertContains(results, NamedApiResource(name, category, id)) 42 | } 43 | } 44 | 45 | private suspend fun testCase(category: String, id: Int, call: suspend () -> ApiResourceList) { 46 | call().apply { 47 | assertTrue(results.size <= pageSize) 48 | if (pageSize >= count) { 49 | assertEquals(count, results.size) 50 | assertEquals(null, next) 51 | } else { 52 | assertEquals(pageSize, results.size) 53 | assertNotEquals(null, next) 54 | } 55 | 56 | results.forEach { 57 | assertNotEquals("", it.category) 58 | it.id 59 | } 60 | 61 | assertContains(results, ApiResource(category, id)) 62 | } 63 | } 64 | 65 | @Test 66 | fun getBerryList() = runTest { 67 | testCase("berry", 4, "rawst") { LocalPokeApi.getBerryList(0, pageSize) } 68 | } 69 | 70 | @Test 71 | fun getBerryFirmnessList() = runTest { 72 | testCase("berry-firmness", 4, "very-hard") { LocalPokeApi.getBerryFirmnessList(0, pageSize) } 73 | } 74 | 75 | @Test 76 | fun getBerryFlavorList() = runTest { 77 | testCase("berry-flavor", 4, "bitter") { LocalPokeApi.getBerryFlavorList(0, pageSize) } 78 | } 79 | 80 | @Test 81 | fun getContestTypeList() = runTest { 82 | testCase("contest-type", 4, "smart") { LocalPokeApi.getContestTypeList(0, pageSize) } 83 | } 84 | 85 | @Test 86 | fun getContestEffectList() = runTest { 87 | testCase("contest-effect", 4) { LocalPokeApi.getContestEffectList(0, pageSize) } 88 | } 89 | 90 | @Test 91 | fun getSuperContestEffectList() = runTest { 92 | testCase("super-contest-effect", 2) { LocalPokeApi.getSuperContestEffectList(0, pageSize) } 93 | } 94 | 95 | @Test 96 | fun getEncounterMethodList() = runTest { 97 | testCase("encounter-method", 5, "surf") { LocalPokeApi.getEncounterMethodList(0, pageSize) } 98 | } 99 | 100 | @Test 101 | fun getEncounterConditionList() = runTest { 102 | testCase("encounter-condition", 3, "radar") { 103 | LocalPokeApi.getEncounterConditionList(0, pageSize) 104 | } 105 | } 106 | 107 | @Test 108 | fun getEncounterConditionValueList() = runTest { 109 | testCase("encounter-condition-value", 4, "time-day") { 110 | LocalPokeApi.getEncounterConditionValueList(0, pageSize) 111 | } 112 | } 113 | 114 | @Test 115 | fun getEvolutionChainList() = runTest { 116 | testCase("evolution-chain", 5) { LocalPokeApi.getEvolutionChainList(0, pageSize) } 117 | } 118 | 119 | @Test 120 | fun getEvolutionTriggerList() = runTest { 121 | testCase("evolution-trigger", 2, "trade") { LocalPokeApi.getEvolutionTriggerList(0, pageSize) } 122 | } 123 | 124 | @Test 125 | fun getGenerationList() = runTest { 126 | testCase("generation", 3, "generation-iii") { LocalPokeApi.getGenerationList(0, pageSize) } 127 | } 128 | 129 | @Test 130 | fun getPokedexList() = runTest { 131 | testCase("pokedex", 2, "kanto") { LocalPokeApi.getPokedexList(0, pageSize) } 132 | } 133 | 134 | @Test 135 | fun getVersionList() = runTest { 136 | testCase("version", 4, "gold") { LocalPokeApi.getVersionList(0, pageSize) } 137 | } 138 | 139 | @Test 140 | fun getVersionGroupList() = runTest { 141 | testCase("version-group", 3, "gold-silver") { LocalPokeApi.getVersionGroupList(0, pageSize) } 142 | } 143 | 144 | @Test 145 | fun getItemList() = runTest { 146 | testCase("item", 16, "cherish-ball") { LocalPokeApi.getItemList(0, pageSize) } 147 | } 148 | 149 | @Test 150 | fun getItemAttributeList() = runTest { 151 | testCase("item-attribute", 2, "consumable") { LocalPokeApi.getItemAttributeList(0, pageSize) } 152 | } 153 | 154 | @Test 155 | fun getItemCategoryList() = runTest { 156 | testCase("item-category", 2, "effort-drop") { LocalPokeApi.getItemCategoryList(0, pageSize) } 157 | } 158 | 159 | @Test 160 | fun getItemFlingEffectList() = runTest { 161 | testCase("item-fling-effect", 4, "herb-effect") { 162 | LocalPokeApi.getItemFlingEffectList(0, pageSize) 163 | } 164 | } 165 | 166 | @Test 167 | fun getItemPocketList() = runTest { 168 | testCase("item-pocket", 3, "pokeballs") { LocalPokeApi.getItemPocketList(0, pageSize) } 169 | } 170 | 171 | @Test 172 | fun getMoveList() = runTest { 173 | testCase("move", 17, "wing-attack") { LocalPokeApi.getMoveList(0, pageSize) } 174 | } 175 | 176 | @Test 177 | fun getMoveAilmentList() = runTest { 178 | testCase("move-ailment", 5, "poison") { LocalPokeApi.getMoveAilmentList(0, pageSize) } 179 | } 180 | 181 | @Test 182 | fun getMoveBattleStyleList() = runTest { 183 | testCase("move-battle-style", 2, "defense") { LocalPokeApi.getMoveBattleStyleList(0, pageSize) } 184 | } 185 | 186 | @Test 187 | fun getMoveCategoryList() = runTest { 188 | testCase("move-category", 11, "field-effect") { LocalPokeApi.getMoveCategoryList(0, pageSize) } 189 | } 190 | 191 | @Test 192 | fun getMoveDamageClassList() = runTest { 193 | testCase("move-damage-class", 2, "physical") { 194 | LocalPokeApi.getMoveDamageClassList(0, pageSize) 195 | } 196 | } 197 | 198 | @Test 199 | fun getMoveLearnMethodList() = runTest { 200 | testCase("move-learn-method", 4, "machine") { LocalPokeApi.getMoveLearnMethodList(0, pageSize) } 201 | } 202 | 203 | @Test 204 | fun getMoveTargetList() = runTest { 205 | testCase("move-target", 14, "all-pokemon") { LocalPokeApi.getMoveTargetList(0, pageSize) } 206 | } 207 | 208 | @Test 209 | fun getLocationList() = runTest { 210 | testCase("location", 31, "sinnoh-route-201") { LocalPokeApi.getLocationList(0, pageSize) } 211 | } 212 | 213 | @Test 214 | fun getLocationAreaList() = runTest { 215 | testCase("location-area", 34, "solaceon-ruins-b1f-c") { 216 | LocalPokeApi.getLocationAreaList(0, pageSize) 217 | } 218 | } 219 | 220 | @Test 221 | fun getPalParkAreaList() = runTest { 222 | testCase("pal-park-area", 3, "mountain") { LocalPokeApi.getPalParkAreaList(0, pageSize) } 223 | } 224 | 225 | @Test 226 | fun getRegionList() = runTest { 227 | testCase("region", 1, "kanto") { LocalPokeApi.getRegionList(0, pageSize) } 228 | } 229 | 230 | @Test 231 | fun getAbilityList() = runTest { 232 | testCase("ability", 5, "sturdy") { LocalPokeApi.getAbilityList(0, pageSize) } 233 | } 234 | 235 | @Test 236 | fun getCharacteristicList() = runTest { 237 | testCase("characteristic", 4) { LocalPokeApi.getCharacteristicList(0, pageSize) } 238 | } 239 | 240 | @Test 241 | fun getEggGroupList() = runTest { 242 | testCase("egg-group", 1, "monster") { LocalPokeApi.getEggGroupList(0, pageSize) } 243 | } 244 | 245 | @Test 246 | fun getGenderList() = runTest { 247 | testCase("gender", 2, "male") { LocalPokeApi.getGenderList(0, pageSize) } 248 | } 249 | 250 | @Test 251 | fun getGrowthRateList() = runTest { 252 | testCase("growth-rate", 3, "fast") { LocalPokeApi.getGrowthRateList(0, pageSize) } 253 | } 254 | 255 | @Test 256 | fun getNatureList() = runTest { 257 | testCase("nature", 5, "timid") { LocalPokeApi.getNatureList(0, pageSize) } 258 | } 259 | 260 | @Test 261 | fun getPokeathlonStatList() = runTest { 262 | testCase("pokeathlon-stat", 5, "jump") { LocalPokeApi.getPokeathlonStatList(0, pageSize) } 263 | } 264 | 265 | @Test 266 | fun getPokemonList() = runTest { 267 | testCase("pokemon", 3, "venusaur") { LocalPokeApi.getPokemonList(0, pageSize) } 268 | } 269 | 270 | @Test 271 | fun getPokemonColorList() = runTest { 272 | testCase("pokemon-color", 8, "red") { LocalPokeApi.getPokemonColorList(0, pageSize) } 273 | } 274 | 275 | @Test 276 | fun getPokemonFormList() = runTest { 277 | testCase("pokemon-form", 18, "pidgeot") { LocalPokeApi.getPokemonFormList(0, pageSize) } 278 | } 279 | 280 | @Test 281 | fun getPokemonHabitatList() = runTest { 282 | testCase("pokemon-habitat", 8, "urban") { LocalPokeApi.getPokemonHabitatList(0, pageSize) } 283 | } 284 | 285 | @Test 286 | fun getPokemonShapeList() = runTest { 287 | testCase("pokemon-shape", 13, "bug-wings") { LocalPokeApi.getPokemonShapeList(0, pageSize) } 288 | } 289 | 290 | @Test 291 | fun getPokemonSpeciesList() = runTest { 292 | testCase("pokemon-species", 20, "raticate") { LocalPokeApi.getPokemonSpeciesList(0, pageSize) } 293 | } 294 | 295 | @Test 296 | fun getPokemonStatList() = runTest { 297 | testCase("stat", 6, "speed") { LocalPokeApi.getStatList(0, pageSize) } 298 | } 299 | 300 | @Test 301 | fun getPokemonTypeList() = runTest { 302 | testCase("type", 18, "fairy") { LocalPokeApi.getTypeList(0, pageSize) } 303 | } 304 | 305 | @Test 306 | fun getLanguageList() = runTest { 307 | testCase("language", 9, "en") { LocalPokeApi.getLanguageList(0, pageSize) } 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/dev/sargunv/pokekotlin/test/model/UtilityTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test.model 2 | 3 | import dev.sargunv.pokekotlin.model.Name 4 | import dev.sargunv.pokekotlin.model.NamedApiResource 5 | import dev.sargunv.pokekotlin.test.LocalPokeApi 6 | import kotlin.test.Test 7 | import kotlin.test.assertContains 8 | import kotlin.test.assertEquals 9 | import kotlinx.coroutines.test.runTest 10 | 11 | class UtilityTest { 12 | 13 | @Test 14 | fun getLanguage() = runTest { 15 | LocalPokeApi.getLanguage(9).apply { 16 | assertEquals(9, id) 17 | assertEquals("us", iso3166) 18 | assertEquals("en", iso639) 19 | assertEquals("en", name) 20 | assertContains( 21 | names, 22 | Name(name = "English", language = NamedApiResource("en", "language", 9)), 23 | ) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/dev/sargunv/pokekotlin/internal/getDefaultEngine.js.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.internal 2 | 3 | import io.ktor.client.engine.js.Js 4 | 5 | internal actual fun getDefaultEngine() = Js.create() 6 | -------------------------------------------------------------------------------- /src/jvmMain/kotlin/dev/sargunv/pokekotlin/internal/getDefaultEngine.jvm.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.internal 2 | 3 | import io.ktor.client.engine.okhttp.OkHttp 4 | 5 | internal actual fun getDefaultEngine() = OkHttp.create() 6 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/dev/sargunv/pokekotlin/test/EndpointTest.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.test 2 | 3 | import dev.sargunv.pokekotlin.PokeApi 4 | import dev.sargunv.pokekotlin.internal.PokeApiJson 5 | import io.ktor.client.HttpClient 6 | import io.ktor.client.request.get 7 | import io.ktor.client.statement.bodyAsText 8 | import kotlin.reflect.full.declaredMemberFunctions 9 | import kotlin.test.Test 10 | import kotlin.test.assertEquals 11 | import kotlinx.coroutines.test.runTest 12 | 13 | class EndpointTest { 14 | 15 | private val httpClient = HttpClient() 16 | 17 | @Test 18 | fun checkAllEndpoints() = runTest { 19 | // call the mock API to get a list of resource endpoints 20 | val json = httpClient.get("http://localhost:8080/api/v2/").bodyAsText() 21 | 22 | // parse the expected resources using the list 23 | val expectedSingleResources = 24 | PokeApiJson.decodeFromString>(json) 25 | .keys 26 | .map { endpointName -> 27 | endpointName.split('-').joinToString(separator = "") { 28 | it.replaceFirstChar(Char::uppercase) 29 | } 30 | } 31 | .toSet() 32 | 33 | val expectedListResources = 34 | expectedSingleResources.map { it + "List" }.toSet() + "PokemonEncounterList" 35 | 36 | // use reflection to determine the actual resources in the client 37 | val actualResources = 38 | PokeApi::class 39 | .declaredMemberFunctions 40 | .map { it.name.removePrefix("get") } 41 | .groupBy { it.endsWith("List") } 42 | 43 | val actualSingleResources = actualResources.getValue(false).toSet() 44 | val actualListResources = actualResources.getValue(true).toSet() 45 | 46 | // make sure the resources in the client match the ones in the API 47 | assertEquals(expectedSingleResources.sorted(), actualSingleResources.sorted()) 48 | assertEquals(expectedListResources.sorted(), actualListResources.sorted()) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/linuxMain/kotlin/dev/sargunv/pokekotlin/internal/getDefaultEngine.linux.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.internal 2 | 3 | import io.ktor.client.engine.curl.Curl 4 | 5 | internal actual fun getDefaultEngine() = Curl.create() 6 | -------------------------------------------------------------------------------- /src/mingwMain/kotlin/dev/sargunv/pokekotlin/internal/getDefaultEngine.mingw.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.internal 2 | 3 | import io.ktor.client.engine.winhttp.WinHttp 4 | 5 | internal actual fun getDefaultEngine() = WinHttp.create() 6 | -------------------------------------------------------------------------------- /src/wasmJsMain/kotlin/dev/sargunv/pokekotlin/internal/getDefaultEngine.wasmJs.kt: -------------------------------------------------------------------------------- 1 | package dev.sargunv.pokekotlin.internal 2 | 3 | import io.ktor.client.engine.js.Js 4 | 5 | internal actual fun getDefaultEngine() = Js.create() 6 | --------------------------------------------------------------------------------