Skip to content

Add TSX support to UnifiedParser#4466

Merged
Molerat merged 6 commits intomainfrom
feature/tsx-support
Apr 20, 2026
Merged

Add TSX support to UnifiedParser#4466
Molerat merged 6 commits intomainfrom
feature/tsx-support

Conversation

@Molerat
Copy link
Copy Markdown
Collaborator

@Molerat Molerat commented Mar 27, 2026

Add TSX language support to UnifiedParser

Please read the CONTRIBUTING.md before opening a PR.

Closes: #

Description

UnifiedParser did not support .tsx (TypeScript JSX) files, leaving TSX source files silently skipped during analysis.

This PR adds TSX as a first-class supported language:

  • Added TSX(".tsx") to the FileExtension enum so the file extension is recognized
  • Added FileExtension.TSX → Language.TSX mapping in TreeSitterAdapter so the TreeSitter excavation site library parses TSX files correctly
  • Added TSX to AvailableCollectors to wire the extension to its TreeSitterLibraryCollector
  • Extended TreeSitterAdapterTest to cover the TSX mappings
  • Added a TsxCollectorTest and a tsxSample.tsx integration test resource
  • Fixed a timing race in ProjectInputReader where a fixed 100ms sleep was too short when all JVMs in a pipe chain start concurrently; replaced with a 500ms polling loop that exits as soon as data is
    available

Definition of Done

A PR is only ready for merge once all the following acceptance criteria are fulfilled:

  • Changes have been manually tested
  • All TODOs related to this PR have been closed
  • There are automated tests for newly written code and bug fixes
  • All bugs discovered while working on this PR have been submitted as issues (if not already an open issue)
  • Documentation (GH-pages, analysis/visualization READMEs, parser READMEs, --help, etc.) has been updated (almost always necessary except for bug fixes)
  • CHANGELOG.md has been updated

Screenshots or gifs

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for TSX (TypeScript JSX) files in UnifiedParser. TSX files can now be analyzed with comprehensive metrics including lines of code, complexity, function counts, and comment lines.
  • Documentation

    • Updated unified parser documentation with TSX language specifications and complete metrics definitions.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 27, 2026

Warning

Rate limit exceeded

@Molerat has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 55 minutes and 41 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 55 minutes and 41 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5a6d2a31-4629-49fd-96fb-14c817bc6e76

📥 Commits

Reviewing files that changed from the base of the PR and between bf3a3f3 and 0769f32.

📒 Files selected for processing (38)
  • analysis/.kotlin/sessions/kotlin-compiler-12322078610956747093.salive
  • analysis/analysers/parsers/UnifiedParser/README.md
  • analysis/analysers/parsers/UnifiedParser/build.gradle.kts
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/AttributeDescriptors.kt
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/AvailableCollectors.kt
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapter.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/UnifiedParserTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapterTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/empty.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/excludePattern.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/includeAll.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/kotlinOnly.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/bashSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/cHeaderSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/cSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/cSharpSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/cppHeaderSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/cppSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/goSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/javaSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/javascriptSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/kotlinSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/objectiveCSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/phpSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/pythonSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/rubySample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/swiftSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.tsx
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/typescriptSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/vueSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/mergeResult.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/sampleProject.cc.json
  • analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/FileExtension.kt
  • analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/ProjectInputReader.kt
  • gh-pages/_docs/05-parser/05-unified.md
  • plans/add-tsx-support.md
📝 Walkthrough

Walkthrough

This pull request adds TypeScript JSX (TSX) language support to the UnifiedParser by introducing new enum constants, updating language mappings, creating comprehensive test coverage, and extending test fixtures. Additionally, infrastructure improvements were made to handle input stream availability with polling logic.

Changes

