diff --git a/analysis/.kotlin/sessions/kotlin-compiler-12322078610956747093.salive b/analysis/.kotlin/sessions/kotlin-compiler-12322078610956747093.salive new file mode 100644 index 0000000000..e69de29bb2 diff --git a/analysis/analysers/parsers/UnifiedParser/README.md b/analysis/analysers/parsers/UnifiedParser/README.md index cd33a39813..2571dd1204 100644 --- a/analysis/analysers/parsers/UnifiedParser/README.md +++ b/analysis/analysers/parsers/UnifiedParser/README.md @@ -10,6 +10,7 @@ The Unified Parser is parser to generate code metrics from a source code file or |--------------|----------------------------------------| | Javascript | .js, .cjs, .mjs | | Typescript | .ts, .cts, .mts | +| TSX | .tsx | | Java | .java | | Kotlin | .kt | | C# | .cs | @@ -22,6 +23,7 @@ The Unified Parser is parser to generate code metrics from a source code file or | Ruby | .rb | | Swift | .swift | | Bash | .sh | +| Vue | .vue | ## Supported Metrics diff --git a/analysis/analysers/parsers/UnifiedParser/build.gradle.kts b/analysis/analysers/parsers/UnifiedParser/build.gradle.kts index e0511d0295..cfe57de0db 100644 --- a/analysis/analysers/parsers/UnifiedParser/build.gradle.kts +++ b/analysis/analysers/parsers/UnifiedParser/build.gradle.kts @@ -9,7 +9,7 @@ dependencies { implementation(libs.kotter.test) // TreesitterLibrary provides all TreeSitter dependencies and metric calculation - implementation("com.github.MaibornWolff:TreeSitterExcavationSite:v0.2.0") + implementation("com.github.MaibornWolff:TreeSitterExcavationSite:v0.4.1") testImplementation(libs.jsonassert) } diff --git a/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/AttributeDescriptors.kt b/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/AttributeDescriptors.kt index c094f8583f..dcef105db5 100644 --- a/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/AttributeDescriptors.kt +++ b/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/AttributeDescriptors.kt @@ -94,7 +94,10 @@ internal fun getAttributeDescriptors(): Map { ), "mean_complexity_per_function" to AttributeDescriptor( title = "Mean complexity per function", - description = "The mean complexity found in the body of a function of this file." + description = "The mean complexity found in the body of a function of this file.", + link = ghLink, + direction = -1, + analyzers = analyzerName ), "median_complexity_per_function" to AttributeDescriptor( title = "Median complexity per function", diff --git a/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/AvailableCollectors.kt b/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/AvailableCollectors.kt index d039363e80..e6bb56396a 100644 --- a/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/AvailableCollectors.kt +++ b/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/AvailableCollectors.kt @@ -3,8 +3,15 @@ package de.maibornwolff.codecharta.analysers.parsers.unified.metriccollectors import de.maibornwolff.codecharta.serialization.FileExtension import de.maibornwolff.treesitter.excavationsite.api.Language -enum class AvailableCollectors(val fileExtension: FileExtension, val collectorFactory: () -> TreeSitterLibraryCollector) { +/** Maps each supported [FileExtension] to a factory for the corresponding [TreeSitterLibraryCollector]. */ +enum class AvailableCollectors( + /** The file extension this collector handles. */ + val fileExtension: FileExtension, + /** Factory function that creates the collector for this language. */ + val collectorFactory: () -> TreeSitterLibraryCollector +) { TYPESCRIPT(FileExtension.TYPESCRIPT, { TreeSitterLibraryCollector(Language.TYPESCRIPT) }), + TSX(FileExtension.TSX, { TreeSitterLibraryCollector(Language.TSX) }), JAVASCRIPT(FileExtension.JAVASCRIPT, { TreeSitterLibraryCollector(Language.JAVASCRIPT) }), KOTLIN(FileExtension.KOTLIN, { TreeSitterLibraryCollector(Language.KOTLIN) }), OBJECTIVE_C(FileExtension.OBJECTIVE_C, { TreeSitterLibraryCollector(Language.OBJECTIVE_C) }), diff --git a/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapter.kt b/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapter.kt index 5b408e29c7..1dd9def2ea 100644 --- a/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapter.kt +++ b/analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapter.kt @@ -51,6 +51,7 @@ object TreeSitterAdapter { FileExtension.JAVA -> Language.JAVA FileExtension.KOTLIN -> Language.KOTLIN FileExtension.TYPESCRIPT -> Language.TYPESCRIPT + FileExtension.TSX -> Language.TSX FileExtension.JAVASCRIPT -> Language.JAVASCRIPT FileExtension.PYTHON -> Language.PYTHON FileExtension.GO -> Language.GO diff --git a/analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/UnifiedParserTest.kt b/analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/UnifiedParserTest.kt index 0d8a3807ad..1f580cd2e4 100644 --- a/analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/UnifiedParserTest.kt +++ b/analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/UnifiedParserTest.kt @@ -43,6 +43,7 @@ class UnifiedParserTest { Arguments.of("ruby", ".rb"), Arguments.of("swift", ".swift"), Arguments.of("typescript", ".ts"), + Arguments.of("tsx", ".tsx"), Arguments.of("vue", ".vue") ) } diff --git a/analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapterTest.kt b/analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapterTest.kt index 03deeb949f..95d64f1e93 100644 --- a/analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapterTest.kt +++ b/analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapterTest.kt @@ -64,6 +64,7 @@ class TreeSitterAdapterTest { FileExtension.JAVA to Language.JAVA, FileExtension.KOTLIN to Language.KOTLIN, FileExtension.TYPESCRIPT to Language.TYPESCRIPT, + FileExtension.TSX to Language.TSX, FileExtension.JAVASCRIPT to Language.JAVASCRIPT, FileExtension.PYTHON to Language.PYTHON, FileExtension.GO to Language.GO, @@ -143,6 +144,7 @@ class TreeSitterAdapterTest { FileExtension.JAVA, FileExtension.KOTLIN, FileExtension.TYPESCRIPT, + FileExtension.TSX, FileExtension.JAVASCRIPT, FileExtension.PYTHON, FileExtension.GO, diff --git a/analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt b/analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt new file mode 100644 index 0000000000..ee9e458260 --- /dev/null +++ b/analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt @@ -0,0 +1,185 @@ +package de.maibornwolff.codecharta.analysers.parsers.unified.metriccollectors + +import de.maibornwolff.treesitter.excavationsite.api.AvailableFileMetrics +import de.maibornwolff.treesitter.excavationsite.api.Language +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import java.io.File + +class TsxCollectorTest { + private val collector = TreeSitterLibraryCollector(Language.TSX) + + private fun createTestFile(content: String): File { + val tempFile = File.createTempFile("testFile", ".tsx") + tempFile.writeText(content) + tempFile.deleteOnExit() + return tempFile + } + + @Test + fun `should parse a minimal tsx component and return non-zero loc`() { + // Arrange + val fileContent = """ + function Hello() { + return
Hello World
; + } + """.trimIndent() + val input = createTestFile(fileContent) + + // Act + val result = collector.collectMetricsForFile(input) + + // Assert + assertThat(result.attributes[AvailableFileMetrics.LINES_OF_CODE.metricName] as Double).isGreaterThan(0.0) + assertThat(result.attributes[AvailableFileMetrics.NUMBER_OF_FUNCTIONS.metricName] as Double).isEqualTo(1.0) + } + + @Test + fun `should count ternary operator inside JSX expression for complexity`() { + // Arrange + val fileContent = """const element = (

{x < 10 ? "Banana" : "Apple"}

);""" + val input = createTestFile(fileContent) + + // Act + val result = collector.collectMetricsForFile(input) + + // Assert + assertThat(result.attributes[AvailableFileMetrics.COMPLEXITY.metricName]).isEqualTo(1.0) + } + + @Test + fun `should count logical AND short-circuit in JSX expression for complexity`() { + // Arrange + val fileContent = """const element = (
{isLoggedIn && }
);""" + val input = createTestFile(fileContent) + + // Act + val result = collector.collectMetricsForFile(input) + + // Assert + assertThat(result.attributes[AvailableFileMetrics.COMPLEXITY.metricName]).isEqualTo(1.0) + } + + @Test + fun `should not count inline arrow function in JSX prop as a function`() { + // Arrange + val fileContent = """ + function App() { + return (