├── .github ├── CODEOWNERS ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── build.yml │ ├── publish-docs.yml │ └── release.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build.gradle.kts ├── cli ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── dev │ └── shreyaspatil │ └── composeCompilerMetricsGenerator │ └── cli │ └── Main.kt ├── core ├── build.gradle.kts ├── gradle.properties └── src │ └── main │ └── kotlin │ └── dev │ └── shreyaspatil │ └── composeCompilerMetricsGenerator │ └── core │ ├── ComposeCompilerMetricsProvider.kt │ ├── ComposeCompilerRawReportProvider.kt │ ├── ComposeMetricsContentProvider.kt │ ├── exception │ └── ParsingException.kt │ ├── file │ └── ReportAndMetricsFileFinder.kt │ ├── mapper │ └── ConditionMapper.kt │ ├── model │ ├── Condition.kt │ ├── DetailedStatistics.kt │ ├── RawContent.kt │ ├── classes │ │ ├── ClassDetail.kt │ │ └── ClassesReport.kt │ └── composables │ │ ├── ComposableDetail.kt │ │ └── ComposablesReport.kt │ ├── parser │ ├── ClassReportParser.kt │ ├── ComposableReportParser.kt │ └── Parser.kt │ └── utils │ ├── CamelCaseToWord.kt │ └── FileUtils.kt ├── docs ├── images │ ├── brief-stats.png │ ├── class-report.png │ ├── composable-report.png │ ├── detailed-stats.png │ ├── gradle-plugin-example-android.png │ └── gradle-plugin-example-kmp.png ├── index.md └── use │ ├── using-cli.md │ ├── using-gradle-plugin.md │ └── using-utility-as-library.md ├── gradle-plugin ├── build.gradle.kts ├── gradle.properties └── src │ └── main │ └── kotlin │ └── dev │ └── shreyaspatil │ └── composeCompilerMetricsGenerator │ └── plugin │ ├── ComposeCompilerReportExtension.kt │ ├── ReportGenPlugin.kt │ ├── multiplatform │ ├── android │ │ └── configure.kt │ ├── configure.kt │ └── jvm │ │ └── configure.kt │ └── task │ └── ComposeCompilerReportGenerateTask.kt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── mkdocs.yml ├── package-lock.json ├── package.json ├── report-generator ├── build.gradle.kts ├── gradle.properties └── src │ └── main │ └── kotlin │ └── dev │ └── shreyaspatil │ └── composeCompilerMetricsGenerator │ └── generator │ ├── HtmlReportGenerator.kt │ ├── ReportSpec.kt │ ├── content │ ├── BriefStatistics.kt │ ├── ClassReport.kt │ ├── ComposableReport.kt │ ├── DetailedStatistics.kt │ ├── ErrorReports.kt │ ├── Footer.kt │ ├── MainContent.kt │ └── common │ │ ├── CollapsibleContent.kt │ │ ├── EmptyContent.kt │ │ ├── IconText.kt │ │ ├── Icons.kt │ │ └── Svg.kt │ ├── script │ └── CollapsibleScript.kt │ ├── style │ ├── Colors.kt │ ├── CssStyle.kt │ ├── Fonts.kt │ └── PageStyle.kt │ └── utils │ ├── ListExt.kt │ └── StringExt.kt ├── settings.gradle.kts └── spotless └── copyright.kt /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @PatilShreyas 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: PatilShreyas 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://www.paypal.me/PatilShreyas99/'] 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gradle" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | 13 | commit-message: 14 | prefix: "[Update]" 15 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | build: 6 | name: Build 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout branch 11 | uses: actions/checkout@v3.5.3 12 | 13 | - name: Set up JDK 17 14 | uses: actions/setup-java@v3 15 | with: 16 | java-version: 17 17 | distribution: temurin 18 | cache: gradle 19 | 20 | - name: Grant Permission to Execute 21 | run: chmod +x gradlew 22 | 23 | - name: 🏗 Build with Gradle 🛠️ 24 | run: ./gradlew build --stacktrace 25 | -------------------------------------------------------------------------------- /.github/workflows/publish-docs.yml: -------------------------------------------------------------------------------- 1 | name: Publish docs 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | workflow_dispatch: 8 | 9 | jobs: 10 | deploy_docs: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout branch 15 | uses: actions/checkout@v3.5.3 16 | 17 | - name: Set up JDK 17 18 | uses: actions/setup-java@v3 19 | with: 20 | java-version: 17 21 | distribution: temurin 22 | cache: gradle 23 | 24 | - name: Setup Python 25 | uses: actions/setup-python@v2 26 | with: 27 | python-version: '3.x' 28 | 29 | - name: Install dependencies 30 | run: | 31 | python3 -m pip install --upgrade pip 32 | python3 -m pip install mkdocs 33 | python3 -m pip install mkdocs-material 34 | 35 | - name: Build site 36 | run: mkdocs build 37 | 38 | - name: Deploy 39 | uses: peaceiris/actions-gh-pages@v3 40 | with: 41 | github_token: ${{ secrets.GITHUB_TOKEN }} 42 | publish_dir: ./site -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | tags: 5 | - 'v*' 6 | 7 | jobs: 8 | build: 9 | name: Build 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout branch 14 | uses: actions/checkout@v3.5.3 15 | 16 | - name: Set up JDK 17 17 | uses: actions/setup-java@v3 18 | with: 19 | java-version: 17 20 | distribution: temurin 21 | cache: gradle 22 | 23 | - name: Set up NPM 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: 14 27 | registry-url: 'https://registry.npmjs.org' 28 | 29 | - name: Grant Permission to Execute 30 | run: chmod +x gradlew 31 | 32 | - name: 🏗 Build with Gradle 🛠️ 33 | run: ./gradlew build --stacktrace 34 | 35 | - name: Publish Library on Maven Central 36 | run: ./gradlew publishAndReleaseToMavenCentral --no-configuration-cache 37 | env: 38 | ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY }} 39 | ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_PASSWORD }} 40 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} 41 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 42 | 43 | - name: Publish Gradle Plugin 44 | run: | 45 | echo "Publishing Gradle Plugin🚀" 46 | ./gradlew :gradle-plugin:publishPlugins 47 | env: 48 | GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PLUGIN_PORTAL_KEY }} 49 | GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PLUGIN_PORTAL_SECRET }} 50 | 51 | - name: Publish CLI Application 🚀 52 | run: | 53 | npm ci 54 | npm install 55 | npm install jdeploy -g 56 | jdeploy publish 57 | env: 58 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 59 | 60 | - name: Create Release ✅ 61 | id: create_release 62 | uses: actions/create-release@v1 63 | env: 64 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 65 | with: 66 | tag_name: ${{ github.ref }} 67 | release_name: ${{ github.ref }} 68 | draft: true 69 | prerelease: false 70 | 71 | - name: Upload CLI JAR ⬆️ 72 | uses: actions/upload-release-asset@v1 73 | env: 74 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 75 | with: 76 | upload_url: ${{ steps.create_release.outputs.upload_url }} 77 | asset_path: cli/build/libs/cli.jar 78 | asset_name: composeReport2Html.jar 79 | asset_content_type: application/jar 80 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # For Gradle 2 | 3 | *.iml 4 | .gradle 5 | /local.properties 6 | /.idea/ 7 | .DS_Store 8 | /captures 9 | .externalNativeBuild 10 | .cxx 11 | */build 12 | build/ 13 | 14 | # For NPM 15 | # Logs 16 | logs 17 | *.log 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | lerna-debug.log* 22 | .pnpm-debug.log* 23 | 24 | # Diagnostic reports (https://nodejs.org/api/report.html) 25 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 26 | 27 | # Runtime data 28 | pids 29 | *.pid 30 | *.seed 31 | *.pid.lock 32 | 33 | # Directory for instrumented libs generated by jscoverage/JSCover 34 | lib-cov 35 | 36 | # Coverage directory used by tools like istanbul 37 | coverage 38 | *.lcov 39 | 40 | # nyc test coverage 41 | .nyc_output 42 | 43 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 44 | .grunt 45 | 46 | # Bower dependency directory (https://bower.io/) 47 | bower_components 48 | 49 | # node-waf configuration 50 | .lock-wscript 51 | 52 | # Compiled binary addons (https://nodejs.org/api/addons.html) 53 | build/Release 54 | 55 | # Dependency directories 56 | node_modules/ 57 | jspm_packages/ 58 | 59 | # Snowpack dependency directory (https://snowpack.dev/) 60 | web_modules/ 61 | 62 | # TypeScript cache 63 | *.tsbuildinfo 64 | 65 | # Optional npm cache directory 66 | .npm 67 | 68 | # Optional eslint cache 69 | .eslintcache 70 | 71 | # Optional stylelint cache 72 | .stylelintcache 73 | 74 | # Microbundle cache 75 | .rpt2_cache/ 76 | .rts2_cache_cjs/ 77 | .rts2_cache_es/ 78 | .rts2_cache_umd/ 79 | 80 | # Optional REPL history 81 | .node_repl_history 82 | 83 | # Output of 'npm pack' 84 | *.tgz 85 | 86 | # Yarn Integrity file 87 | .yarn-integrity 88 | 89 | # dotenv environment variable files 90 | .env 91 | .env.development.local 92 | .env.test.local 93 | .env.production.local 94 | .env.local 95 | 96 | # parcel-bundler cache (https://parceljs.org/) 97 | .cache 98 | .parcel-cache 99 | 100 | # Next.js build output 101 | .next 102 | out 103 | 104 | # Nuxt.js build / generate output 105 | .nuxt 106 | dist 107 | 108 | # Gatsby files 109 | .cache/ 110 | # Comment in the public line in if your project uses Gatsby and not Next.js 111 | # https://nextjs.org/blog/next-9-1#public-directory-support 112 | # public 113 | 114 | # vuepress build output 115 | .vuepress/dist 116 | 117 | # vuepress v2.x temp and cache directory 118 | .temp 119 | .cache 120 | 121 | # Docusaurus cache and generated files 122 | .docusaurus 123 | 124 | # Serverless directories 125 | .serverless/ 126 | 127 | # FuseBox cache 128 | .fusebox/ 129 | 130 | # DynamoDB Local files 131 | .dynamodb/ 132 | 133 | # TernJS port file 134 | .tern-port 135 | 136 | # Stores VSCode versions used for testing VSCode extensions 137 | .vscode-test 138 | 139 | # yarn v2 140 | .yarn/cache 141 | .yarn/unplugged 142 | .yarn/build-state.yml 143 | .yarn/install-state.gz 144 | .pnp.* -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at shreyaspatilg@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Feeling Awesome! Thanks for thinking about this. 2 | 3 | You can contribute us by filing issues, bugs and PRs. You can also take a look at active issues and fix them. 4 | 5 | If you want to discuss on something then feel free to present your opinions, views or any other relevant comment on [discussions](https://github.com/PatilShreyas/compose-report-to-html/discussions). 6 | 7 | ### Code contribution 8 | 9 | - Open issue regarding proposed change. 10 | - If your proposed change is approved, Fork this repo and do changes. 11 | - Open PR against latest *development* branch. Add nice description in PR. 12 | - You're done! 13 | 14 | ### Code contribution checklist 15 | 16 | - New code addition/deletion should not break existing flow of a system. 17 | - All tests should be passed. 18 | - Verify `./gradlew build` is passing before raising a PR. 19 | - Reformat code with Spotless `./gradlew spotlessApply` before raising a PR. 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Shreyas Patil 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Compose Compiler Reports to HTML Generator 2 | 3 | A utility to convert Jetpack Compose compiler metrics and reports to beautified 😍 HTML page. 4 | _Made with ❤️ for Android Developers and Composers_ 5 | 6 | [![Build](https://github.com/PatilShreyas/compose-report-to-html/actions/workflows/build.yml/badge.svg)](https://github.com/PatilShreyas/compose-report-to-html/actions/workflows/build.yml) 7 | [![Release](https://github.com/PatilShreyas/compose-report-to-html/actions/workflows/release.yml/badge.svg)](https://github.com/PatilShreyas/compose-report-to-html/actions/workflows/release.yml) 8 | 9 | | Distribution | Usage Guide | Install | 10 | |----------------------|---------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 11 | | **Gradle Plugin** | [Read](https://patilshreyas.github.io/compose-report-to-html/use/using-gradle-plugin/) | [![Gradle Plugin](https://img.shields.io/gradle-plugin-portal/v/dev.shreyaspatil.compose-compiler-report-generator?color=%233cafc6&label=Plugin&logo=gradle&style=flat-square)](https://plugins.gradle.org/plugin/dev.shreyaspatil.compose-compiler-report-generator) | 12 | | **CLI** | [Read](https://patilshreyas.github.io/compose-report-to-html/use/using-cli/) | [![NPM Package](https://img.shields.io/npm/v/compose-report2html?label=npm&logo=npm&style=flat-square)](https://www.npmjs.com/package/compose-report2html)
[![Download JAR](https://img.shields.io/github/v/release/patilshreyas/compose-report-to-html?label=JAR&logo=java&style=flat-square)](https://github.com/patilshreyas/compose-report-to-html/releases/latest/download/composeReport2Html.jar) | 13 | | **Library Artifact** | [Read](https://patilshreyas.github.io/compose-report-to-html/use/using-utility-as-library/) | [![Install](https://img.shields.io/maven-central/v/dev.shreyaspatil.compose-compiler-report-generator/core?label=Maven%20Central&logo=android&style=flat-square)](https://search.maven.org/search?q=g:dev.shreyaspatil.compose-compiler-report-generator) | 14 | 15 | **▶️ [Read _the documentation_](https://patilshreyas.github.io/compose-report-to-html/) for more information and guide to 16 | use 17 | this utility** 18 | 19 | ## 🙋‍♂️ Contribute 20 | 21 | Read [contribution guidelines](CONTRIBUTING.md) for more information regarding contribution. 22 | 23 | ## 💬 Discuss? 24 | 25 | Have any questions, doubts or want to present your opinions, views? You're always welcome. You 26 | can [start discussions](https://github.com/PatilShreyas/compose-report-to-html/discussions). 27 | 28 | ## License 29 | 30 | ``` 31 | MIT License 32 | 33 | Copyright (c) 2022 Shreyas Patil 34 | 35 | Permission is hereby granted, free of charge, to any person obtaining a copy 36 | of this software and associated documentation files (the "Software"), to deal 37 | in the Software without restriction, including without limitation the rights 38 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 39 | copies of the Software, and to permit persons to whom the Software is 40 | furnished to do so, subject to the following conditions: 41 | 42 | The above copyright notice and this permission notice shall be included in all 43 | copies or substantial portions of the Software. 44 | 45 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 48 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 49 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 50 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 51 | SOFTWARE. 52 | ``` 53 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | val VERSION_NAME: String by project 4 | val GROUP: String by project 5 | 6 | plugins { 7 | kotlin("jvm") version libs.versions.kotlin.get() 8 | alias(libs.plugins.spotless) 9 | alias(libs.plugins.mavenPublish) apply false 10 | } 11 | 12 | group = GROUP 13 | version = VERSION_NAME 14 | 15 | tasks.withType { 16 | kotlinOptions.jvmTarget = "1.8" 17 | } 18 | 19 | subprojects { 20 | apply(plugin = "com.diffplug.spotless") 21 | configure { 22 | kotlin { 23 | target("**/*.kt") 24 | targetExclude("$buildDir/**/*.kt") 25 | targetExclude("bin/**/*.kt") 26 | 27 | ktlint() 28 | licenseHeaderFile(rootProject.file("spotless/copyright.kt")) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cli/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") 3 | application 4 | } 5 | val mainCliClassName = "dev.shreyaspatil.composeCompilerMetricsGenerator.cli.MainKt" 6 | application { 7 | mainClass.set(mainCliClassName) 8 | } 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | dependencies { 15 | implementation(project(":core")) 16 | implementation(project(":report-generator")) 17 | 18 | implementation(kotlin("stdlib")) 19 | implementation(libs.kotlinx.cli) 20 | } 21 | 22 | tasks.withType { 23 | manifest { 24 | attributes["Main-Class"] = mainCliClassName 25 | } 26 | val dependencies = 27 | configurations 28 | .runtimeClasspath 29 | .get() 30 | .map(::zipTree) 31 | from(dependencies) 32 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE 33 | } 34 | -------------------------------------------------------------------------------- /cli/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/cli/Main.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.cli 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.ComposeCompilerMetricsProvider 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.ComposeCompilerRawReportProvider 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.utils.ensureDirectory 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.utils.ensureFileExists 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.HtmlReportGenerator 31 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.ReportOptions 32 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.ReportSpec 33 | import kotlinx.cli.ArgParser 34 | import kotlinx.cli.ArgType 35 | import kotlinx.cli.default 36 | import kotlinx.cli.required 37 | import java.io.File 38 | import java.nio.file.Path 39 | import java.nio.file.Paths 40 | 41 | /** 42 | * Entry point of a CLI application 43 | */ 44 | fun main(args: Array) { 45 | val arguments = CliArguments(args, Paths.get("").toAbsolutePath()) 46 | 47 | val reportSpec = 48 | ReportSpec( 49 | name = arguments.applicationName, 50 | options = 51 | ReportOptions( 52 | includeStableComposables = arguments.includeStableComposables, 53 | includeStableClasses = arguments.includeStableClasses, 54 | includeClasses = arguments.includeClasses, 55 | showOnlyUnstableComposables = arguments.showOnlyUnstableComposables, 56 | ), 57 | ) 58 | val rawReportProvider = arguments.getRawReportProvider() 59 | 60 | printHeader("Generating Composable HTML Report") 61 | 62 | val html = 63 | HtmlReportGenerator( 64 | reportSpec = reportSpec, 65 | metricsProvider = ComposeCompilerMetricsProvider(rawReportProvider), 66 | ).generateHtml() 67 | 68 | printHeader("Saving Composable Report") 69 | val reportPath = saveReportAsHtml(html, arguments.outputDirectory) 70 | 71 | println("Report for '${reportSpec.name}' is successfully generated at '$reportPath'") 72 | println("DONE!") 73 | } 74 | 75 | /** 76 | * Saves a file with [htmlContent] having name as 'index.html' at specified [outputDirectory] 77 | */ 78 | fun saveReportAsHtml( 79 | htmlContent: String, 80 | outputDirectory: String, 81 | ): String { 82 | val directory = File(Paths.get(outputDirectory).toAbsolutePath().toString()) 83 | 84 | if (!directory.exists()) { 85 | if (!directory.mkdirs()) { 86 | // When it fails to create a directory, create a temporary file so that developers can atleast access it. 87 | val file = File.createTempFile("index", ".html") 88 | file.writeText(htmlContent) 89 | error("Failed to create directory '$outputDirectory'. Have created temporary file at '${file.canonicalPath}'") 90 | } 91 | } 92 | val file = File("${directory.absolutePath}/index.html") 93 | file.writeText(htmlContent) 94 | 95 | return file.canonicalPath 96 | } 97 | 98 | /** 99 | * Parses and validates CLI arguments 100 | */ 101 | class CliArguments( 102 | args: Array, 103 | private val path: Path, 104 | ) { 105 | private val parser = ArgParser("Compose Compiler Report to HTML Generator ~ ${Constants.VERSION}") 106 | 107 | val applicationName by parser 108 | .option( 109 | ArgType.String, 110 | shortName = "app", 111 | description = "Application name (To be displayed in the report)", 112 | ).required() 113 | 114 | val inputDirectory by parser.option( 115 | ArgType.String, 116 | shortName = "i", 117 | description = "Input directory where composable report and metrics are available", 118 | ) 119 | 120 | val overallStatsFile by parser.option( 121 | ArgType.String, 122 | shortName = "overallStatsReport", 123 | description = "Overall Statistics Metrics JSON files (separated by commas)", 124 | ) 125 | 126 | val detailedStatsFile by parser.option( 127 | ArgType.String, 128 | shortName = "detailedStatsMetrics", 129 | description = "Detailed Statistics Metrics CSV files (separated by commas)", 130 | ) 131 | 132 | val composableMetricsFile by parser.option( 133 | ArgType.String, 134 | shortName = "composableMetrics", 135 | description = "Composable Metrics TXT files (separated by commas)", 136 | ) 137 | 138 | val classMetricsFile by parser.option( 139 | ArgType.String, 140 | shortName = "classMetrics", 141 | description = "Class Metrics TXT files (separated by commas)", 142 | ) 143 | 144 | val outputDirectory by parser 145 | .option( 146 | ArgType.String, 147 | shortName = "o", 148 | description = "Output directory name", 149 | ).default(path.toAbsolutePath().toString()) 150 | 151 | val includeStableComposables by parser 152 | .option( 153 | ArgType.Boolean, 154 | description = "Whether to include stable Composable functions in the report", 155 | ).default(true) 156 | 157 | val includeStableClasses by parser 158 | .option( 159 | ArgType.Boolean, 160 | description = "Whether to include stable classes in the report", 161 | ).default(true) 162 | 163 | val includeClasses by parser 164 | .option( 165 | ArgType.Boolean, 166 | description = "Whether to include all the classes in the report", 167 | ).default(true) 168 | 169 | val showOnlyUnstableComposables by parser 170 | .option( 171 | ArgType.Boolean, 172 | description = "Whether to ONLY include unstable composables in the report", 173 | ).default(false) 174 | 175 | init { 176 | parser.parse(args) 177 | 178 | printHeader("Validating Arguments") 179 | 180 | require(applicationName.isNotBlank()) { "Application name should not be blank" } 181 | require(outputDirectory.isNotBlank()) { "Output directory path should not be blank" } 182 | } 183 | 184 | fun getRawReportProvider(): ComposeCompilerRawReportProvider { 185 | val directory = inputDirectory 186 | 187 | val files = 188 | arrayOf( 189 | overallStatsFile, 190 | detailedStatsFile, 191 | composableMetricsFile, 192 | classMetricsFile, 193 | ) 194 | 195 | return if (directory != null) { 196 | ensureDirectory(directory) { "Directory '$directory' not exists" } 197 | getRawReportProviderFromDirectory(directory) 198 | } else if (files.all { !it.isNullOrBlank() }) { 199 | getRawReportProviderFromIndividualFiles() 200 | } else { 201 | // Assume report and metric files available in the current working directory as specified in the `path` 202 | val defaultDirectory = path.toAbsolutePath().toString() 203 | getRawReportProviderFromDirectory(defaultDirectory) 204 | } 205 | } 206 | 207 | private fun getRawReportProviderFromIndividualFiles(): ComposeCompilerRawReportProvider = 208 | ComposeCompilerRawReportProvider.FromIndividualFiles( 209 | briefStatisticsJsonFiles = files(overallStatsFile!!), 210 | detailedStatisticsCsvFiles = files(detailedStatsFile!!), 211 | composableReportFiles = files(composableMetricsFile!!), 212 | classesReportFiles = files(classMetricsFile!!), 213 | ) 214 | 215 | private fun getRawReportProviderFromDirectory(directory: String): ComposeCompilerRawReportProvider.FromDirectory = 216 | ComposeCompilerRawReportProvider.FromDirectory(File(Paths.get(directory).toAbsolutePath().toString())) 217 | 218 | private fun files(filenames: String): List = filenames.split(",").map { ensureFileExists(it) { "File not exist: $it" } } 219 | } 220 | 221 | fun printHeader(header: String) = 222 | println( 223 | """ 224 | ------------------------------------------------------------------ 225 | $header 226 | """.trimIndent(), 227 | ) 228 | 229 | object Constants { 230 | const val VERSION = "v1.4.2" 231 | } 232 | -------------------------------------------------------------------------------- /core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") 3 | kotlin("plugin.serialization") version libs.versions.kotlin.get() 4 | id(libs.plugins.mavenPublish.get().pluginId) 5 | } 6 | 7 | repositories { 8 | mavenCentral() 9 | } 10 | 11 | dependencies { 12 | implementation(kotlin("stdlib")) 13 | implementation(libs.kotlinx.serialization.json) 14 | } 15 | -------------------------------------------------------------------------------- /core/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=core 2 | POM_NAME=Compose Report to HTML - Core 3 | POM_DESCRIPTION=Generates details from raw compose report. -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/ComposeCompilerMetricsProvider.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.DetailedStatistics 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.Item 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.RowItems 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.classes.ClassesReport 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.composables.ComposablesReport 31 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.parser.ClassReportParser 32 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.parser.ComposableReportParser 33 | import kotlinx.serialization.json.Json 34 | import kotlinx.serialization.json.JsonObject 35 | import kotlinx.serialization.json.JsonPrimitive 36 | import kotlinx.serialization.json.longOrNull 37 | 38 | /** 39 | * Provides metrics and reports of a Compose compiler 40 | */ 41 | interface ComposeCompilerMetricsProvider { 42 | /** 43 | * Returns key-value pairs from composable metrics 44 | */ 45 | fun getOverallStatistics(): Map 46 | 47 | /** 48 | * Returns detailed statistics from composable report 49 | */ 50 | fun getDetailedStatistics(): DetailedStatistics 51 | 52 | /** 53 | * Returns metrics for the composable functions. 54 | */ 55 | fun getComposablesReport(): ComposablesReport 56 | 57 | /** 58 | * Returns metrics for the classes. 59 | */ 60 | fun getClassesReport(): ClassesReport 61 | } 62 | 63 | /** 64 | * Default implementation for [ComposeCompilerMetricsProvider] which parses content provided by 65 | * [ComposeCompilerRawReportProvider]. 66 | */ 67 | private class DefaultComposeCompilerMetricsProvider( 68 | private val contentProvider: ComposeMetricsContentProvider, 69 | ) : ComposeCompilerMetricsProvider { 70 | override fun getOverallStatistics(): Map { 71 | val statistics = mutableMapOf() 72 | contentProvider.briefStatisticsContents.forEach { statContent -> 73 | val stats = 74 | Json 75 | .decodeFromString(statContent) 76 | .mapNotNull { entry -> 77 | // In Compose 1.7.0, now JSON also includes the details of compiler features. 78 | // To avoid deserialization issues, we have to skip adding these details in this report and just 79 | // have to take primitive values (i.e. actually metrics) in the account. 80 | val primitive = entry.value as? JsonPrimitive 81 | primitive?.longOrNull?.let { longValue -> 82 | entry.key to longValue 83 | } 84 | } 85 | 86 | if (statistics.isEmpty()) { 87 | statistics.putAll(stats) 88 | } else { 89 | stats.forEach { (key, value) -> 90 | statistics[key] = statistics[key]?.plus(value) ?: value 91 | } 92 | } 93 | } 94 | return statistics.toMap() 95 | } 96 | 97 | override fun getDetailedStatistics(): DetailedStatistics { 98 | val csv = contentProvider.detailedStatisticsCsvRows 99 | 100 | val metrics = 101 | if (csv.size > 1) { 102 | val headers = splitWithCsvSeparator(csv.first()) 103 | 104 | csv 105 | .subList(1, csv.size) 106 | .map { splitWithCsvSeparator(it) } 107 | .map { items -> RowItems(items.mapIndexed { index, value -> Item(headers[index], value) }) } 108 | } else { 109 | emptyList() 110 | } 111 | 112 | return DetailedStatistics(metrics) 113 | } 114 | 115 | override fun getComposablesReport(): ComposablesReport = ComposableReportParser.parse(contentProvider.composablesReportContents) 116 | 117 | override fun getClassesReport(): ClassesReport = ClassReportParser.parse(contentProvider.classesReportContents) 118 | 119 | private fun splitWithCsvSeparator(content: String) = content.split(",").filter { it.isNotBlank() } 120 | } 121 | 122 | /** 123 | * Factory function for creating [ComposeCompilerMetricsProvider]. 124 | */ 125 | fun ComposeCompilerMetricsProvider(files: ComposeCompilerRawReportProvider): ComposeCompilerMetricsProvider { 126 | val contentProvider = ComposeMetricsContentProvider(files) 127 | return DefaultComposeCompilerMetricsProvider(contentProvider) 128 | } 129 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/ComposeCompilerRawReportProvider.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.file.ReportAndMetricsFileFinder 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.utils.ensureDirectory 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.utils.ensureFileExists 29 | import java.io.File 30 | 31 | /** 32 | * Provide files of compose compiler metrics and reports 33 | */ 34 | sealed interface ComposeCompilerRawReportProvider { 35 | val briefStatisticsJsonFiles: List 36 | val detailedStatisticsCsvFiles: List 37 | val composableReportFiles: List 38 | val classesReportFiles: List 39 | 40 | /** 41 | * Provides report from individual files 42 | */ 43 | class FromIndividualFiles( 44 | override val briefStatisticsJsonFiles: List, 45 | override val detailedStatisticsCsvFiles: List, 46 | override val composableReportFiles: List, 47 | override val classesReportFiles: List, 48 | ) : ComposeCompilerRawReportProvider { 49 | init { 50 | validateComposeCompilerRawReportProvider() 51 | } 52 | } 53 | 54 | /** 55 | * Searches for files in the given [directory] and provides report and metric files found in that directory. 56 | */ 57 | class FromDirectory( 58 | directory: File, 59 | ) : ComposeCompilerRawReportProvider { 60 | private val finder = ReportAndMetricsFileFinder(directory) 61 | 62 | override val briefStatisticsJsonFiles: List = finder.findBriefStatisticsJsonFile() 63 | override val detailedStatisticsCsvFiles: List = finder.findDetailsStatisticsCsvFile() 64 | override val composableReportFiles: List = finder.findComposablesReportTxtFile() 65 | override val classesReportFiles: List = finder.findClassesReportTxtFile() 66 | 67 | init { 68 | ensureDirectory(directory) { "Directory '$directory' not exists" } 69 | validateComposeCompilerRawReportProvider() 70 | } 71 | } 72 | } 73 | 74 | /** 75 | * Validates report and metric files 76 | */ 77 | fun ComposeCompilerRawReportProvider.validateComposeCompilerRawReportProvider() { 78 | val files = 79 | briefStatisticsJsonFiles + 80 | detailedStatisticsCsvFiles + 81 | composableReportFiles + 82 | classesReportFiles 83 | 84 | files.forEach { ensureFileExists(it) { "File '$it' not exists" } } 85 | } 86 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/ComposeMetricsContentProvider.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core 25 | 26 | /** 27 | * Provides content of a composable report and metrics 28 | */ 29 | class ComposeMetricsContentProvider( 30 | private val fileProvider: ComposeCompilerRawReportProvider, 31 | ) { 32 | val briefStatisticsContents: List get() = fileProvider.briefStatisticsJsonFiles.map { it.readText() } 33 | val detailedStatisticsCsvRows: List get() = fileProvider.detailedStatisticsCsvFiles.flatMap { it.readLines() } 34 | val composablesReportContents: String get() = fileProvider.composableReportFiles.joinToString(separator = "\n") { it.readText() } 35 | val classesReportContents: String get() = fileProvider.classesReportFiles.joinToString(separator = "\n") { it.readText() } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/exception/ParsingException.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.exception 25 | 26 | class ParsingException( 27 | val content: String, 28 | cause: Throwable, 29 | message: String = "Error occurred while parsing the content", 30 | ) : RuntimeException(message, cause) 31 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/file/ReportAndMetricsFileFinder.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.file 25 | 26 | import java.io.File 27 | import java.nio.file.Files 28 | 29 | /** 30 | * Finds reports and metrics files generated by Compose compiler 31 | * 32 | * @param directory The directory in which files will be searched 33 | */ 34 | class ReportAndMetricsFileFinder( 35 | directory: File, 36 | ) { 37 | private val allFiles = directory.listAllFiles() 38 | 39 | fun findBriefStatisticsJsonFile(): List = allFiles.filter { it.name.endsWith(FileSuffixes.MODULE_REPORT_JSON) } 40 | 41 | fun findDetailsStatisticsCsvFile(): List = allFiles.filter { it.name.endsWith(FileSuffixes.COMPOSABLES_STATS_METRICS_CSV) } 42 | 43 | fun findComposablesReportTxtFile(): List = allFiles.filter { it.name.endsWith(FileSuffixes.COMPOSABLES_REPORT_TXT) } 44 | 45 | fun findClassesReportTxtFile(): List = allFiles.filter { it.name.endsWith(FileSuffixes.CLASSES_REPORT_TXT) } 46 | 47 | private fun File.listAllFiles(): List = 48 | buildList { 49 | val currentPath = toPath() 50 | Files.newDirectoryStream(currentPath).use { directoryStream -> 51 | for (entry in directoryStream) { 52 | val file = entry.toFile() ?: continue 53 | if (Files.isDirectory(entry)) { 54 | addAll(file.listAllFiles()) 55 | } else { 56 | add(file) 57 | } 58 | } 59 | } 60 | } 61 | 62 | object FileSuffixes { 63 | const val CLASSES_REPORT_TXT = "-classes.txt" 64 | const val COMPOSABLES_REPORT_TXT = "-composables.txt" 65 | const val COMPOSABLES_STATS_METRICS_CSV = "-composables.csv" 66 | const val MODULE_REPORT_JSON = "-module.json" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/mapper/ConditionMapper.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.mapper 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.Condition 27 | 28 | object ConditionMapper { 29 | fun from(value: String): Condition = 30 | when (value.lowercase()) { 31 | "stable" -> Condition.STABLE 32 | "unstable" -> Condition.UNSTABLE 33 | else -> Condition.MISSING 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/model/Condition.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.model 25 | 26 | enum class Condition { 27 | STABLE, 28 | UNSTABLE, 29 | MISSING, 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/model/DetailedStatistics.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.model 25 | 26 | /** 27 | * Model for holding detailed statistical information 28 | * 29 | * @property items List of detailed items 30 | */ 31 | data class DetailedStatistics( 32 | val items: List, 33 | ) { 34 | /** 35 | * Headers of a report 36 | */ 37 | val headers: List get() = items.first().item.map { it.name } 38 | } 39 | 40 | /** 41 | * Model for holding list of name and value pairs i.e. item details 42 | */ 43 | data class RowItems( 44 | val item: List, 45 | ) 46 | 47 | /** 48 | * Model representing name-value pairs 49 | */ 50 | data class Item( 51 | val name: String, 52 | val value: String, 53 | ) 54 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/model/RawContent.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.model 25 | 26 | /** 27 | * Represents raw data provided by Compose compiler. 28 | * Example: Composable function metric generated by compiler extracted from `-composables.txt` file 29 | */ 30 | data class RawContent( 31 | val content: String, 32 | ) 33 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/model/classes/ClassDetail.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.classes 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.Condition 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.RawContent 28 | 29 | /** 30 | * Model for holding class details 31 | * 32 | * @property className Name of a class 33 | * @property stability Stability of a class 34 | * @property runtimeStability Runtime stability of a class 35 | * @property fields List of member fields of a class 36 | */ 37 | data class ClassDetail( 38 | val className: String, 39 | val stability: Condition, 40 | val runtimeStability: Condition?, 41 | val fields: List, 42 | val rawContent: RawContent, 43 | ) { 44 | /** 45 | * Model for holding field details of a class 46 | * 47 | * @property status Status of a field. E.g. STABLE, UNSTABLE, etc 48 | * @property details Name and type details of a field. 49 | */ 50 | data class Field( 51 | val status: String, 52 | val details: String, 53 | ) { 54 | private val nameAndType by lazy { 55 | details 56 | .split(":") 57 | .map { it.trim() } 58 | .let { (name, type) -> name to type } 59 | } 60 | 61 | /** 62 | * Name of a field 63 | */ 64 | val name: String get() = nameAndType.first 65 | 66 | /** 67 | * Type of field 68 | */ 69 | val type: String get() = nameAndType.second 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/model/classes/ClassesReport.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.classes 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.exception.ParsingException 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.Condition 28 | 29 | /** 30 | * A model representing class reports 31 | * 32 | * @property classes All class details 33 | * @property errors List of Errors occurred while parsing the classes 34 | */ 35 | data class ClassesReport( 36 | val classes: List, 37 | val errors: List, 38 | ) { 39 | private val stableAndUnstableClasses by lazy { 40 | classes.partition { it.stability === Condition.STABLE } 41 | } 42 | 43 | /** 44 | * List of stable classes 45 | */ 46 | val stableClasses = stableAndUnstableClasses.first 47 | 48 | /** 49 | * List of unstable classes 50 | */ 51 | val unstableClasses = stableAndUnstableClasses.second 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/model/composables/ComposableDetail.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.composables 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.Condition 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.RawContent 28 | 29 | /** 30 | * Model for holding Detail of a composable function 31 | * 32 | * @property functionName Name of a function 33 | * @property isRestartable States whether composable function is restartable or not 34 | * @property isSkippable States whether composable function is skippable or not 35 | * @property isInline States whether composable function is inline or not 36 | * @property params List of parameters of a composable function 37 | */ 38 | data class ComposableDetail( 39 | val functionName: String, 40 | val isRestartable: Boolean, 41 | val isSkippable: Boolean, 42 | val isInline: Boolean, 43 | val params: List, 44 | val rawContent: RawContent, 45 | ) { 46 | /** 47 | * Model for holding details of a parameter of a function 48 | * 49 | * @property condition Stability condition of a parameter 50 | * @property details Name and type details of a parameter 51 | */ 52 | data class Parameter( 53 | val condition: Condition, 54 | val details: String, 55 | ) { 56 | private val nameAndType by lazy { 57 | details.split(":").map { it.trim() }.let { (name, type) -> name to type } 58 | } 59 | 60 | /** 61 | * Name of parameter 62 | */ 63 | val name: String get() = nameAndType.first 64 | 65 | /** 66 | * Type of parameter 67 | */ 68 | val type: String get() = nameAndType.second 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/model/composables/ComposablesReport.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.composables 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.exception.ParsingException 27 | 28 | data class ComposablesReport( 29 | val composables: List, 30 | val errors: List, 31 | ) { 32 | private val partitionedComposables by lazy { composables.partition { !it.isSkippable && it.isRestartable } } 33 | 34 | val restartableButNotSkippableComposables: List get() = partitionedComposables.first 35 | val nonIssuesComposables: List get() = partitionedComposables.second 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/parser/ClassReportParser.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.parser 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.exception.ParsingException 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.mapper.ConditionMapper 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.RawContent 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.classes.ClassDetail 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.classes.ClassesReport 31 | 32 | /** 33 | * Parses [ClassesReport] from the [String] content. 34 | */ 35 | object ClassReportParser : Parser { 36 | private val REGEX_RUNTIME_STABILITY = " = (\\w+)".toRegex() 37 | private val REGEX_CLASS_NAME = "(stable|unstable|runtime) class (\\w*)".toRegex() 38 | private val REGEX_CLASS_FIELDS = "((\\w*) ((?:val|var) .*))".toRegex() 39 | 40 | /** 41 | * Parses all classes 42 | */ 43 | override fun parse(content: String): ClassesReport { 44 | val errors = mutableListOf() 45 | 46 | val classes = 47 | getClasses(content) 48 | .mapNotNull { classBody -> 49 | runCatching { 50 | parseClassDetail(classBody) 51 | }.onFailure { cause -> 52 | errors.add(ParsingException(classBody, cause)) 53 | }.getOrNull() 54 | }.toList() 55 | 56 | return ClassesReport(classes, errors.toList()) 57 | } 58 | 59 | internal fun getClasses(content: String): List { 60 | val lines = content.split("\n").filter { it.isNotBlank() } 61 | 62 | val classIndexes = 63 | lines.mapIndexedNotNull { index, s -> 64 | if (REGEX_CLASS_NAME.containsMatchIn(s)) { 65 | index 66 | } else { 67 | null 68 | } 69 | } 70 | 71 | return classIndexes.mapIndexed { index: Int, item: Int -> 72 | lines.subList(item, classIndexes.getOrElse(index + 1) { lines.size }).joinToString(separator = "\n") 73 | } 74 | } 75 | 76 | /** 77 | * Parses unit class 78 | */ 79 | private fun parseClassDetail(classBody: String): ClassDetail { 80 | val classDetail = REGEX_CLASS_NAME.find(classBody)?.groupValues 81 | val className = classDetail?.getOrNull(2) ?: error("Undefined name for the class body: $classBody") 82 | val stability = 83 | classDetail.getOrNull(1)?.let { ConditionMapper.from(it) } 84 | ?: error("Undefined stability status for the class body: $classBody") 85 | 86 | val runtimeStability = 87 | REGEX_RUNTIME_STABILITY 88 | .find(classBody) 89 | ?.groupValues 90 | ?.getOrNull(1) 91 | ?.let { ConditionMapper.from(it) } 92 | 93 | val fields = 94 | REGEX_CLASS_FIELDS 95 | .findAll(classBody) 96 | .map { it.groupValues } 97 | .filter { it.isNotEmpty() } 98 | .map { ClassDetail.Field(it[2], it[3]) } 99 | .toList() 100 | 101 | return ClassDetail( 102 | className = className, 103 | stability = stability, 104 | runtimeStability = runtimeStability, 105 | fields = fields, 106 | rawContent = RawContent(classBody), 107 | ) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/parser/ComposableReportParser.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.parser 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.exception.ParsingException 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.mapper.ConditionMapper 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.RawContent 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.composables.ComposableDetail 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.composables.ComposablesReport 31 | 32 | /** 33 | * Parses [ComposablesReport] from the [String] content. 34 | */ 35 | object ComposableReportParser : Parser { 36 | private val REGEX_COMPOSABLE_FUNCTION = "(?:(.*))fun (\\w*)".toRegex() 37 | private val REGEX_COMPOSABLE_PARAMETERS = "(?:(stable|unstable|\\w+) (\\w*:\\s.*))".toRegex() 38 | 39 | /** 40 | * Parses all composable functions 41 | */ 42 | override fun parse(content: String): ComposablesReport { 43 | val errors = mutableListOf() 44 | 45 | val composables = 46 | getComposableFunctions(content) 47 | .mapNotNull { function -> 48 | runCatching { 49 | parseComposableDetail(function) 50 | }.onFailure { cause -> 51 | errors.add(ParsingException(function, cause)) 52 | }.getOrNull() 53 | }.toList() 54 | 55 | return ComposablesReport(composables, errors.toList()) 56 | } 57 | 58 | internal fun getComposableFunctions(content: String): List { 59 | val lines = content.split("\n").filter { it.isNotBlank() } 60 | 61 | val composableFunIndexes = 62 | lines.mapIndexedNotNull { index, s -> 63 | if (REGEX_COMPOSABLE_FUNCTION.containsMatchIn(s)) { 64 | index 65 | } else { 66 | null 67 | } 68 | } 69 | 70 | return composableFunIndexes.mapIndexed { index: Int, item: Int -> 71 | lines.subList(item, composableFunIndexes.getOrElse(index + 1) { lines.size }).joinToString(separator = "\n") 72 | } 73 | } 74 | 75 | /** 76 | * Parses unit composable 77 | */ 78 | private fun parseComposableDetail(function: String): ComposableDetail { 79 | val composableDetails = REGEX_COMPOSABLE_FUNCTION.find(function)?.groupValues!! 80 | 81 | val functionDetail = composableDetails[0] 82 | val functionName = composableDetails[2] 83 | 84 | val isInline = functionDetail.contains("inline") 85 | val isRestartable = functionDetail.contains("restartable") 86 | val isSkippable = functionDetail.contains("skippable") 87 | 88 | val params = 89 | REGEX_COMPOSABLE_PARAMETERS 90 | .findAll(function) 91 | .map { it.groupValues } 92 | .filter { it.isNotEmpty() } 93 | .map { ComposableDetail.Parameter(ConditionMapper.from(it[1]), it[2]) } 94 | .toList() 95 | 96 | return ComposableDetail( 97 | functionName = functionName, 98 | isRestartable = isRestartable, 99 | isSkippable = isSkippable, 100 | isInline = isInline, 101 | params = params, 102 | rawContent = RawContent(function), 103 | ) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/parser/Parser.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.parser 25 | 26 | /** 27 | * Core parser for parsing value from [I] type to [O] type. 28 | */ 29 | interface Parser { 30 | /** 31 | * Parses the [content] and returns [O] 32 | */ 33 | fun parse(content: I): O 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/utils/CamelCaseToWord.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.utils 25 | 26 | private val REGEX_CAMEL_CASE = "(\\A[a-z]|[A-Z])".toRegex() 27 | 28 | fun camelCaseToWord(content: String): String = content.replace(REGEX_CAMEL_CASE) { " ${it.value[0].uppercase()}" }.trim() 29 | -------------------------------------------------------------------------------- /core/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/core/utils/FileUtils.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.core.utils 25 | 26 | import java.io.File 27 | import java.io.FileNotFoundException 28 | import java.nio.file.Paths 29 | 30 | /** 31 | * Checks whether directory with [path] exists or not. 32 | * Else throws [FileNotFoundException]. 33 | */ 34 | inline fun ensureDirectory( 35 | path: String, 36 | lazyMessage: () -> Any, 37 | ) { 38 | val file = File(Paths.get(path).toAbsolutePath().toString()) 39 | ensureDirectory(file, lazyMessage) 40 | } 41 | 42 | /** 43 | * Checks whether directory with [path] exists or not. 44 | * Else throws [FileNotFoundException]. 45 | */ 46 | inline fun ensureDirectory( 47 | directory: File, 48 | lazyMessage: () -> Any, 49 | ) { 50 | println("Checking directory '${directory.absolutePath}'") 51 | if (!directory.isDirectory) { 52 | val message = lazyMessage() 53 | throw FileNotFoundException(message.toString()) 54 | } 55 | } 56 | 57 | /** 58 | * Checks whether file with [filename] exists or not. Else throws [FileNotFoundException]. 59 | */ 60 | inline fun ensureFileExists( 61 | filename: String, 62 | lazyMessage: () -> Any, 63 | ): File { 64 | val file = File(Paths.get(filename).toAbsolutePath().toString()) 65 | return ensureFileExists(file, lazyMessage) 66 | } 67 | 68 | /** 69 | * Checks whether [file] with exists or not. Else throws [FileNotFoundException]. 70 | */ 71 | inline fun ensureFileExists( 72 | file: File, 73 | lazyMessage: () -> Any, 74 | ): File { 75 | println("Checking file '${file.absolutePath}'") 76 | if (!file.exists()) { 77 | val message = lazyMessage() 78 | throw FileNotFoundException(message.toString()) 79 | } 80 | return file 81 | } 82 | -------------------------------------------------------------------------------- /docs/images/brief-stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatilShreyas/compose-report-to-html/4d8d01495045ec4532e629865453445bcabe6188/docs/images/brief-stats.png -------------------------------------------------------------------------------- /docs/images/class-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatilShreyas/compose-report-to-html/4d8d01495045ec4532e629865453445bcabe6188/docs/images/class-report.png -------------------------------------------------------------------------------- /docs/images/composable-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatilShreyas/compose-report-to-html/4d8d01495045ec4532e629865453445bcabe6188/docs/images/composable-report.png -------------------------------------------------------------------------------- /docs/images/detailed-stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatilShreyas/compose-report-to-html/4d8d01495045ec4532e629865453445bcabe6188/docs/images/detailed-stats.png -------------------------------------------------------------------------------- /docs/images/gradle-plugin-example-android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatilShreyas/compose-report-to-html/4d8d01495045ec4532e629865453445bcabe6188/docs/images/gradle-plugin-example-android.png -------------------------------------------------------------------------------- /docs/images/gradle-plugin-example-kmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatilShreyas/compose-report-to-html/4d8d01495045ec4532e629865453445bcabe6188/docs/images/gradle-plugin-example-kmp.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | hide: 3 | 4 | - toc 5 | 6 | --- 7 | 8 | # Compose Compiler Report to HTML 9 | 10 | A utility (**Gradle Plugin + CLI**) to convert Jetpack Compose compiler metrics and reports to beautified 😍 HTML page. 11 | _Made with ❤️ for Android Developers and Composers_ 12 | 13 | | Distribution | Usage Guide | Install | 14 | |----------------------|---------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 15 | | **Gradle Plugin** | [Read](https://patilshreyas.github.io/compose-report-to-html/use/using-gradle-plugin/) | [![Gradle Plugin](https://img.shields.io/gradle-plugin-portal/v/dev.shreyaspatil.compose-compiler-report-generator?color=%233cafc6&label=Plugin&logo=gradle&style=flat-square)](https://plugins.gradle.org/plugin/dev.shreyaspatil.compose-compiler-report-generator) | 16 | | **CLI** | [Read](https://patilshreyas.github.io/compose-report-to-html/use/using-cli/) | [![NPM Package](https://img.shields.io/npm/v/compose-report2html?label=npm&logo=npm&style=flat-square)](https://www.npmjs.com/package/compose-report2html)
[![Download JAR](https://img.shields.io/github/v/release/patilshreyas/compose-report-to-html?label=JAR&logo=java&style=flat-square)](https://github.com/patilshreyas/compose-report-to-html/releases/latest/download/composeReport2Html.jar) | 17 | | **Library Artifact** | [Read](https://patilshreyas.github.io/compose-report-to-html/use/using-utility-as-library/) | [![Install](https://img.shields.io/maven-central/v/dev.shreyaspatil.compose-compiler-report-generator/core?label=Maven%20Central&logo=android&style=flat-square)](https://search.maven.org/search?q=g:dev.shreyaspatil.compose-compiler-report-generator) | 18 | 19 | ## 💡 Motivation 20 | 21 | The Compose Compiler plugin can generate reports / metrics around certain compose-specific concepts that can be useful 22 | to understand what is happening with some of your compose code at a fine-grained level. 23 | [_**See this**_](https://github.com/androidx/androidx/blob/androidx-main/compose/compiler/design/compiler-metrics.md) 24 | to understand this concept in detail. 25 | 26 | This generates reports in `json`, `csv` and `txt` files which are not easily trace-able for developers. 27 | Also, Composable function and class reports becomes large and tedious to check. 28 | This tool parses the reports and metrics generated by Compose compiler and beautifies into a HTML page and intelligently 29 | distinguishes problematic and non-problematic composable functions and classes. 30 | 31 | _This utility doesn't generate Compose Metrics and Reports on its own. 32 | First, raw Compose report should be generated from the Compose Compiler and those generated files should be feed to 33 | this utility. By parsing that data, this utility generates the beautified report._ 34 | 35 | ## 📈 How it looks? 36 | 37 | !!! info 38 | 39 | _See report generated for [NotyKT app](https://patilshreyas.github.io/NotyKT/#/pages/noty-android/compose-compiler-metrics-and-report)_. 40 | Once report is generated, it looks like this ⬇️. 41 | 42 | [View Report](https://patilshreyas.github.io/NotyKT/pages/noty-android/compose_report.html){ .md-button .md-button--primary } 43 | 44 | This is overall Report Overview: 45 | 46 | | **Title** | **Preview** | 47 | |-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 48 | | **Brief Statistics** | Generates metrics from `.json` file and represents in tabular format.

![Brief Statistics](images/brief-stats.png) | 49 | | **Detailed Statistics** | Generates report from `.csv` file and represents in tabular format.

![Detailed Statistics](images/detailed-stats.png) | 50 | | **Composable Report** | Parses `-composables.txt` file and separates out composables with and without issues and properly highlights issues associated with them.

![Composable Report](images/composable-report.png) | 51 | | **Class Report** | Parses `-classes.txt` file and separates out stable and unstable classes out of it and properly highlights issues associated with them.

![Class Report](images/class-report.png) | 52 | 53 | Right now, work is in progress and more improvements related to the report 54 | will happen in some time. If you have any feedback / suggestions related to 55 | the report, feel free to [discuss](https://github.com/PatilShreyas/compose-report-to-html/discussions). 56 | -------------------------------------------------------------------------------- /docs/use/using-cli.md: -------------------------------------------------------------------------------- 1 | # CLI Utility 2 | 3 | ## Pre-requisite 4 | 5 | This CLI utility just takes care of generating beautified report from generated raw report by Compose compiler. 6 | Thus, before using CLI, you'll need to generate compose compiler metrics and reports manually. 7 | 8 | ### How to generate Compose Compiler metric and report? 9 | 10 | Make sure to generate Compose compiler metrics and reports as 11 | mentioned [here](https://github.com/androidx/androidx/blob/androidx-main/compose/compiler/design/compiler-metrics.md) 12 | or [this good read article by Chris Banes](https://chrisbanes.me/posts/composable-metrics/). These files are then needed to 13 | this CLI utility to feed the data. 14 | 15 | To generate the report, provide details related to app, metric and report files and output directory. 16 | 17 | ## Using CLI 18 | 19 | CLI utility is available in the two forms: 20 | 21 | 1. JAR Distribution 22 | 2. NPM package 23 | 24 | ### 1. Install the distribution 25 | 26 | === "JAR Distribution" 27 | 28 | Navigate to the [releases](https://github.com/PatilShreyas/compose-report-to-html/releases) and download the latest JAR artifact. 29 | 30 | Latest: [![Download JAR](https://img.shields.io/github/v/release/patilshreyas/compose-report-to-html?label=JAR&logo=java)](https://github.com/patilshreyas/compose-report-to-html/releases/latest/download/composeReport2Html.jar) 31 | 32 | === "NPM Package" 33 | 34 | ```shell 35 | npm install -g compose-report2html 36 | ``` 37 | 38 | Latest: [![NPM Package](https://img.shields.io/npm/v/compose-report2html?label=npm&logo=npm)](https://www.npmjs.com/package/compose-report2html) 39 | 40 | ### 2. Know usage 41 | 42 | Run the command to know the usage of CLI 43 | 44 | === "JAR Distribution" 45 | 46 | ```shell 47 | java -jar composeReport2Html.jar -h 48 | ``` 49 | 50 | === "NPM Package" 51 | 52 | ```shell 53 | composeReport2Html.jar -h 54 | ``` 55 | 56 | !!! success "▶️Output" 57 | 58 | ```shell 59 | Usage: Compose Compiler Report to HTML Generator ~ v1.4.2 options_list 60 | Options: 61 | --applicationName, -app -> Application name (To be displayed in the report) (always required) { String } 62 | --inputDirectory, -i -> Input directory where composable report and metrics are available { String } 63 | --overallStatsFile, -overallStatsReport -> Overall Statistics Metrics JSON files (separated by commas) { String } 64 | --detailedStatsFile, -detailedStatsMetrics -> Detailed Statistics Metrics CSV files (separated by commas) { String } 65 | --composableMetricsFile, -composableMetrics -> Composable Metrics TXT files (separated by commas) { String } 66 | --classMetricsFile, -classMetrics -> Class Metrics TXT files (separated by commas) { String } 67 | --outputDirectory, -o -> Output directory name { String } 68 | --includeStableComposables [true] -> Whether to include stable Composable functions in the report 69 | --includeStableClasses [true] -> Whether to include stable classes in the report 70 | --includeClasses [true] -> Whether to include all the classes in the report 71 | --showOnlyUnstableComposables [false] -> Whether to ONLY include unstable composables in the report 72 | --help, -h -> Usage info 73 | ``` 74 | 75 | ### 3. Generate report 76 | 77 | HTML Report can be generated with the following combinations. 78 | 79 | #### 3.1 When all metric and report files are available in the same directory 80 | 81 | Assuming report and metrics generated by Compose Compiler are available in one directory then you can specify path to 82 | that directory only and utility will automatically pick files. 83 | 84 | === "JAR Distribution" 85 | 86 | ```shell 87 | java -jar composeReport2Html.jar \ 88 | -app MyAppName \ 89 | -i path/to/metric/directory \ 90 | -o path/to/html/output 91 | ``` 92 | 93 | === "NPM Package" 94 | 95 | ```shell 96 | composeReport2Html \ 97 | -app MyAppName \ 98 | -i path/to/metric/directory \ 99 | -o path/to/html/output 100 | ``` 101 | 102 | !!! info 103 | 104 | In the above command, path provided to `-i` parameter assumes all metrics and report are present and generates and saves report in the path provided to `-o` parameter. 105 | 106 | #### 3.2 Provide path to individual report and metric files 107 | 108 | You can provide each metric/report file individually using separate parameters. 109 | 110 | === "JAR Distribution" 111 | 112 | ```shell 113 | java -jar composeReport2Html.jar \ 114 | -app MyAppName \ 115 | -overallStatsReport app_release-module.json \ 116 | -detailedStatsMetrics app_release-composables.csv \ 117 | -composableMetrics app_release-composables.txt \ 118 | -classMetrics app_release-classes.txt \ 119 | -o htmlReportDir 120 | ``` 121 | 122 | === "NPM Package" 123 | 124 | ```shell 125 | composeReport2Html \ 126 | -app MyAppName \ 127 | -overallStatsReport app_release-module.json \ 128 | -detailedStatsMetrics app_release-composables.csv \ 129 | -composableMetrics app_release-composables.txt \ 130 | -classMetrics app_release-classes.txt \ 131 | -o htmlReportDir 132 | ``` 133 | 134 | !!! info 135 | 136 | Multiple metric/report files can be provided as a CLI parameter by providing path separated by comma (`,`). 137 | -------------------------------------------------------------------------------- /docs/use/using-gradle-plugin.md: -------------------------------------------------------------------------------- 1 | # Gradle Plugin 2 | 3 | Using the Gradle Plugin, you can fully automate the process of generating the report without any overhead. 4 | This Gradle plugin takes care of generating raw compose metrics and report from the Compose compiler and then 5 | generates the beautified report from them. 6 | 7 | **This plugin has support for Android projects and Kotlin Multiplatform projects.** 8 | 9 | ## ✅ Apply the plugin 10 | 11 | Apply the plugin to the module in which _**compose is enabled**_. 12 | 13 | !!! info 14 | 15 | Check the latest plugin release: 16 | [![Gradle Plugin](https://img.shields.io/gradle-plugin-portal/v/dev.shreyaspatil.compose-compiler-report-generator?color=%233cafc6&label=Plugin&logo=gradle&style=flat-square)](https://plugins.gradle.org/plugin/dev.shreyaspatil.compose-compiler-report-generator) 17 | 18 | ### Using the plugins DSL: 19 | 20 | === "Groovy" 21 | 22 | ```groovy title="build.gradle" 23 | plugins { 24 | id "dev.shreyaspatil.compose-compiler-report-generator" version "1.4.2" 25 | } 26 | ``` 27 | 28 | === "Kotlin" 29 | 30 | ```kotlin title="build.gradle.kts" 31 | plugins { 32 | id("dev.shreyaspatil.compose-compiler-report-generator") version "1.4.2" 33 | } 34 | ``` 35 | 36 | ### Using legacy plugin application: 37 | 38 | Add this to top project level `build.gradle` 39 | 40 | === "Groovy" 41 | 42 | ```groovy title="build.gradle" 43 | buildscript { 44 | repositories { 45 | maven { 46 | url "https://plugins.gradle.org/m2/" 47 | } 48 | } 49 | dependencies { 50 | classpath "dev.shreyaspatil.compose-compiler-report-generator:gradle-plugin:1.4.2" 51 | } 52 | } 53 | ``` 54 | 55 | Apply in the module level project: 56 | 57 | ```groovy 58 | apply plugin: "dev.shreyaspatil.compose-compiler-report-generator" 59 | ``` 60 | 61 | === "Kotlin" 62 | 63 | ```kotlin title="build.gradle.kts" 64 | buildscript { 65 | repositories { 66 | maven { 67 | url = uri("https://plugins.gradle.org/m2/") 68 | } 69 | } 70 | dependencies { 71 | classpath("dev.shreyaspatil.compose-compiler-report-generator:gradle-plugin:1.4.2") 72 | } 73 | } 74 | ``` 75 | 76 | Apply in the module level project: 77 | 78 | ```kotlin 79 | apply(plugin = "dev.shreyaspatil.compose-compiler-report-generator") 80 | ``` 81 | 82 | ## 💫 Sync the project 83 | 84 | Once plugin is applied, sync the project. After the project is synced, tasks for generating compose 85 | report will be generated for the variants and flavors used in the project. 86 | 87 | !!! example 88 | 89 | === "Android Project" 90 | 91 | ![](../images/gradle-plugin-example-android.png){ height="150" } 92 | 93 | === "Multiplatform Project" 94 | For Kotlin Multiplatform project, tasks will be generated for the platform modules 95 | and build types. 96 | 97 | ![](../images/gradle-plugin-example-kmp.png){ height="120" } 98 | 99 | 100 | 101 | ## 🪄 Generate report 102 | 103 | Run the Gradle task (_or directly run the task from tasks pane available on the right side of IDE_) 104 | 105 | ```shell 106 | ./gradlew :app:releaseComposeCompilerHtmlReport 107 | ``` 108 | 109 | If report is generated successfully, the path to report will be logged in the console 110 | 111 | !!! example "Example (Console output)" 112 | 113 | ```shell 114 | Compose Compiler report is generated: .../noty-android/app/composeapp/build/compose_report/index.html 115 | 116 | BUILD SUCCESSFUL in 58s 117 | 1 actionable task: 1 executed 118 | ``` 119 | 120 | ## ⚙️ Configure parameters for plugin (Optional) 121 | 122 | If you have to configure plugin parameters manually (which is completely optional), it can be configured as follows: 123 | 124 | === "Groovy" 125 | 126 | ```groovy title="build.gradle" 127 | htmlComposeCompilerReport { 128 | // Enables metrics generation from the compose compiler 129 | enableMetrics = true/false // Default: `true` 130 | 131 | // Enables report generation from the compose compiler 132 | enableReport = true/false // Default: `true` 133 | 134 | // Sets the name for a report 135 | name = "Report Name" // Default: Module name 136 | 137 | // Output directory where report will be generated 138 | outputDirectory = layout.buildDirectory.dir("custom_dir").get().asFile // Default: module/buildDir/compose_report 139 | 140 | // Whether to include stable composable functions in the final report or not. 141 | includeStableComposables = true/false // Default: true 142 | 143 | // Whether to include stable classes in the final report or not. 144 | includeStableClasses = true/false // Default: true 145 | 146 | // Whether to include the ALL classes in the final report or not. 147 | includeClasses = true/false // Default: true 148 | 149 | // ONLY show unstable composables in the report without stats and classes 150 | showOnlyUnstableComposables = true/false // Default: false 151 | } 152 | ``` 153 | 154 | === "Kotlin (JVM / Android / Multiplatform)" 155 | 156 | ```kotlin title="build.gradle.kts" 157 | htmlComposeCompilerReport { 158 | // Enables metrics generation from the compose compiler 159 | enableMetrics.set(true/false) // Default: `true` 160 | 161 | // Enables report generation from the compose compiler 162 | enableReport.set(true/false) // Default: `true` 163 | 164 | // Sets the name for a report 165 | name.set("Report Name") // Default: Module name 166 | 167 | // Output directory where report will be generated 168 | outputDirectory.set(layout.buildDirectory.dir("custom_dir").get().asFile) // Default: module/buildDir/compose_report 169 | 170 | // Whether to include stable composable functions in the final report or not. 171 | includeStableComposables.set(true/false) // Default: true 172 | 173 | // Whether to include stable classes in the final report or not. 174 | includeStableClasses.set(true/false) // Default: true 175 | 176 | // Whether to include the ALL classes in the final report or not. 177 | includeClasses.set(true/false) // Default: true 178 | 179 | // ONLY show unstable composables in the report without stats and classes 180 | showOnlyUnstableComposables.set(true/false) // Default: false 181 | } 182 | ``` -------------------------------------------------------------------------------- /docs/use/using-utility-as-library.md: -------------------------------------------------------------------------------- 1 | # Using utility as a library 2 | 3 | This utility is also published as a maven artifact on Maven Central so that you can make use of it as you want to use it 4 | (_For example: automation in CI_). 5 | 6 | 7 | ## Add dependency 8 | 9 | Declare the following dependencies in the project: 10 | 11 | ```kotlin 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | implementation("dev.shreyaspatil.compose-compiler-report-generator:core:$version") 18 | implementation("dev.shreyaspatil.compose-compiler-report-generator:report-generator:$version") 19 | } 20 | ``` 21 | 22 | Refer to the latest release on [GitHub Releases](https://github.com/PatilShreyas/compose-report-to-html/releases) or maven central: [![Install](https://img.shields.io/maven-central/v/dev.shreyaspatil.compose-compiler-report-generator/core?label=Maven%20Central&logo=android&style=flat-square)](https://search.maven.org/search?q=g:dev.shreyaspatil.compose-compiler-report-generator) 23 | 24 | ## Usage 25 | 26 | ```kotlin 27 | // Create a report specification with application name 28 | val reportSpec = ReportSpec( 29 | name = "Your Application Name", 30 | options = ReportOptions() // Customize it as per need 31 | ) 32 | 33 | // Get provider for raw reports (generated by compose compiler) 34 | val rawReportProvider = ComposeCompilerRawReportProvider.FromDirectory("path/to/raw-reports") 35 | 36 | // Provide metric files to generator 37 | val htmlGenerator = HtmlReportGenerator( 38 | reportSpec = reportSpec, 39 | metricsProvider = ComposeCompilerMetricsProvider(rawReportProvider) 40 | ) 41 | 42 | // Generate HTML (String) 43 | val html = htmlGenerator.generateHtml() 44 | ``` -------------------------------------------------------------------------------- /gradle-plugin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | val GROUP: String by project 2 | val POM_NAME: String by project 3 | val VERSION_NAME: String by project 4 | val POM_DESCRIPTION: String by project 5 | 6 | plugins { 7 | `kotlin-dsl` 8 | `java-gradle-plugin` 9 | alias(libs.plugins.gradle.plugin.publish) 10 | } 11 | 12 | group = GROUP 13 | version = VERSION_NAME 14 | 15 | dependencies { 16 | compileOnly(gradleApi()) 17 | compileOnly(kotlin("stdlib")) 18 | compileOnly(libs.kotlin.gradle.plugin) 19 | compileOnly(libs.android.gradle.plugin) 20 | compileOnly(libs.compose.multiplatform.gradle.plugin) 21 | 22 | implementation(project(":core")) 23 | implementation(project(":report-generator")) 24 | } 25 | 26 | tasks.getByName("test") { 27 | useJUnitPlatform() 28 | } 29 | 30 | gradlePlugin { 31 | website.set("https://github.com/PatilShreyas/compose-report-to-html") 32 | vcsUrl.set("https://github.com/PatilShreyas/compose-report-to-html") 33 | plugins { 34 | create("reportGenPlugin") { 35 | id = "dev.shreyaspatil.compose-compiler-report-generator" 36 | displayName = POM_NAME 37 | description = POM_DESCRIPTION 38 | implementationClass = "dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.ReportGenPlugin" 39 | tags.set(listOf("android", "compose", "report", "jetpackcompose", "composecompiler")) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /gradle-plugin/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=gradle-plugin 2 | POM_NAME=Compose Report to HTML - Gradle Plugin 3 | POM_DESCRIPTION=A gradle plugin to generates HTML report from Android Studio Project. -------------------------------------------------------------------------------- /gradle-plugin/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/plugin/ComposeCompilerReportExtension.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.plugin 25 | 26 | import org.gradle.api.Project 27 | import org.gradle.api.provider.Property 28 | import org.gradle.kotlin.dsl.create 29 | import org.gradle.kotlin.dsl.getByType 30 | import java.io.File 31 | 32 | interface ComposeCompilerReportExtension { 33 | /** 34 | * Enable calculating metrics from the compose compiler in the main report. 35 | */ 36 | val enableMetrics: Property 37 | 38 | /** 39 | * Enable extracting statistical report from the compose compiler in the main report. 40 | */ 41 | val enableReport: Property 42 | 43 | /** 44 | * Name of the report. It can be a name of application, module, etc. 45 | */ 46 | val name: Property 47 | 48 | /** 49 | * The directory where report will be stored. 50 | */ 51 | val outputDirectory: Property 52 | 53 | /** 54 | * Include the report for stable composable functions in the module which doesn't need optimizations. 55 | */ 56 | val includeStableComposables: Property 57 | 58 | /** 59 | * Include the report for stable classes in the module which doesn't need optimizations. 60 | */ 61 | val includeStableClasses: Property 62 | 63 | /** 64 | * Include the report for all classes in the module. 65 | */ 66 | val includeClasses: Property 67 | 68 | /** 69 | * The report will only include the detail of unstable composables. 70 | */ 71 | val showOnlyUnstableComposables: Property 72 | 73 | val composeRawMetricsOutputDirectory: File 74 | get() = outputDirectory.get().resolve("raw") 75 | 76 | companion object { 77 | const val NAME = "htmlComposeCompilerReport" 78 | 79 | /** 80 | * Creates a extension of type [ComposeCompilerReportExtension] and returns 81 | */ 82 | fun create(target: Project) = 83 | target.extensions.create(NAME).apply { 84 | enableReport.convention(true) 85 | enableMetrics.convention(true) 86 | includeStableComposables.convention(true) 87 | includeStableClasses.convention(true) 88 | includeClasses.convention(true) 89 | name.convention("${target.rootProject.name}:${target.name}") 90 | outputDirectory.convention(target.buildDir.resolve("compose_report")) 91 | showOnlyUnstableComposables.convention(false) 92 | } 93 | 94 | /** 95 | * Get extensions applied to the [target] project. 96 | */ 97 | fun get(target: Project) = target.extensions.getByType() 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /gradle-plugin/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/plugin/ReportGenPlugin.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.plugin 25 | 26 | import com.android.build.api.variant.AndroidComponentsExtension 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.multiplatform.android.configureKotlinAndroidComposeCompilerReports 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.multiplatform.configureKotlinMultiplatformComposeCompilerReports 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.multiplatform.jvm.configureKotlinJvmComposeCompilerReports 30 | import org.gradle.api.Plugin 31 | import org.gradle.api.Project 32 | import org.gradle.kotlin.dsl.getByType 33 | import org.jetbrains.kotlin.gradle.dsl.KotlinCommonToolOptions 34 | import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension 35 | import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension 36 | 37 | @Suppress("UnstableApiUsage") 38 | class ReportGenPlugin : Plugin { 39 | override fun apply(target: Project) { 40 | val reportExt = ComposeCompilerReportExtension.create(target) 41 | var isAppliedForKmp = false 42 | 43 | with(target) { 44 | pluginManager.withPlugin("org.jetbrains.compose") { 45 | isAppliedForKmp = true 46 | pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { 47 | // if kotlin jvm is applied 48 | val jvm = extensions.getByType(KotlinJvmProjectExtension::class.java) 49 | configureKotlinJvmComposeCompilerReports(jvm) 50 | } 51 | pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") { 52 | // if kotlin multiplatform is applied 53 | val multiplatform = extensions.getByType(KotlinMultiplatformExtension::class.java) 54 | configureKotlinMultiplatformComposeCompilerReports(multiplatform) 55 | } 56 | pluginManager.withPlugin("org.jetbrains.kotlin.android") { 57 | // if kotlin android is applied 58 | val android = extensions.getByType(AndroidComponentsExtension::class.java) 59 | configureKotlinAndroidComposeCompilerReports(android) 60 | } 61 | } 62 | var isAppliedForAndroid = false 63 | if (!isAppliedForKmp) { 64 | val android = extensions.getByType(AndroidComponentsExtension::class.java) 65 | pluginManager.withPlugin("com.android.application") { 66 | configureKotlinAndroidComposeCompilerReports(android) 67 | isAppliedForAndroid = true 68 | } 69 | pluginManager.withPlugin("com.android.library") { 70 | configureKotlinAndroidComposeCompilerReports(android) 71 | isAppliedForAndroid = true 72 | } 73 | } 74 | if (!isAppliedForAndroid && !isAppliedForKmp) { 75 | error("Jetpack Compose is not found enabled in this module '$name'") 76 | } 77 | } 78 | } 79 | } 80 | 81 | fun KotlinCommonToolOptions.configureKotlinOptionsForComposeCompilerReport(project: Project) { 82 | val reportExtension = project.extensions.getByType() 83 | val outputPath = reportExtension.composeRawMetricsOutputDirectory.absolutePath 84 | if (reportExtension.enableReport.get()) { 85 | freeCompilerArgs += 86 | listOf( 87 | "-P", 88 | "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=$outputPath", 89 | ) 90 | } 91 | if (reportExtension.enableMetrics.get()) { 92 | freeCompilerArgs += 93 | listOf( 94 | "-P", 95 | "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=$outputPath", 96 | ) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /gradle-plugin/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/plugin/multiplatform/android/configure.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | @file:Suppress("ktlint:standard:filename") 25 | 26 | package dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.multiplatform.android 27 | 28 | import com.android.build.api.dsl.CommonExtension 29 | import com.android.build.api.variant.AndroidComponentsExtension 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.multiplatform.configureKotlinOptionsForComposeCompilerReport 31 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.task.executingComposeCompilerReportGenerationGradleTask 32 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.task.registerComposeCompilerReportGenTaskForVariant 33 | import org.gradle.api.Project 34 | import org.gradle.kotlin.dsl.getByType 35 | import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension 36 | 37 | fun Project.configureKotlinAndroidComposeCompilerReports(android: AndroidComponentsExtension<*, *, *>) { 38 | val commonExtension = 39 | runCatching { extensions.getByType(CommonExtension::class.java) }.getOrNull() 40 | 41 | android.onVariants { variant -> 42 | // Create gradle tasks for generating report 43 | registerComposeCompilerReportGenTaskForVariant(variant) 44 | } 45 | 46 | afterEvaluate { 47 | val isComposeEnabled = commonExtension?.buildFeatures?.compose 48 | 49 | if (isComposeEnabled != true) { 50 | error("Jetpack Compose is not found enabled in this module '$name'") 51 | } 52 | 53 | // When this method returns true it means gradle task for generating report is executing otherwise 54 | // normal compilation task is executing. 55 | val isFromReportGenGradleTask = executingComposeCompilerReportGenerationGradleTask() 56 | if (isFromReportGenGradleTask) { 57 | val kotlinAndroidExt = extensions.getByType() 58 | kotlinAndroidExt.target { 59 | // Exclude for test variants, no use! 60 | configureKotlinOptionsForComposeCompilerReport(compilations) 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /gradle-plugin/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/plugin/multiplatform/configure.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | @file:Suppress("ktlint:standard:filename") 25 | 26 | package dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.multiplatform 27 | 28 | import com.android.build.api.variant.AndroidComponentsExtension 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.configureKotlinOptionsForComposeCompilerReport 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.task.executingComposeCompilerReportGenerationGradleTask 31 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.task.registerComposeCompilerReportGenTaskForTarget 32 | import org.gradle.api.Project 33 | import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension 34 | import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation 35 | 36 | fun Project.configureKotlinMultiplatformComposeCompilerReports(multiplatformExt: KotlinMultiplatformExtension) { 37 | // Create gradle tasks for generating report 38 | multiplatformExt.targets.configureEach { 39 | if (this.name == "metadata") return@configureEach 40 | 41 | if (this.name == "android") { 42 | // register a task for each variant 43 | val androidExt = extensions.getByType(AndroidComponentsExtension::class.java) 44 | androidExt.onVariants { variant -> 45 | registerComposeCompilerReportGenTaskForTarget(this, variant) 46 | } 47 | } else { 48 | registerComposeCompilerReportGenTaskForTarget(this) 49 | } 50 | } 51 | 52 | afterEvaluate { 53 | // When this method returns true it means gradle task for generating report is executing otherwise 54 | // normal compilation task is executing. 55 | val isFromReportGenGradleTask = executingComposeCompilerReportGenerationGradleTask() 56 | if (isFromReportGenGradleTask) { 57 | configureKotlinOptionsForComposeCompilerReport(multiplatformExt.targets.flatMap { it.compilations }) 58 | } 59 | } 60 | } 61 | 62 | fun Project.configureKotlinOptionsForComposeCompilerReport(compilations: Collection>) { 63 | compilations 64 | .filter { compilation -> !compilation.name.endsWith("Test", ignoreCase = true) } 65 | .forEach { 66 | it.kotlinOptions { 67 | configureKotlinOptionsForComposeCompilerReport(this@configureKotlinOptionsForComposeCompilerReport) 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /gradle-plugin/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/plugin/multiplatform/jvm/configure.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | @file:Suppress("ktlint:standard:filename") 25 | 26 | package dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.multiplatform.jvm 27 | 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.multiplatform.configureKotlinOptionsForComposeCompilerReport 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.task.executingComposeCompilerReportGenerationGradleTask 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.task.registerComposeCompilerReportGenTaskForJvmProject 31 | import org.gradle.api.Project 32 | import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension 33 | 34 | fun Project.configureKotlinJvmComposeCompilerReports(jvm: KotlinJvmProjectExtension) { 35 | // Create gradle tasks for generating report 36 | registerComposeCompilerReportGenTaskForJvmProject() 37 | 38 | afterEvaluate { 39 | // When this method returns true it means gradle task for generating report is executing otherwise 40 | // normal compilation task is executing. 41 | val isFromReportGenGradleTask = executingComposeCompilerReportGenerationGradleTask() 42 | if (isFromReportGenGradleTask) { 43 | jvm.target { 44 | configureKotlinOptionsForComposeCompilerReport(compilations) 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /gradle-plugin/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/plugin/task/ComposeCompilerReportGenerateTask.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.task 25 | 26 | import com.android.build.api.variant.Variant 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.ComposeCompilerMetricsProvider 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.ComposeCompilerRawReportProvider 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.HtmlReportGenerator 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.ReportOptions 31 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.ReportSpec 32 | import dev.shreyaspatil.composeCompilerMetricsGenerator.plugin.ComposeCompilerReportExtension 33 | import org.gradle.api.DefaultTask 34 | import org.gradle.api.Project 35 | import org.gradle.api.file.DirectoryProperty 36 | import org.gradle.api.provider.Property 37 | import org.gradle.api.tasks.CacheableTask 38 | import org.gradle.api.tasks.Input 39 | import org.gradle.api.tasks.InputDirectory 40 | import org.gradle.api.tasks.OutputDirectory 41 | import org.gradle.api.tasks.PathSensitive 42 | import org.gradle.api.tasks.PathSensitivity 43 | import org.gradle.api.tasks.TaskAction 44 | import org.gradle.api.tasks.TaskProvider 45 | import org.gradle.tooling.GradleConnector 46 | import org.jetbrains.kotlin.gradle.plugin.KotlinTarget 47 | import java.io.File 48 | import java.io.FileNotFoundException 49 | 50 | const val KEY_ENABLE_REPORT_GEN = "dev.shreyaspatil.composeCompiler.reportGen.enable" 51 | 52 | @CacheableTask 53 | abstract class ComposeCompilerReportGenerateTask : DefaultTask() { 54 | @get:InputDirectory 55 | @get:PathSensitive(PathSensitivity.RELATIVE) 56 | abstract val projectDirectory: DirectoryProperty 57 | 58 | @get:Input 59 | abstract val compileKotlinTasks: Property 60 | 61 | @get:Input 62 | abstract val reportName: Property 63 | 64 | @get:OutputDirectory 65 | abstract val composeRawMetricsOutputDirectory: DirectoryProperty 66 | 67 | @get:OutputDirectory 68 | abstract val outputDirectory: DirectoryProperty 69 | 70 | @get:Input 71 | abstract val includeStableComposables: Property 72 | 73 | @get:Input 74 | abstract val includeStableClasses: Property 75 | 76 | @get:Input 77 | abstract val includeClasses: Property 78 | 79 | @get:Input 80 | abstract val showOnlyUnstableComposables: Property 81 | 82 | @TaskAction 83 | fun generate() { 84 | val outputDirectory = outputDirectory.get().asFile 85 | cleanupDirectory(outputDirectory) 86 | 87 | generateRawMetricsAndReport() 88 | 89 | generateReport(outputDirectory) 90 | } 91 | 92 | private fun generateRawMetricsAndReport() { 93 | GradleConnector 94 | .newConnector() 95 | .forProjectDirectory(projectDirectory.get().asFile) 96 | .connect() 97 | .use { 98 | it 99 | .newBuild() 100 | .setStandardOutput(System.out) 101 | .setStandardError(System.err) 102 | .setStandardInput(System.`in`) 103 | .forTasks(compileKotlinTasks.get()) 104 | .withArguments( 105 | // Re-running is necessary. In case devs deleted raw files and if task uses cache 106 | // then this task will explode 💣 107 | "--rerun-tasks", 108 | // Signal for enabling report generation in `kotlinOptions{}` block. 109 | "-P$KEY_ENABLE_REPORT_GEN=true", 110 | ).run() 111 | } 112 | } 113 | 114 | private fun generateReport(outputDirectory: File) { 115 | // Create a report specification with application name 116 | val reportSpec = 117 | ReportSpec( 118 | name = reportName.get(), 119 | options = 120 | ReportOptions( 121 | includeStableComposables = includeStableComposables.get(), 122 | includeStableClasses = includeStableClasses.get(), 123 | includeClasses = includeClasses.get(), 124 | showOnlyUnstableComposables = showOnlyUnstableComposables.get(), 125 | ), 126 | ) 127 | 128 | val rawReportProvider = 129 | ComposeCompilerRawReportProvider.FromDirectory( 130 | directory = composeRawMetricsOutputDirectory.get().asFile, 131 | ) 132 | 133 | // Provide metric files to generator 134 | val htmlGenerator = 135 | HtmlReportGenerator( 136 | reportSpec = reportSpec, 137 | metricsProvider = ComposeCompilerMetricsProvider(rawReportProvider), 138 | ) 139 | 140 | // Generate HTML (as String) 141 | val html = htmlGenerator.generateHtml() 142 | 143 | // Create a report file 144 | val file = outputDirectory.resolve("index.html") 145 | file.writeText(html) 146 | 147 | val reportUrl = file.toURI().toURL().toExternalForm() 148 | logger.quiet("Compose Compiler report is generated: $reportUrl") 149 | } 150 | 151 | private fun cleanupDirectory(outputDirectory: File) { 152 | if (outputDirectory.exists()) { 153 | if (!outputDirectory.isDirectory) { 154 | throw FileNotFoundException("'$outputDirectory' is not a directory") 155 | } 156 | } 157 | 158 | outputDirectory.deleteRecursively() 159 | } 160 | } 161 | 162 | /** 163 | * Register a task for generating Compose Compiler Report for a Kotlin Multiplatform Android target. 164 | * @param target Kotlin Target for which report is to be generated 165 | * @param variant Android Variant for which report is to be generated 166 | */ 167 | fun Project.registerComposeCompilerReportGenTaskForTarget( 168 | target: KotlinTarget, 169 | variant: Variant? = null, 170 | ): TaskProvider { 171 | val variantName = variant?.name?.let { it[0].uppercaseChar() + it.substring(1) } ?: "" 172 | val taskName = target.name + variantName + "ComposeCompilerHtmlReport" 173 | val compileKotlinTaskName = compileKotlinTaskNameFromTarget(target, variantName) 174 | val descSuffix = 175 | buildString { 176 | append("'${target.name}' target") 177 | if (variant != null) { 178 | append(" '${variant.name}' variant") 179 | } 180 | append(" in multiplatform project") 181 | } 182 | return registerComposeCompilerReportGenTask(taskName, compileKotlinTaskName, descSuffix) 183 | } 184 | 185 | /** 186 | * Register a task for generating Compose Compiler Report for JVM variant. 187 | */ 188 | fun Project.registerComposeCompilerReportGenTaskForJvmProject(): TaskProvider { 189 | val taskName = "jvmComposeCompilerHtmlReport" 190 | val compileKotlinTaskName = "compileKotlin" 191 | val descSuffix = "'Jvm/Desktop' Project" 192 | return registerComposeCompilerReportGenTask(taskName, compileKotlinTaskName, descSuffix) 193 | } 194 | 195 | /** 196 | * Register a task for generating Compose Compiler Report for Android variant. 197 | */ 198 | fun Project.registerComposeCompilerReportGenTaskForVariant(variant: Variant): TaskProvider { 199 | val taskName = variant.name + "ComposeCompilerHtmlReport" 200 | val compileKotlinTaskName = compileKotlinTaskNameFromVariant(variant) 201 | val descSuffix = "'${variant.name}' variant in Android project" 202 | return registerComposeCompilerReportGenTask(taskName, compileKotlinTaskName, descSuffix) 203 | } 204 | 205 | /** 206 | * Register a task for generating Compose Compiler Report. 207 | * @param taskName Name of the task 208 | * @param compileKotlinTaskName Name of the compileKotlin task 209 | * @param descSuffix Description suffix 210 | */ 211 | fun Project.registerComposeCompilerReportGenTask( 212 | taskName: String, 213 | compileKotlinTaskName: String, 214 | descSuffix: String, 215 | ): TaskProvider { 216 | val reportExtension = ComposeCompilerReportExtension.get(project) 217 | 218 | return tasks.register(taskName, ComposeCompilerReportGenerateTask::class.java) { 219 | projectDirectory.set(layout.projectDirectory) 220 | compileKotlinTasks.set(compileKotlinTaskName) 221 | reportName.set(reportExtension.name) 222 | composeRawMetricsOutputDirectory.set(reportExtension.composeRawMetricsOutputDirectory) 223 | outputDirectory.set(layout.dir(reportExtension.outputDirectory)) 224 | includeStableComposables.set(reportExtension.includeStableComposables) 225 | includeStableClasses.set(reportExtension.includeStableClasses) 226 | includeClasses.set(reportExtension.includeClasses) 227 | showOnlyUnstableComposables.set(reportExtension.showOnlyUnstableComposables) 228 | 229 | group = "compose compiler report" 230 | description = "Generate Compose Compiler Metrics and Report for $descSuffix" 231 | } 232 | } 233 | 234 | /** 235 | * Returns true if currently executing task is about generating compose compiler report 236 | */ 237 | fun Project.executingComposeCompilerReportGenerationGradleTask() = 238 | runCatching { 239 | property(KEY_ENABLE_REPORT_GEN) 240 | }.getOrNull() == "true" 241 | 242 | /** 243 | * Returns a task name for compileKotlin with [variant] 244 | */ 245 | fun compileKotlinTaskNameFromVariant(variant: Variant): String { 246 | val variantName = variant.name.let { it[0].toUpperCase() + it.substring(1) } 247 | return "compile${variantName}Kotlin" 248 | } 249 | 250 | /** 251 | * Returns a task name for compileKotlin with [target] 252 | */ 253 | fun compileKotlinTaskNameFromTarget( 254 | target: KotlinTarget, 255 | variantName: String, 256 | ): String { 257 | val targetName = target.name.let { it[0].toUpperCase() + it.substring(1) } 258 | return "compile${variantName}Kotlin$targetName" 259 | } 260 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | 3 | GROUP=dev.shreyaspatil.compose-compiler-report-generator 4 | VERSION_NAME=1.4.2 5 | 6 | # Library configuration 7 | SONATYPE_HOST=DEFAULT 8 | RELEASE_SIGNING_ENABLED=true 9 | 10 | POM_INCEPTION_YEAR=2023 11 | POM_URL=https://github.com/PatilShreyas/compose-report-to-html/ 12 | 13 | POM_LICENSE_NAME=MIT 14 | POM_LICENSE_URL=https://raw.githubusercontent.com/PatilShreyas/compose-report-to-html/main/LICENSE 15 | POM_LICENSE_DIST=repo 16 | 17 | POM_SCM_URL=https://github.com/PatilShreyas/compose-report-to-html/ 18 | POM_SCM_CONNECTION=scm:git:git://github.com/PatilShreyas/compose-report-to-html.git 19 | POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/PatilShreyas/compose-report-to-html.git 20 | 21 | POM_DEVELOPER_ID=PatilShreyas 22 | POM_DEVELOPER_NAME=Shreyas Patil 23 | POM_DEVELOPER_URL=https://github.com/PatilShreyas/ -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | kotlin = "2.1.20" 3 | serialization = "1.8.1" 4 | coroutines = "1.10.2" 5 | spotless = "7.0.3" 6 | kotlinxHtml = "0.12.0" 7 | kotlinxCli = "0.3.6" 8 | compose = "1.8.1" 9 | mavenPublish = "0.31.0" 10 | androidGradlePlugin = "8.9.2" 11 | gradlePluginPublish = "1.3.1" 12 | 13 | [libraries] 14 | kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" } 15 | kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } 16 | kotlinx-html-jvm = { module = "org.jetbrains.kotlinx:kotlinx-html-jvm", version.ref = "kotlinxHtml" } 17 | kotlinx-cli = { module = "org.jetbrains.kotlinx:kotlinx-cli", version.ref = "kotlinxCli" } 18 | android-gradle-plugin = { module = "com.android.tools.build:gradle", version.ref = "androidGradlePlugin" } 19 | kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } 20 | compose-multiplatform-gradle-plugin = { module = "org.jetbrains.compose:compose-gradle-plugin", version.ref = "compose" } 21 | 22 | [plugins] 23 | spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } 24 | mavenPublish = { id = "com.vanniktech.maven.publish", version.ref = "mavenPublish" } 25 | gradle-plugin-publish = { id = "com.gradle.plugin-publish", version.ref = "gradlePluginPublish" } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatilShreyas/compose-report-to-html/4d8d01495045ec4532e629865453445bcabe6188/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.7-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /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/master/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 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || 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 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /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 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | # Project 2 | site_name: Compose Compiler Report to HTML 3 | site_description: 'Utility to convert Jetpack Compose compiler metrics and reports to beautified 😍 HTML page' 4 | site_author: 'PatilShreyas' 5 | site_url: 'https://github.com/PatilShreyas/compose-report-to-html' 6 | edit_uri: 'tree/main/docs/' 7 | remote_branch: gh-pages 8 | 9 | # Repository 10 | repo_name: 'Compose Report to HTML' 11 | repo_url: https://github.com/PatilShreyas/compose-report-to-html 12 | 13 | theme: 14 | name: material 15 | palette: 16 | primary: white 17 | accent: red 18 | icon: 19 | repo: fontawesome/brands/github 20 | font: 21 | text: 'Roboto' 22 | code: 'JetBrains Mono' 23 | features: 24 | - content.action.edit 25 | - content.code.copy 26 | - content.tabs.link 27 | 28 | plugins: 29 | - search 30 | 31 | markdown_extensions: 32 | # Admonitions 33 | - admonition 34 | - pymdownx.details 35 | 36 | # Code highlight 37 | - pymdownx.highlight: 38 | anchor_linenums: true 39 | - pymdownx.inlinehilite 40 | - pymdownx.snippets 41 | - pymdownx.superfences 42 | 43 | # Tabs 44 | - pymdownx.superfences 45 | - pymdownx.tabbed: 46 | alternate_style: true 47 | 48 | - toc: 49 | permalink: true 50 | 51 | # For images 52 | - attr_list 53 | - md_in_html 54 | 55 | # Navigation 56 | nav: 57 | - 'Overview': index.md 58 | - 'How to use?': 59 | - 'Gradle Plugin': use/using-gradle-plugin.md 60 | - 'CLI': use/using-cli.md 61 | - 'Library': use/using-utility-as-library.md -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "bin": { 3 | "composeReport2Html": "jdeploy-bundle/jdeploy.js" 4 | }, 5 | "author": "Shreyas Patil", 6 | "description": "CLI utility to convert Jetpack Compose metrics and report to beautified HTML page", 7 | "main": "index.js", 8 | "preferGlobal": true, 9 | "repository": "https://github.com/PatilShreyas/compose-report-to-html", 10 | "version": "1.4.2", 11 | "jdeploy": { 12 | "jdk": false, 13 | "javaVersion": "11", 14 | "jar": "cli/build/libs/cli.jar", 15 | "javafx": false, 16 | "title": "Compose Report to HTML Generator" 17 | }, 18 | "dependencies": { 19 | "node-fetch": "^2.6.7", 20 | "njre": "^1.1.0", 21 | "shelljs": "^0.8.4" 22 | }, 23 | "license": "MIT", 24 | "name": "compose-report2html", 25 | "files": [ 26 | "jdeploy-bundle", 27 | "images/*" 28 | ], 29 | "scripts": { 30 | "test": "echo \"Error: no test specified\" && exit 1" 31 | }, 32 | "homepage": "https://patilshreyas.github.io/compose-report-to-html/", 33 | "keywords": [ 34 | "android", 35 | "jetpack-compose", 36 | "compose-compiler", 37 | "report", 38 | "kotlin", 39 | "androidx", 40 | "jetpack" 41 | ], 42 | "funding": { 43 | "type": "individual", 44 | "url": "https://github.com/sponsors/PatilShreyas/" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /report-generator/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") 3 | id(libs.plugins.mavenPublish.get().pluginId) 4 | } 5 | repositories { 6 | mavenCentral() 7 | } 8 | 9 | dependencies { 10 | implementation(project(":core")) 11 | implementation(kotlin("stdlib")) 12 | 13 | implementation(libs.kotlinx.coroutines.core) 14 | implementation(libs.kotlinx.html.jvm) 15 | } 16 | -------------------------------------------------------------------------------- /report-generator/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=report-generator 2 | POM_NAME=Compose Report to HTML - Report generator 3 | POM_DESCRIPTION=Generates HTML report from raw Compose report. -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/HtmlReportGenerator.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.ComposeCompilerMetricsProvider 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.DetailedStatistics 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.classes.ClassesReport 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.composables.ComposablesReport 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.utils.camelCaseToWord 31 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.MainContent 32 | import kotlinx.coroutines.Dispatchers 33 | import kotlinx.coroutines.async 34 | import kotlinx.coroutines.runBlocking 35 | import kotlinx.html.html 36 | import kotlinx.html.stream.createHTML 37 | 38 | /** 39 | * Generates HTML content of a report using [metricsProvider] 40 | */ 41 | class HtmlReportGenerator( 42 | private val reportSpec: ReportSpec, 43 | private val metricsProvider: ComposeCompilerMetricsProvider, 44 | ) { 45 | /** 46 | * Returns HTML content as a [String] 47 | */ 48 | fun generateHtml(): String = 49 | runBlocking(Dispatchers.Default) { 50 | val deferredOverallStatistics = 51 | async { 52 | metricsProvider.getOverallStatistics().map { (name, value) -> camelCaseToWord(name) to value }.toMap() 53 | } 54 | val deferredDetailedStatistics = async { metricsProvider.getDetailedStatistics() } 55 | val deferredComposablesReport = async { metricsProvider.getComposablesReport() } 56 | val deferredClassesReport = async { metricsProvider.getClassesReport() } 57 | 58 | val overallStatistics = deferredOverallStatistics.await() 59 | val detailedStatistics = deferredDetailedStatistics.await() 60 | val composablesReport = deferredComposablesReport.await() 61 | val classesReport = deferredClassesReport.await() 62 | 63 | return@runBlocking reportPageHtml(overallStatistics, detailedStatistics, composablesReport, classesReport) 64 | } 65 | 66 | private fun reportPageHtml( 67 | overallStatistics: Map, 68 | detailedStatistics: DetailedStatistics, 69 | composablesReport: ComposablesReport, 70 | classesReport: ClassesReport, 71 | ) = createHTML().html { 72 | MainContent( 73 | reportSpec = reportSpec, 74 | overallStatistics = overallStatistics, 75 | detailedStatistics = detailedStatistics, 76 | composablesReport = composablesReport, 77 | classesReport = classesReport, 78 | ) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/ReportSpec.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator 25 | 26 | /** 27 | * Specification of a report 28 | */ 29 | data class ReportSpec( 30 | val name: String, 31 | val options: ReportOptions = ReportOptions(), 32 | ) 33 | 34 | /** 35 | * Options for a report 36 | */ 37 | data class ReportOptions( 38 | val includeStableComposables: Boolean = true, 39 | val includeStableClasses: Boolean = true, 40 | val includeClasses: Boolean = true, 41 | val showOnlyUnstableComposables: Boolean = false, 42 | ) 43 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/BriefStatistics.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.CollapsibleContent 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.EmptyContent 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.setStyle 29 | import kotlinx.html.FlowContent 30 | import kotlinx.html.section 31 | import kotlinx.html.table 32 | import kotlinx.html.td 33 | import kotlinx.html.th 34 | import kotlinx.html.tr 35 | 36 | @Suppress("ktlint:standard:function-naming") 37 | fun FlowContent.BriefStatistics(overallStatistics: Map) { 38 | if (overallStatistics.isEmpty()) { 39 | EmptyContent("No overall metrics") 40 | return 41 | } 42 | section { 43 | CollapsibleContent("Brief Statistics") { 44 | table("center") { 45 | setStyle(textAlign = "left") 46 | overallStatistics.forEach { (header, value) -> 47 | tr { 48 | th { 49 | +header 50 | } 51 | td { 52 | +value.toString() 53 | } 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/ClassReport.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.Condition 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.classes.ClassDetail 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.classes.ClassesReport 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.CheckIconWithText 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.CollapsibleContent 31 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.CrossIconWithText 32 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.EmptyContent 33 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.Colors 34 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.setStyle 35 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.statusCssClass 36 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.utils.forEachIndexedFromOne 37 | import kotlinx.html.FlowContent 38 | import kotlinx.html.br 39 | import kotlinx.html.div 40 | import kotlinx.html.h3 41 | import kotlinx.html.section 42 | import kotlinx.html.span 43 | import kotlinx.html.table 44 | import kotlinx.html.td 45 | import kotlinx.html.th 46 | import kotlinx.html.tr 47 | 48 | @Suppress("ktlint:standard:function-naming") 49 | fun FlowContent.ClassesReport( 50 | includeStableClasses: Boolean, 51 | report: ClassesReport, 52 | ) { 53 | if (report.classes.isEmpty()) { 54 | EmptyContent("No Class Report") 55 | return 56 | } 57 | section { 58 | div { 59 | CollapsibleContent("Classes Report") { 60 | if (report.unstableClasses.isNotEmpty()) { 61 | CollapsibleContent( 62 | summary = "Unstable Classes", 63 | summaryAttr = { 64 | setStyle( 65 | backgroundColor = Colors.RED_DARK, 66 | fontSize = "18px", 67 | ) 68 | }, 69 | ) { 70 | setStyle(backgroundColor = Colors.PINK_LIGHT) 71 | ClassesReport(report.unstableClasses) 72 | } 73 | } else { 74 | EmptyContent("No Unstable classes found") 75 | } 76 | 77 | if (report.stableClasses.isNotEmpty() && includeStableClasses) { 78 | CollapsibleContent( 79 | summary = "Stable Classes", 80 | summaryAttr = { 81 | setStyle( 82 | backgroundColor = Colors.GREEN_DARK, 83 | fontSize = "18px", 84 | ) 85 | }, 86 | ) { 87 | setStyle(backgroundColor = Colors.ALABASTER) 88 | ClassesReport(report.stableClasses) 89 | } 90 | } else { 91 | br { } 92 | val message = 93 | if (!includeStableClasses) { 94 | "Report for stable classes is disabled in the options" 95 | } else { 96 | "No Stable classes found" 97 | } 98 | EmptyContent(message) 99 | } 100 | } 101 | } 102 | } 103 | } 104 | 105 | @Suppress("ktlint:standard:function-naming") 106 | fun FlowContent.ClassesReport(classes: List) = 107 | table { 108 | classes.forEachIndexedFromOne { index, detail -> 109 | tr { 110 | td { 111 | +"$index." 112 | } 113 | td { 114 | h3 { 115 | span(statusCssClass(detail.stability === Condition.STABLE)) { 116 | when (detail.stability) { 117 | Condition.STABLE -> CheckIconWithText("Stable") 118 | Condition.UNSTABLE -> CrossIconWithText("Unstable") 119 | else -> +"Missing" 120 | } 121 | } 122 | span("code") { +" class ${detail.className}" } 123 | } 124 | table { 125 | if (detail.fields.isNotEmpty()) { 126 | tr { 127 | th { +"No." } 128 | th { +"Status" } 129 | th { +"Field" } 130 | th { +"Type" } 131 | } 132 | detail.fields.forEachIndexedFromOne { index, field -> 133 | tr { 134 | setStyle( 135 | backgroundColor = statusColorFrom(field.status), 136 | color = textColorFrom(field.status), 137 | ) 138 | td { +index.toString() } 139 | td { +field.status.uppercase() } 140 | td("code") { +field.name } 141 | td("code") { +field.type } 142 | } 143 | } 144 | } 145 | } 146 | } 147 | } 148 | } 149 | } 150 | 151 | fun statusColorFrom(status: String) = 152 | when (status.lowercase()) { 153 | "stable" -> Colors.GREEN_LIGHT 154 | "unstable" -> Colors.RED_DARK 155 | else -> Colors.YELLOW 156 | } 157 | 158 | fun textColorFrom(status: String) = 159 | when (status.lowercase()) { 160 | "unstable" -> Colors.WHITE 161 | else -> Colors.BLACK 162 | } 163 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/ComposableReport.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.Condition 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.composables.ComposableDetail 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.composables.ComposablesReport 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.CheckIconWithText 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.CollapsibleContent 31 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.CrossIconWithText 32 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.EmptyContent 33 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.Colors 34 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.setStyle 35 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.utils.forEachIndexedFromOne 36 | import kotlinx.html.BODY 37 | import kotlinx.html.FlowContent 38 | import kotlinx.html.br 39 | import kotlinx.html.h3 40 | import kotlinx.html.h4 41 | import kotlinx.html.section 42 | import kotlinx.html.span 43 | import kotlinx.html.table 44 | import kotlinx.html.td 45 | import kotlinx.html.th 46 | import kotlinx.html.tr 47 | 48 | @Suppress("ktlint:standard:function-naming") 49 | fun BODY.ComposablesReport( 50 | includeStableComposables: Boolean, 51 | onlyUnstableComposables: Boolean = false, 52 | composablesReport: ComposablesReport, 53 | ) { 54 | if (composablesReport.composables.isEmpty()) { 55 | EmptyContent("No Composables Report") 56 | return 57 | } 58 | section { 59 | if (onlyUnstableComposables) { 60 | setStyle(backgroundColor = Colors.PINK_LIGHT, padding = "16px") 61 | ComposablesReport(composablesReport.restartableButNotSkippableComposables) 62 | return@section 63 | } 64 | CollapsibleContent("Composables Report") { 65 | if (composablesReport.restartableButNotSkippableComposables.isNotEmpty()) { 66 | CollapsibleContent( 67 | summary = "Composables with issues (Restartable but Not Skippable)", 68 | summaryAttr = { 69 | setStyle(backgroundColor = Colors.RED_DARK, fontSize = "18px") 70 | }, 71 | ) { 72 | setStyle(backgroundColor = Colors.PINK_LIGHT) 73 | ComposablesReport(composablesReport.restartableButNotSkippableComposables) 74 | } 75 | } else { 76 | EmptyContent("No composable found with issues 😁") 77 | } 78 | 79 | if (composablesReport.nonIssuesComposables.isNotEmpty() && includeStableComposables) { 80 | CollapsibleContent( 81 | summary = "Composibles without issues", 82 | summaryAttr = { 83 | setStyle(backgroundColor = Colors.GREEN_DARK, fontSize = "18px") 84 | }, 85 | ) { 86 | setStyle(backgroundColor = Colors.ALABASTER) 87 | ComposablesReport(composablesReport.nonIssuesComposables) 88 | } 89 | } else { 90 | br { } 91 | val message = 92 | if (!includeStableComposables) { 93 | "Report for stable composables is disabled in the options" 94 | } else { 95 | "No composable found without any issues" 96 | } 97 | EmptyContent(message) 98 | } 99 | } 100 | } 101 | } 102 | 103 | @Suppress("ktlint:standard:function-naming") 104 | fun FlowContent.ComposablesReport(composables: List) = 105 | table { 106 | composables.forEachIndexedFromOne { index, detail -> 107 | tr { 108 | td { 109 | +"$index." 110 | } 111 | td { 112 | h3("code") { 113 | if (detail.isInline) { 114 | +"inline" 115 | } 116 | span { +" fun ${detail.functionName}" } 117 | } 118 | h4 { 119 | span(if (detail.isSkippable) "status-success" else "status-failure") { 120 | if (detail.isSkippable) { 121 | CheckIconWithText("Skippable") 122 | } else { 123 | CrossIconWithText("Non Skippable") 124 | } 125 | } 126 | span(if (detail.isRestartable) "status-success" else "status-failure") { 127 | if (detail.isRestartable) { 128 | CheckIconWithText("Restartable") 129 | } else { 130 | CrossIconWithText("Non Restartable") 131 | } 132 | } 133 | } 134 | table { 135 | if (detail.params.isNotEmpty()) { 136 | tr { 137 | th { +"No." } 138 | th { +"Stability" } 139 | th { +"Parameter" } 140 | th { +"Type" } 141 | } 142 | detail.params.forEachIndexedFromOne { index, param -> 143 | tr( 144 | when (param.condition) { 145 | Condition.STABLE -> "background-status-success" 146 | Condition.UNSTABLE -> "background-status-failure" 147 | Condition.MISSING -> "background-status-missing" 148 | }, 149 | ) { 150 | td { +index.toString() } 151 | td { +param.condition.toString() } 152 | td("code") { +param.name } 153 | td("code") { +param.type } 154 | } 155 | } 156 | } 157 | } 158 | } 159 | } 160 | } 161 | } 162 | 163 | @Suppress("ktlint:standard:function-naming") 164 | fun BODY.OnlyUnstableComposables(composablesReport: ComposablesReport) { 165 | h3 { +"Composables with issues (Restartable but Not Skippable)" } 166 | ComposablesReport( 167 | includeStableComposables = false, 168 | onlyUnstableComposables = true, 169 | composablesReport = composablesReport, 170 | ) 171 | } 172 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/DetailedStatistics.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.DetailedStatistics 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.CollapsibleContent 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.EmptyContent 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.setStyle 30 | import kotlinx.html.FlowContent 31 | import kotlinx.html.section 32 | import kotlinx.html.table 33 | import kotlinx.html.td 34 | import kotlinx.html.th 35 | import kotlinx.html.tr 36 | 37 | @Suppress("ktlint:standard:function-naming") 38 | fun FlowContent.DetailedStatistics(detailedStatistics: DetailedStatistics) { 39 | if (detailedStatistics.items.isEmpty()) { 40 | EmptyContent("No Detailed Statistics") 41 | return 42 | } 43 | section { 44 | CollapsibleContent("Detailed Statistics") { 45 | table { 46 | setStyle(width = "100%") 47 | 48 | tr { 49 | detailedStatistics.headers.forEach { header -> 50 | th { +header } 51 | } 52 | } 53 | 54 | detailedStatistics.items.forEach { 55 | tr { 56 | it.item.map { it.value }.forEach { value -> 57 | td { +value } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/ErrorReports.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.exception.ParsingException 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common.CollapsibleContent 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.Colors 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.setStyle 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.utils.forEachIndexedFromOne 31 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.utils.lines 32 | import kotlinx.html.FlowContent 33 | import kotlinx.html.a 34 | import kotlinx.html.b 35 | import kotlinx.html.br 36 | import kotlinx.html.i 37 | import kotlinx.html.p 38 | 39 | @Suppress("ktlint:standard:function-naming") 40 | fun FlowContent.ErrorReports(errors: List) { 41 | if (errors.isNotEmpty()) { 42 | i { 43 | +"These below errors were occurred while generating this report" 44 | a( 45 | href = "https://github.com/PatilShreyas/compose-report-to-html/issues", 46 | target = "_blank", 47 | ) { +" Please report issues here" } 48 | } 49 | errors.forEachIndexedFromOne { index, error -> 50 | CollapsibleContent( 51 | summary = "$index. ${error.message ?: "Unknown error"}", 52 | summaryAttr = { 53 | setStyle(backgroundColor = Colors.RED_DARK, color = Colors.WHITE, margin = "4px", fontSize = "14px") 54 | }, 55 | ) { 56 | p("code") { 57 | setStyle( 58 | backgroundColor = Colors.PINK_LIGHT, 59 | fontSize = "14px", 60 | color = Colors.BLACK, 61 | textAlign = "left", 62 | padding = "8px", 63 | ) 64 | 65 | error.stackTraceToString().lines().forEach { line -> 66 | +line 67 | br { } 68 | } 69 | 70 | br { } 71 | b { +"The content was:" } 72 | 73 | br { } 74 | error.content.lines().forEach { line -> 75 | +line 76 | br { } 77 | } 78 | } 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/Footer.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content 25 | 26 | import kotlinx.html.BODY 27 | import kotlinx.html.a 28 | import kotlinx.html.footer 29 | import kotlinx.html.i 30 | 31 | @Suppress("ktlint:standard:function-naming") 32 | fun BODY.Footer() { 33 | footer { 34 | i { 35 | +"This report is beautified with " 36 | a( 37 | href = "https://github.com/PatilShreyas/compose-report-to-html", 38 | target = "_blank", 39 | ) { +"Compose Report to HTML" } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/MainContent.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.DetailedStatistics 27 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.classes.ClassesReport 28 | import dev.shreyaspatil.composeCompilerMetricsGenerator.core.model.composables.ComposablesReport 29 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.ReportSpec 30 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.script.CollapsibleScript 31 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.FontsLinking 32 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.PageStyle 33 | import kotlinx.html.HTML 34 | import kotlinx.html.body 35 | import kotlinx.html.h1 36 | import kotlinx.html.head 37 | import kotlinx.html.hr 38 | import kotlinx.html.title 39 | 40 | @Suppress("ktlint:standard:function-naming") 41 | fun HTML.MainContent( 42 | reportSpec: ReportSpec, 43 | overallStatistics: Map, 44 | detailedStatistics: DetailedStatistics, 45 | composablesReport: ComposablesReport, 46 | classesReport: ClassesReport, 47 | ) { 48 | val options = reportSpec.options 49 | head { 50 | title("${reportSpec.name} - Compose Compiler Report") 51 | FontsLinking() 52 | PageStyle() 53 | } 54 | body { 55 | h1 { +"Compose Compiler Report - ${reportSpec.name}" } 56 | if (options.showOnlyUnstableComposables) { 57 | OnlyUnstableComposables(composablesReport) 58 | } else { 59 | BriefStatistics(overallStatistics) 60 | hr { } 61 | DetailedStatistics(detailedStatistics) 62 | hr { } 63 | ComposablesReport( 64 | includeStableComposables = options.includeStableComposables, 65 | composablesReport = composablesReport, 66 | ) 67 | hr { } 68 | if (options.includeClasses) { 69 | ClassesReport(options.includeStableClasses, classesReport) 70 | hr { } 71 | } 72 | } 73 | ErrorReports(composablesReport.errors + classesReport.errors) 74 | Footer() 75 | CollapsibleScript() 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/common/CollapsibleContent.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common 25 | 26 | import kotlinx.html.DIV 27 | import kotlinx.html.FlowContent 28 | import kotlinx.html.button 29 | import kotlinx.html.div 30 | import kotlinx.html.impl.DelegatingMap 31 | 32 | @Suppress("ktlint:standard:function-naming") 33 | fun FlowContent.CollapsibleContent( 34 | summary: String, 35 | summaryAttr: DelegatingMap.() -> Unit = {}, 36 | content: DIV.() -> Unit, 37 | ) { 38 | button(classes = "collapsible") { 39 | attributes.apply(summaryAttr) 40 | +summary 41 | } 42 | div("content", block = content) 43 | } 44 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/common/EmptyContent.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common 25 | 26 | import kotlinx.html.FlowContent 27 | import kotlinx.html.div 28 | 29 | @Suppress("ktlint:standard:function-naming") 30 | fun FlowContent.EmptyContent(text: String) { 31 | div("empty-content") { +text } 32 | } 33 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/common/IconText.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.setStyle 27 | import kotlinx.html.FlowOrPhrasingContent 28 | import kotlinx.html.SPAN 29 | import kotlinx.html.span 30 | 31 | @Suppress("ktlint:standard:function-naming") 32 | fun FlowOrPhrasingContent.IconWithText( 33 | icon: SPAN.() -> Unit, 34 | text: String, 35 | fontSize: String = "18px", 36 | ) { 37 | span { 38 | setStyle(alignItems = "center", display = "flex", fontSize = fontSize) 39 | 40 | icon() 41 | +text 42 | } 43 | } 44 | 45 | @Suppress("ktlint:standard:function-naming") 46 | fun FlowOrPhrasingContent.CrossIconWithText( 47 | text: String, 48 | fontSize: String = "18px", 49 | ) { 50 | IconWithText( 51 | icon = { 52 | cross(width = fontSize, height = fontSize) 53 | }, 54 | text = text, 55 | fontSize = fontSize, 56 | ) 57 | } 58 | 59 | @Suppress("ktlint:standard:function-naming") 60 | fun FlowOrPhrasingContent.CheckIconWithText( 61 | text: String, 62 | fontSize: String = "18px", 63 | ) { 64 | IconWithText( 65 | icon = { 66 | check(width = fontSize, height = fontSize) 67 | }, 68 | text = text, 69 | fontSize = fontSize, 70 | ) 71 | } 72 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/common/Icons.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | @file:Suppress("ktlint:standard:max-line-length") 25 | /** 26 | * MIT License 27 | * 28 | * Copyright (c) 2022 Shreyas Patil 29 | * 30 | * Permission is hereby granted, free of charge, to any person obtaining a copy 31 | * of this software and associated documentation files (the "Software"), to deal 32 | * in the Software without restriction, including without limitation the rights 33 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 34 | * copies of the Software, and to permit persons to whom the Software is 35 | * furnished to do so, subject to the following conditions: 36 | * 37 | * The above copyright notice and this permission notice shall be included in all 38 | * copies or substantial portions of the Software. 39 | * 40 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 43 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 44 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 45 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 46 | * SOFTWARE. 47 | */ 48 | 49 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common 50 | 51 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.Colors 52 | import kotlinx.html.FlowOrPhrasingContent 53 | 54 | fun FlowOrPhrasingContent.cross( 55 | width: String, 56 | height: String, 57 | fill: String = Colors.RED_DARK, 58 | ) { 59 | SvgIcon( 60 | width = width, 61 | height = height, 62 | viewBox = "0 0 24 24", 63 | fill = "none", 64 | fillRule = "evenodd", 65 | clipRule = "evenodd", 66 | d = "M11 13C11 13.5523 11.4477 14 12 14C12.5523 14 13 13.5523 13 13V10C13 9.44772 12.5523 9 12 9C11.4477 9 11 9.44772 11 10V13ZM13 15.9888C13 15.4365 12.5523 14.9888 12 14.9888C11.4477 14.9888 11 15.4365 11 15.9888V16C11 16.5523 11.4477 17 12 17C12.5523 17 13 16.5523 13 16V15.9888ZM9.37735 4.66136C10.5204 2.60393 13.4793 2.60393 14.6223 4.66136L21.2233 16.5431C22.3341 18.5427 20.8882 21 18.6008 21H5.39885C3.11139 21 1.66549 18.5427 2.77637 16.5431L9.37735 4.66136Z", 67 | pathFill = fill, 68 | ) 69 | } 70 | 71 | fun FlowOrPhrasingContent.check( 72 | width: String, 73 | height: String, 74 | fill: String = Colors.GREEN_DARK, 75 | ) { 76 | SvgIcon( 77 | width = width, 78 | height = height, 79 | viewBox = "0 0 24 24", 80 | fill = "none", 81 | fillRule = "evenodd", 82 | clipRule = "evenodd", 83 | d = "M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM16.0303 8.96967C16.3232 9.26256 16.3232 9.73744 16.0303 10.0303L11.0303 15.0303C10.7374 15.3232 10.2626 15.3232 9.96967 15.0303L7.96967 13.0303C7.67678 12.7374 7.67678 12.2626 7.96967 11.9697C8.26256 11.6768 8.73744 11.6768 9.03033 11.9697L10.5 13.4393L12.7348 11.2045L14.9697 8.96967C15.2626 8.67678 15.7374 8.67678 16.0303 8.96967Z", 84 | pathFill = fill, 85 | ) 86 | } 87 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/content/common/Svg.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.content.common 25 | 26 | import dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style.setStyle 27 | import kotlinx.html.FlowOrPhrasingContent 28 | import kotlinx.html.HTMLTag 29 | import kotlinx.html.HtmlInlineTag 30 | import kotlinx.html.TagConsumer 31 | import kotlinx.html.svg 32 | import kotlinx.html.visit 33 | 34 | /** 35 | * Acts as a SVG Icon HTML element 36 | */ 37 | @Suppress("ktlint:standard:function-naming") 38 | fun FlowOrPhrasingContent.SvgIcon( 39 | width: String, 40 | height: String, 41 | viewBox: String, 42 | fill: String, 43 | fillRule: String, 44 | clipRule: String, 45 | d: String, 46 | pathFill: String, 47 | ) { 48 | svg { 49 | setStyle(width = width, height = height) 50 | attributes.run { 51 | this["viewBox"] = viewBox 52 | this["fill"] = fill 53 | } 54 | path { 55 | this.fillRule = fillRule 56 | this.clipRule = clipRule 57 | this.d = d 58 | this.fill = pathFill 59 | } 60 | } 61 | } 62 | 63 | /** 64 | * Represents as a `path` for SVG 65 | */ 66 | class SvgPath( 67 | consumer: TagConsumer<*>, 68 | ) : HTMLTag( 69 | tagName = "path", 70 | consumer = consumer, 71 | initialAttributes = emptyMap(), 72 | inlineTag = true, 73 | emptyTag = false, 74 | ), 75 | HtmlInlineTag { 76 | var fillRule: String 77 | get() = attributes["fill-rule"].toString() 78 | set(newValue) { 79 | attributes["fill-rule"] = newValue 80 | } 81 | 82 | var clipRule: String 83 | get() = attributes["clip-rule"].toString() 84 | set(newValue) { 85 | attributes["clip-rule"] = newValue 86 | } 87 | 88 | var d: String 89 | get() = attributes["d"].toString() 90 | set(newValue) { 91 | attributes["d"] = newValue 92 | } 93 | 94 | var fill: String 95 | get() = attributes["fill"].toString() 96 | set(newValue) { 97 | attributes["fill"] = newValue 98 | } 99 | } 100 | 101 | fun FlowOrPhrasingContent.path(block: SvgPath.() -> Unit = {}) { 102 | SvgPath(consumer).visit(block) 103 | } 104 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/script/CollapsibleScript.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.script 25 | 26 | import kotlinx.html.FlowContent 27 | import kotlinx.html.script 28 | import kotlinx.html.unsafe 29 | 30 | @Suppress("ktlint:standard:function-naming") 31 | fun FlowContent.CollapsibleScript() { 32 | script { 33 | unsafe { 34 | raw( 35 | """ 36 | var coll = document.getElementsByClassName("collapsible"); 37 | var i; 38 | 39 | for (i = 0; i < coll.length; i++) { 40 | coll[i].addEventListener("click", function() { 41 | this.classList.toggle("active"); 42 | var content = this.nextElementSibling; 43 | if (content.style.maxHeight){ 44 | content.style.maxHeight = null; 45 | content.style.overflow = "hidden" 46 | } else { 47 | content.style.maxHeight = content.scrollHeight + "px"; 48 | content.style.overflow = "auto"; 49 | content.style.maxHeight = "none"; 50 | } 51 | }); 52 | } 53 | """.trimIndent(), 54 | ) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/style/Colors.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style 25 | 26 | object Colors { 27 | const val RED_DARK = "#D32F2F" 28 | const val GREEN_LIGHT = "#B2DFDB" 29 | const val GREEN_DARK = "#004D40" 30 | const val PINK_LIGHT = "#FFEBEE" 31 | const val ALABASTER = "#F1F8E9" 32 | const val YELLOW = "#FFF9C4" 33 | const val BLUE_LIGHT = "#E1F5FE" 34 | const val WHITE = "#FFFFFF" 35 | const val BLACK = "#000000" 36 | const val BRIGHT_ORANGE = "#FFAC1C" 37 | } 38 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/style/CssStyle.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style 25 | 26 | import kotlinx.html.HTMLTag 27 | import kotlinx.html.impl.DelegatingMap 28 | 29 | @Suppress("ktlint:standard:property-naming") 30 | object StyleProps { 31 | const val Color = "color" 32 | const val BackgroundColor = "background-color" 33 | const val FontSize = "font-size" 34 | const val TextAlign = "text-align" 35 | const val Width = "width" 36 | const val Height = "height" 37 | const val Margin = "margin" 38 | const val Padding = "padding" 39 | const val AlignItems = "align-items" 40 | const val Display = "Display" 41 | } 42 | 43 | fun HTMLTag.setStyle( 44 | color: String? = null, 45 | backgroundColor: String? = null, 46 | fontSize: String? = null, 47 | textAlign: String? = null, 48 | width: String? = null, 49 | height: String? = null, 50 | margin: String? = null, 51 | padding: String? = null, 52 | alignItems: String? = null, 53 | display: String? = null, 54 | ) { 55 | attributes.setStyle( 56 | color = color, 57 | backgroundColor = backgroundColor, 58 | fontSize = fontSize, 59 | textAlign = textAlign, 60 | width = width, 61 | height = height, 62 | margin = margin, 63 | padding = padding, 64 | alignItems = alignItems, 65 | display = display, 66 | ) 67 | } 68 | 69 | fun DelegatingMap.setStyle( 70 | color: String? = null, 71 | backgroundColor: String? = null, 72 | fontSize: String? = null, 73 | textAlign: String? = null, 74 | width: String? = null, 75 | height: String? = null, 76 | margin: String? = null, 77 | padding: String? = null, 78 | alignItems: String? = null, 79 | display: String? = null, 80 | ) { 81 | set( 82 | "style", 83 | buildStyle( 84 | color = color, 85 | backgroundColor = backgroundColor, 86 | fontSize = fontSize, 87 | textAlign = textAlign, 88 | width = width, 89 | height = height, 90 | margin = margin, 91 | padding = padding, 92 | alignItems = alignItems, 93 | display = display, 94 | ), 95 | ) 96 | } 97 | 98 | fun buildStyle( 99 | color: String? = null, 100 | backgroundColor: String? = null, 101 | fontSize: String? = null, 102 | textAlign: String? = null, 103 | width: String? = null, 104 | height: String? = null, 105 | margin: String? = null, 106 | padding: String? = null, 107 | alignItems: String? = null, 108 | display: String? = null, 109 | ): String = 110 | buildString { 111 | color?.let { append(styleProperty(StyleProps.Color, color)) } 112 | backgroundColor?.let { append(styleProperty(StyleProps.BackgroundColor, backgroundColor)) } 113 | fontSize?.let { append(styleProperty(StyleProps.FontSize, fontSize)) } 114 | textAlign?.let { append(styleProperty(StyleProps.TextAlign, textAlign)) } 115 | width?.let { append(styleProperty(StyleProps.Width, width)) } 116 | height?.let { append(styleProperty(StyleProps.Height, height)) } 117 | margin?.let { append(styleProperty(StyleProps.Margin, margin)) } 118 | padding?.let { append(styleProperty(StyleProps.Padding, padding)) } 119 | alignItems?.let { append(styleProperty(StyleProps.AlignItems, it)) } 120 | display?.let { append(styleProperty(StyleProps.Display, it)) } 121 | } 122 | 123 | fun styleProperty( 124 | property: String, 125 | value: String, 126 | ) = "$property:$value;" 127 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/style/Fonts.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style 25 | 26 | import kotlinx.html.HEAD 27 | import kotlinx.html.link 28 | 29 | @Suppress("ktlint:standard:function-naming", "ktlint:standard:max-line-length") 30 | fun HEAD.FontsLinking() { 31 | link(rel = "preconnect", href = "https://fonts.googleapis.com") 32 | link(rel = "preconnect", href = "https://fonts.gstatic.com", type = "crossorigin") 33 | link( 34 | rel = "stylesheet", 35 | href = "https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap", 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/style/PageStyle.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.style 25 | 26 | import kotlinx.html.HEAD 27 | import kotlinx.html.style 28 | import kotlinx.html.unsafe 29 | 30 | @Suppress("ktlint:standard:function-naming") 31 | fun HEAD.PageStyle() { 32 | style { 33 | unsafe { 34 | raw( 35 | """ 36 | body { 37 | font-family: 'Roboto', sans-serif; 38 | text-align:center 39 | } 40 | 41 | hr { 42 | margin: 8px; 43 | } 44 | 45 | table, th, td { 46 | border: 1px solid black; 47 | border-collapse: collapse; 48 | margin: 8px; 49 | padding: 4px 50 | } 51 | 52 | .code { 53 | font-family: 'Roboto Mono', monospace; 54 | } 55 | 56 | .collapsible { 57 | background-color: #777; 58 | color: white; 59 | cursor: pointer; 60 | padding: 18px; 61 | width: 100%; 62 | border: none; 63 | text-align: left; 64 | outline: none; 65 | font-size: 24px; 66 | font-weight: 600; 67 | } 68 | 69 | .active, .collapsible:hover { 70 | background-color: #555; 71 | } 72 | 73 | .collapsible:after { 74 | content: '\002B'; 75 | color: white; 76 | font-weight: bold; 77 | float: right; 78 | margin-left: 5px; 79 | } 80 | 81 | .active:after { 82 | content: "\2212"; 83 | } 84 | 85 | .content { 86 | padding: 0 18px; 87 | max-height: 0; 88 | overflow: hidden; 89 | transition: max-height 0.2s ease-out; 90 | background-color: #f1f1f1; 91 | } 92 | 93 | .content-header { 94 | background-color: #777; 95 | color: white; 96 | cursor: pointer; 97 | padding: 18px; 98 | width: 100%; 99 | border: none; 100 | text-align: left; 101 | outline: none; 102 | font-size: 24px; 103 | font-weight: 600; 104 | } 105 | 106 | .content-body { 107 | padding: 0 18px; 108 | transition: max-height 0.2s ease-out; 109 | background-color: #f1f1f1; 110 | } 111 | 112 | .center { 113 | margin-left: auto; 114 | margin-right: auto; 115 | } 116 | 117 | footer { 118 | padding: 16px; 119 | background-color: #E0E0E0 120 | } 121 | 122 | .status-success { 123 | color: ${Colors.GREEN_DARK}; 124 | } 125 | 126 | .status-failure { 127 | color: ${Colors.RED_DARK}; 128 | } 129 | 130 | .background-status-success { 131 | background-color: ${Colors.GREEN_LIGHT}; 132 | color: ${Colors.BLACK}; 133 | } 134 | 135 | .background-status-failure { 136 | background-color: ${Colors.RED_DARK}; 137 | color: ${Colors.WHITE} 138 | } 139 | 140 | .background-status-missing { 141 | background-color: ${Colors.BRIGHT_ORANGE}; 142 | color: ${Colors.BLACK} 143 | } 144 | 145 | .empty-content { 146 | margin: 4px; 147 | padding: 18px; 148 | text-align: center; 149 | font-size: 18px; 150 | font-weight: 600; 151 | } 152 | """.trimIndent(), 153 | ) 154 | } 155 | } 156 | } 157 | 158 | fun statusCssClass(success: Boolean) = if (success) "status-success" else "status-failure" 159 | 160 | fun backgroundStatusCssClass(success: Boolean) = if (success) "background-status-success" else "background-status-failure" 161 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/utils/ListExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.utils 25 | 26 | /** 27 | * This is similar to [forEachIndexed] but in this function, index starts from 1 instead of 0 28 | */ 29 | fun Iterable.forEachIndexedFromOne(action: (index: Int, E) -> Unit) = forEachIndexed { index, e -> action(index + 1, e) } 30 | -------------------------------------------------------------------------------- /report-generator/src/main/kotlin/dev/shreyaspatil/composeCompilerMetricsGenerator/generator/utils/StringExt.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package dev.shreyaspatil.composeCompilerMetricsGenerator.generator.utils 25 | 26 | fun String.lines(): List = split("\n") 27 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenCentral() 4 | google() 5 | gradlePluginPortal() 6 | maven(url = "https://plugins.gradle.org/m2/") 7 | } 8 | } 9 | 10 | dependencyResolutionManagement { 11 | repositories { 12 | mavenCentral() 13 | google() 14 | } 15 | } 16 | 17 | rootProject.name = "compose-report-to-html" 18 | 19 | include("core") 20 | include("report-generator") 21 | include("cli") 22 | include("gradle-plugin") 23 | -------------------------------------------------------------------------------- /spotless/copyright.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Shreyas Patil 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | --------------------------------------------------------------------------------