Cohort / File(s) Summary
TSX Language Support
analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/FileExtension.kt, analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/AvailableCollectors.kt, analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapter.kt
Added TSX enum constant with .tsx extension to FileExtension, registered TSX collector in AvailableCollectors mapping to TreeSitterLibraryCollector(Language.TSX), and updated TreeSitterAdapter to map FileExtension.TSX to Language.TSX.
TSX Test Coverage
analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt, analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapterTest.kt, analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/UnifiedParserTest.kt
Created TsxCollectorTest with 10 test cases covering LOC, complexity metrics, function counting, arrow functions, and comment line detection. Updated adapter and parser tests to include TSX in supported extensions and language mappings.
TSX Test Fixtures
analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.tsx, analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.cc.json
Added TSX sample code with React components (UserCard, UserList) and utility function demonstrating conditional rendering, state management, and access-level logic. Generated corresponding metrics fixture JSON with computed attributes for LOC, complexity, functions, and code-smell counters.
Dependency Update
analysis/analysers/parsers/UnifiedParser/build.gradle.kts
Updated TreeSitterExcavationSite dependency from v0.2.0 to v0.4.1 to enable TSX language support.
Test Fixture Metadata Updates
analysis/analysers/parsers/UnifiedParser/src/test/resources/{empty,kotlinOnly,mergeResult,sampleProject,includeAll,excludePattern}.cc.json, analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/{bash,c,cHeader,cpp,cppHeader,cSharp,go,java,javascript,kotlin,objectiveC,php,python,ruby,swift,typescript,vue}Sample.cc.json
Updated all JSON test fixtures with new checksums and modified attributeDescriptors.mean_complexity_per_function metadata to include documentation link (https://codecharta.com/docs/parser/unified) and unifiedParser analyzer attribution.
Documentation
analysis/analysers/parsers/UnifiedParser/README.md, gh-pages/_docs/05-parser/05-unified.md, plans/add-tsx-support.md
Extended language support tables with TSX and Vue entries. Added TSX-specific metric collection documentation covering complexity, comment lines, functions, parameters, and message chains. Created completion plan documenting TSX implementation steps.
Attribute Descriptor Enhancement
analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/AttributeDescriptors.kt
Extended mean_complexity_per_function descriptor to include documentation link and analyzer metadata fields (link, direction, analyzers).
Input Stream Polling
analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/ProjectInputReader.kt
Replaced fixed delay with adaptive polling loop that checks input availability in increments (CHECK_INTERVAL_MS) up to a maximum wait time (MAX_WAIT_MS), improving robustness for stream initialization.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit hops through TypeScript lands so bright,
With TSX components in sight,
New metrics dance, complexity takes flight,
From Vue to TSX, the parser's might!
🎉✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add TSX support to UnifiedParser' accurately and clearly summarizes the main objective of the changeset.
Description check ✅ Passed The PR description addresses the problem, explains the implementation approach with concrete changes, and follows the template structure with Definition of Done checklist items.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/tsx-support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt (2)

12-17: Consider using .tsx extension for test clarity.

While the collector ignores the file extension (using the Language parameter instead), using .tsx would make the test's intent clearer and provide better documentation of what's being tested.

♻️ Suggested improvement
     private fun createTestFile(content: String): File {
-        val tempFile = File.createTempFile("testFile", ".txt")
+        val tempFile = File.createTempFile("testFile", ".tsx")
         tempFile.writeText(content)
         tempFile.deleteOnExit()
         return tempFile
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt`
around lines 12 - 17, The test helper createTestFile currently creates temp
files with ".txt", which obscures intent; change createTestFile to create temp
files with a ".tsx" extension so tests clearly reflect they target TSX parsing:
update the function createTestFile(content: String): File to call
File.createTempFile("testFile", ".tsx") (and keep writeText and deleteOnExit) so
the test file extension matches the component under test
(TsxCollector/TsxCollectorTest) without altering behavior.

32-33: Consider adding TSX-specific metric assertions.

The test only verifies LOC > 0. Since the sample includes a function definition, asserting number_of_functions would strengthen confidence in TSX-specific parsing.

♻️ Additional assertion
         // 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)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt`
around lines 32 - 33, The test currently only asserts LOC > 0; add a
TSX-specific assertion to check that a function was detected by asserting
result.attributes[AvailableFileMetrics.NUMBER_OF_FUNCTIONS.metricName] (cast to
Double) is >= 1.0 — update the TsxCollectorTest to include an assertion like
asserting that
(result.attributes[AvailableFileMetrics.NUMBER_OF_FUNCTIONS.metricName] as
Double) isGreaterThanOrEqualTo(1.0) so the parser’s function-counting for TSX is
validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt`:
- Around line 12-17: The test helper createTestFile currently creates temp files
with ".txt", which obscures intent; change createTestFile to create temp files
with a ".tsx" extension so tests clearly reflect they target TSX parsing: update
the function createTestFile(content: String): File to call
File.createTempFile("testFile", ".tsx") (and keep writeText and deleteOnExit) so
the test file extension matches the component under test
(TsxCollector/TsxCollectorTest) without altering behavior.
- Around line 32-33: The test currently only asserts LOC > 0; add a TSX-specific
assertion to check that a function was detected by asserting
result.attributes[AvailableFileMetrics.NUMBER_OF_FUNCTIONS.metricName] (cast to
Double) is >= 1.0 — update the TsxCollectorTest to include an assertion like
asserting that
(result.attributes[AvailableFileMetrics.NUMBER_OF_FUNCTIONS.metricName] as
Double) isGreaterThanOrEqualTo(1.0) so the parser’s function-counting for TSX is
validated.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ede1921f-14d9-428c-9d0f-17a111cde4b6

📥 Commits

Reviewing files that changed from the base of the PR and between 8697cd8 and 211da04.

📒 Files selected for processing (16)
  • analysis/analysers/parsers/UnifiedParser/README.md
  • analysis/analysers/parsers/UnifiedParser/build.gradle.kts
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/AvailableCollectors.kt
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapter.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/UnifiedParserTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/excludePattern.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/includeAll.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.tsx
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/vueSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/mergeResult.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/sampleProject.cc.json
  • analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/FileExtension.kt
  • gh-pages/_docs/05-parser/05-unified.md
  • plans/add-tsx-support.md

@Molerat Molerat force-pushed the feature/tsx-support branch from 211da04 to 23c209a Compare March 31, 2026 10:24
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/ProjectInputReader.kt`:
- Around line 24-31: The current polling loop in ProjectInputReader (uses
input.available(), MAX_WAIT_MS and CHECK_INTERVAL_MS and then returns "" on
timeout) is unreliable; replace it with a proper blocking read and surface a
timeout exception instead of returning an empty string. Remove the
input.available() loop and either (a) if the InputStream originates from a
Socket, set the socket SO_TIMEOUT and perform a blocking read() so a
SocketTimeoutException is thrown on timeout, or (b) if source is not a socket,
perform a blocking read via InputStream.read() combined with a scheduled timeout
using an Executor/Future and cancel/throw a TimeoutException when MAX_WAIT_MS
elapses. Ensure ProjectInputReader no longer returns "" on timeout but throws an
explicit exception so ProjectDeserializer can handle true timeouts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 758392f2-1dec-4ad7-bed0-fcd7351eb5ba

📥 Commits

Reviewing files that changed from the base of the PR and between 23c209a and 526090e.

📒 Files selected for processing (1)
  • analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/ProjectInputReader.kt

Comment on lines +24 to 31
var waited = 0L
while (input.available() <= 0 && waited < MAX_WAIT_MS) {
Thread.sleep(CHECK_INTERVAL_MS)
waited += CHECK_INTERVAL_MS
}
val availableBytes = input.available()
if (availableBytes <= 0) {
return ""
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

According to the official Java docs, is InputStream.available() a reliable way to decide that no bytes will arrive yet on piped/socket streams, and should it be used as a timeout/readiness gate like this?

💡 Result:

No, according to the official Java documentation, InputStream.available is not a reliable way to decide that no bytes will arrive yet on piped or socket streams, and it should not be used as a timeout or readiness gate. The InputStream.available method returns "an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking, which may be 0, or 0 when end of stream is detected." It explicitly states that it "may be 0" even when bytes are pending but not yet immediately available without blocking, as clarified in spec updates (e.g., JDK-8199355). The base implementation always returns 0. For socket streams (Socket.getInputStream), available often returns 0 even with incoming data not yet in the local buffer, as confirmed by community consensus and examples where it fails reliably. For piped streams (PipedInputStream), while available returns the buffer count (reliable for the internal buffer), it does not predict future writes from another thread—it only indicates current buffered bytes. If no bytes are buffered yet, it returns 0 even if bytes "will arrive" soon, making it unsuitable as a "no bytes will arrive yet" check or readiness gate for external data arrival. Using it in a loop like while(available == 0) as a timeout gate is unreliable: it may loop indefinitely waiting for data that arrives later (false negative), or read prematurely. Official docs warn against using it to determine total stream size or allocate buffers, implying it's not for readiness polling. Instead, use Socket.setSoTimeout, NIO channels with selectors, or proper blocking reads.

Citations:


InputStream.available() is unreliable for timeout gates; use proper blocking reads.

At lines 25–30, the polling loop uses input.available() to decide if bytes will never arrive, then returns "" after timeout. Per official Java documentation, available() returns only an estimate and is "may be 0" even when bytes are pending on socket or piped streams—it cannot reliably detect whether data will arrive. On sockets it often returns 0 despite incoming data in flight; on pipes it only reflects already-buffered bytes, not future writes. Returning "" conflates timeout with genuinely empty input, causing ProjectDeserializer to silently produce null downstream without surfacing the actual timeout condition.

Replace with fail-fast approach (throw exception on timeout)
         val availableBytes = input.available()
         if (availableBytes <= 0) {
-            return ""
+            throw IllegalStateException("Timed out waiting for piped project input after ${MAX_WAIT_MS}ms")
         }

Use proper blocking reads (e.g., read() with socket timeout via Socket.setSoTimeout()) or NIO selectors instead of polling available().

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var waited = 0L
while (input.available() <= 0 && waited < MAX_WAIT_MS) {
Thread.sleep(CHECK_INTERVAL_MS)
waited += CHECK_INTERVAL_MS
}
val availableBytes = input.available()
if (availableBytes <= 0) {
return ""
var waited = 0L
while (input.available() <= 0 && waited < MAX_WAIT_MS) {
Thread.sleep(CHECK_INTERVAL_MS)
waited += CHECK_INTERVAL_MS
}
val availableBytes = input.available()
if (availableBytes <= 0) {
throw IllegalStateException("Timed out waiting for piped project input after ${MAX_WAIT_MS}ms")
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/ProjectInputReader.kt`
around lines 24 - 31, The current polling loop in ProjectInputReader (uses
input.available(), MAX_WAIT_MS and CHECK_INTERVAL_MS and then returns "" on
timeout) is unreliable; replace it with a proper blocking read and surface a
timeout exception instead of returning an empty string. Remove the
input.available() loop and either (a) if the InputStream originates from a
Socket, set the socket SO_TIMEOUT and perform a blocking read() so a
SocketTimeoutException is thrown on timeout, or (b) if source is not a socket,
perform a blocking read via InputStream.read() combined with a scheduled timeout
using an Executor/Future and cancel/throw a TimeoutException when MAX_WAIT_MS
elapses. Ensure ProjectInputReader no longer returns "" on timeout but throws an
explicit exception so ProjectDeserializer can handle true timeouts.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finding does not need to be applied. Here is why:

  1. Intentional design, recently changed: The commit d79579c explicitly introduced this polling approach as a deliberate fix for a "fixed sleep". It is not a bug.
  2. Both callers treat empty-string as a valid, expected signal — not an error:
    - ProjectDeserializer.kt:44: if (projectString.length <= 1) return null — empty string means "no piped input", returns null gracefully.
    - TokeiImporter.kt:136: if (projectString.isNotEmpty()) — same pattern, skips processing if empty.
  3. The stream is not a socket — it is piped stdin from a bash command. Setting SO_TIMEOUT is inapplicable, and wrapping in a Future to throw TimeoutException would break both callers without any gain.
  4. The proposed change would be a breaking API change — switching from an empty-string sentinel to thrown exceptions requires updating all callers and changes semantics: "no input found in time" is not an error condition in
    this codebase, it is a normal flow for the optional pipe use-case.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Molerat, thank you for the thorough explanation — all four points are well-reasoned and I agree the finding does not apply here:

  • The empty-string return is a deliberate sentinel meaning "no piped input is present", which is a normal flow condition, not an error.
  • Both callers (ProjectDeserializer and TokeiImporter) are already designed to handle this gracefully.
  • SO_TIMEOUT and Future-based timeouts are inapplicable for piped stdin and would require breaking changes to callers with no benefit.

I'll withdraw the comment and record this design context for future reviews.


✏️ Learnings added
Learnt from: Molerat
Repo: MaibornWolff/codecharta PR: 4466
File: analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/ProjectInputReader.kt:25-32
Timestamp: 2026-04-01T11:23:21.913Z
Learning: In `analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/ProjectInputReader.kt`, the polling loop using `InputStream.available()` with `MAX_WAIT_MS`/`CHECK_INTERVAL_MS` constants is an intentional design for piped stdin (not sockets). Returning `""` (empty string) on timeout is a valid sentinel meaning "no piped input was found", not an error. Both callers treat it as a normal, non-error flow: `ProjectDeserializer.kt` returns `null` when `projectString.length <= 1`, and `TokeiImporter.kt` skips processing when `projectString.isEmpty()`. Do not suggest replacing this with exceptions or socket timeouts.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
Repo: MaibornWolff/codecharta PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-23T13:57:10.597Z
Learning: Applies to analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/**/*.kt : Use GSON-based serialization with ProjectSerializer/ProjectDeserializer for `.cc.json` format, supporting optional GZIP compression

@Molerat Molerat force-pushed the feature/tsx-support branch 2 times, most recently from 7057b7a to b3d19dd Compare April 1, 2026 09:45
@Molerat Molerat changed the title Feature/tsx support Add TSX support to UnifiedParser Apr 1, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
plans/add-tsx-support.md (1)

19-19: Avoid “latest” in the pinned-version step description.

The step already pins v0.4.1, so “latest version with TSX” is ambiguous and can age poorly in docs.

✏️ Suggested wording tweak
-- Change: `implementation("com.github.MaibornWolff:TreeSitterExcavationSite:v0.4.1")` → latest version with TSX
+- Change: `implementation("com.github.MaibornWolff:TreeSitterExcavationSite:v0.4.1")` (version that includes TSX support)

As per coding guidelines, plans should stay simple, concise, and action-focused.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plans/add-tsx-support.md` at line 19, Replace the ambiguous phrasing "latest
version with TSX" in the plans/add-tsx-support.md step that currently references
implementation("com.github.MaibornWolff:TreeSitterExcavationSite:v0.4.1") with a
concrete, pinned-version instruction (e.g., specify the exact new tag that adds
TSX support) or a clear placeholder like "pin to the TreeSitterExcavationSite
release that adds TSX (e.g., vX.Y.Z)"; update the text so it instructs to change
the dependency version to that exact release instead of using the word "latest".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@plans/add-tsx-support.md`:
- Line 19: Replace the ambiguous phrasing "latest version with TSX" in the
plans/add-tsx-support.md step that currently references
implementation("com.github.MaibornWolff:TreeSitterExcavationSite:v0.4.1") with a
concrete, pinned-version instruction (e.g., specify the exact new tag that adds
TSX support) or a clear placeholder like "pin to the TreeSitterExcavationSite
release that adds TSX (e.g., vX.Y.Z)"; update the text so it instructs to change
the dependency version to that exact release instead of using the word "latest".

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: de57d9c1-aa4c-4055-bec6-4acf9f47d2a3

📥 Commits

Reviewing files that changed from the base of the PR and between fdb30cb and b3d19dd.

📒 Files selected for processing (12)
  • analysis/analysers/parsers/UnifiedParser/README.md
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/AvailableCollectors.kt
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapter.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/UnifiedParserTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapterTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.tsx
  • analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/FileExtension.kt
  • analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/ProjectInputReader.kt
  • gh-pages/_docs/05-parser/05-unified.md
  • plans/add-tsx-support.md
✅ Files skipped from review due to trivial changes (6)
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapterTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/UnifiedParserTest.kt
  • analysis/analysers/parsers/UnifiedParser/README.md
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.tsx
  • gh-pages/_docs/05-parser/05-unified.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/ProjectInputReader.kt
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/AvailableCollectors.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapter.kt

@Molerat Molerat force-pushed the feature/tsx-support branch from b3d19dd to 6243a0f Compare April 1, 2026 10:22
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt (1)

33-34: Strengthen the TSX regression assertion for determinism.

For this fixed snippet, NUMBER_OF_FUNCTIONS should be exact (likely 1.0), not >= 1.0. Tightening this makes regressions easier to catch.

Based on learnings: "All metrics must be deterministic and reproducible across runs".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt`
around lines 33 - 34, The test currently asserts NUMBER_OF_FUNCTIONS >= 1.0
which is too loose; update the assertion in TsxCollectorTest (the check on
result.attributes[AvailableFileMetrics.NUMBER_OF_FUNCTIONS.metricName]) to
assert exact determinism (e.g., isEqualTo(1.0) after casting to Double) so the
test expects the concrete, reproducible function count rather than a lower
bound.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.cc.json`:
- Around line 182-190: The metric descriptor "mean_complexity_per_function" is
missing its "link" and "analyzers" entries causing inconsistent .cc.json
metadata; update the "mean_complexity_per_function" object to include a valid
"link" (same style as other metrics' link values) and populate "analyzers" with
the same analyzer identifiers used for related complexity metrics (e.g., the
analyzer that produces function complexity), ensuring the keys match the format
used elsewhere in the fixture so consumers can attribute the metric correctly.

---

Nitpick comments:
In
`@analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt`:
- Around line 33-34: The test currently asserts NUMBER_OF_FUNCTIONS >= 1.0 which
is too loose; update the assertion in TsxCollectorTest (the check on
result.attributes[AvailableFileMetrics.NUMBER_OF_FUNCTIONS.metricName]) to
assert exact determinism (e.g., isEqualTo(1.0) after casting to Double) so the
test expects the concrete, reproducible function count rather than a lower
bound.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ee9fe88b-1412-4504-a37c-69d26fc2963a

📥 Commits

Reviewing files that changed from the base of the PR and between fdb30cb and b3d19dd.

📒 Files selected for processing (12)
  • analysis/analysers/parsers/UnifiedParser/README.md
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/AvailableCollectors.kt
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapter.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/UnifiedParserTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapterTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TsxCollectorTest.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.tsx
  • analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/FileExtension.kt
  • analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/ProjectInputReader.kt
  • gh-pages/_docs/05-parser/05-unified.md
  • plans/add-tsx-support.md
✅ Files skipped from review due to trivial changes (5)
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapterTest.kt
  • analysis/analysers/parsers/UnifiedParser/README.md
  • analysis/analysers/parsers/UnifiedParser/src/test/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/UnifiedParserTest.kt
  • gh-pages/_docs/05-parser/05-unified.md
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/AvailableCollectors.kt
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/metriccollectors/TreeSitterAdapter.kt
  • analysis/model/src/main/kotlin/de/maibornwolff/codecharta/serialization/ProjectInputReader.kt

@Molerat Molerat force-pushed the feature/tsx-support branch from 6243a0f to c441dab Compare April 1, 2026 10:26
@Molerat
Copy link
Copy Markdown
Collaborator Author

Molerat commented Apr 1, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 1, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Molerat Molerat force-pushed the feature/tsx-support branch from c441dab to 1f5eafd Compare April 1, 2026 11:26
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@analysis/analysers/parsers/UnifiedParser/src/test/resources/includeAll.cc.json`:
- Line 165: Update the incorrect "loc" numeric values in the JSON test fixture
entries for the two source files: set the "loc" for the entry whose "file" is
"foo.py" from 15.0 to 14.0 and set the "loc" for the entry whose "file" is
"helloWorld.ts" from 9.0 to 8.0 so the "loc" fields match the actual source
files.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 655f0d3f-3eee-4165-a140-677895efc505

📥 Commits

Reviewing files that changed from the base of the PR and between 1f5eafd and 7348ebd.

📒 Files selected for processing (25)
  • analysis/analysers/parsers/UnifiedParser/src/main/kotlin/de/maibornwolff/codecharta/analysers/parsers/unified/AttributeDescriptors.kt
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/empty.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/excludePattern.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/includeAll.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/kotlinOnly.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/bashSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/cHeaderSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/cSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/cSharpSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/cppHeaderSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/cppSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/goSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/javaSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/javascriptSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/kotlinSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/objectiveCSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/phpSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/pythonSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/rubySample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/swiftSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/typescriptSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/vueSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/mergeResult.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/sampleProject.cc.json
✅ Files skipped from review due to trivial changes (7)
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/cppSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/goSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/typescriptSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/swiftSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/rubySample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/tsxSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/objectiveCSample.cc.json
🚧 Files skipped from review as they are similar to previous changes (4)
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/excludePattern.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/languageSamples/vueSample.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/mergeResult.cc.json
  • analysis/analysers/parsers/UnifiedParser/src/test/resources/sampleProject.cc.json

@Molerat Molerat force-pushed the feature/tsx-support branch 2 times, most recently from 95091c0 to bf3a3f3 Compare April 20, 2026 07:36
Ulrike Kiesel added 6 commits April 20, 2026 09:40
v0.3.0 of the library changed LOC counting (trailing newlines no longer counted), causing off-by-1 diffs in golden files
The fixed 100ms sleep was insufficient on CI after the TreeSitter v0.4.1
dependency bump (1.5 MB JAR), which slightly increased JVM startup time.
The upstream svnlogparser process no longer wrote its sync flag within
100ms, so modify read an empty stdin and skipped writing the output file.

Replace with a polling loop (50ms interval, 500ms max) that exits as soon
as data is available, making the pipe chain robust to JVM startup variance.
@Molerat Molerat force-pushed the feature/tsx-support branch from bf3a3f3 to 0769f32 Compare April 20, 2026 07:41
@sonarqubecloud
Copy link
Copy Markdown

@Molerat Molerat merged commit c954141 into main Apr 20, 2026
6 checks passed
@Molerat Molerat deleted the feature/tsx-support branch April 20, 2026 08:10
Molerat added a commit that referenced this pull request Apr 21, 2026
* chore(deps): update dependency TreesitterExcavationSite to v0.4.1

v0.3.0 of the library changed LOC counting (trailing newlines no longer counted), causing off-by-1 diffs in golden files

* feat(analysis): add TSX language support to UnifiedParser

* fix(analysis): replace fixed sleep with polling in ProjectInputReader

The fixed 100ms sleep was insufficient on CI after the TreeSitter v0.4.1
dependency bump (1.5 MB JAR), which slightly increased JVM startup time.
The upstream svnlogparser process no longer wrote its sync flag within
100ms, so modify read an empty stdin and skipped writing the output file.

Replace with a polling loop (50ms interval, 500ms max) that exits as soon
as data is available, making the pipe chain robust to JVM startup variance.

* fix(analysis): resolve SonarCloud quality gate failures for TSX support

* fix(analysis): complete mean_complexity_per_function descriptor in tsx fixture

* fix(analysis): add missing link and analyzers to mean_complexity_per_function descriptor

---------

Co-authored-by: Ulrike Kiesel <ulrike.kiesel@maibornwolff.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants