├── .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 | [](https://github.com/PatilShreyas/compose-report-to-html/actions/workflows/build.yml)
7 | [](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/) | [](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/) | [](https://www.npmjs.com/package/compose-report2html)
[](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/) | [](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/) | [](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/) | [](https://www.npmjs.com/package/compose-report2html)
[](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/) | [](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.
 |
49 | | **Detailed Statistics** | Generates report from `.csv` file and represents in tabular format.
 |
50 | | **Composable Report** | Parses `-composables.txt` file and separates out composables with and without issues and properly highlights issues associated with them.
 |
51 | | **Class Report** | Parses `-classes.txt` file and separates out stable and unstable classes out of it and properly highlights issues associated with them.
 |
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: [](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: [](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 | [](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 | { 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 | { 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: [](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 |
--------------------------------------------------------------------------------