Skip to content

fix: support JSONC comments and monorepo tsconfig.json discovery#485

Open
aviavraham wants to merge 2 commits into
ambient-code:mainfrom
aviavraham:431-tsconfig-monorepo-jsonc
Open

fix: support JSONC comments and monorepo tsconfig.json discovery#485
aviavraham wants to merge 2 commits into
ambient-code:mainfrom
aviavraham:431-tsconfig-monorepo-jsonc

Conversation

@aviavraham
Copy link
Copy Markdown
Contributor

@aviavraham aviavraham commented May 31, 2026

Summary

Fixes #431 and #383.

  • JSONC support: Strip // and /* */ comments before parsing tsconfig.json (previously json.load() would choke on comments, common in real-world TypeScript projects like renovatebot/renovate)
  • Monorepo support: Discover all tsconfig.json files recursively via rglob, excluding node_modules/vendor/testdata (previously only checked repo root, failing monorepos like podman-desktop/extension-bootc)
  • Proportional scoring: Aggregate strict mode across all found configs (e.g., 2/3 strict = 67%)

Test plan

Summary by CodeRabbit

  • Documentation

    • Clarified TypeScript criteria: checks all tsconfig files in monorepos (excluding node_modules/vendor/testdata), reports per-file findings, and scores proportionally based on how many have strict mode enabled.
  • Bug Fixes

    • Assessment now correctly aggregates multiple configs, fails when none found, and provides clearer measured values/evidence.
  • Tests

    • Added comprehensive tests covering monorepos, JSONC comment handling, malformed configs, and ignore rules.

…ient-code#431, ambient-code#383)

The TypeScript type annotation assessor now finds all tsconfig.json files
recursively (excluding node_modules) and strips // and /* */ comments
before parsing, fixing false 0-scores on real-world TypeScript repos.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

📝 Walkthrough

Walkthrough

This PR fixes monorepo TypeScript assessment by discovering and scoring all tsconfig.json files instead of just one. The implementation recursively finds configs while excluding node_modules, parses JSONC (JSON with comments), and returns a proportional score: strict_count / total_count passes only when every config has strict mode enabled.

Changes

Monorepo TypeScript Assessment

Layer / File(s) Summary
Core TypeScript assessment refactor with multi-config discovery
src/agentready/assessors/code_quality.py
_assess_typescript_types now discovers all tsconfig.json files using _find_tsconfig_files, strips JSONC comments via _strip_json_comments, tracks how many configs enable strict mode, and returns a proportional Finding score. Parse errors are collected in evidence; returns error Finding if no configs can be parsed or none exist.
Comprehensive test suite for multi-config assessment
tests/unit/test_assessors_typescript.py
Validates assessment correctness across monorepo scenarios: missing/malformed configs, JSONC comment parsing, strict distribution (all/mixed/none), node_modules exclusion, and root+package combination. Also tests _strip_json_comments helper to verify JSONC removal preserves string content and detects remaining parse errors.
Documentation of proportional TypeScript scoring
docs/attributes.md
Documents that type_annotations now checks all tsconfig.json files across monorepo roots and packages (excluding node_modules, vendor, testdata), with scoring proportional to configs with strict mode enabled (e.g., 2/3 strict = 67%).

Possibly related issues

  • #462: Implements scanning of multiple tsconfig.json files, JSONC parsing, and proportional strict-mode scoring — matches the objectives described.

Suggested labels

released

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 73.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title follows Conventional Commits format (fix: ...) and accurately describes the main changes: JSONC comment support and monorepo tsconfig discovery.
Linked Issues check ✅ Passed The PR fully addresses issue #431: implements recursive tsconfig discovery, aggregates strict settings proportionally (e.g., 2/3 → 67%), and handles monorepo layouts correctly.
Out of Scope Changes check ✅ Passed All changes are in scope: documentation updates, TypeScript strict detection logic, helper methods for JSONC parsing and file discovery, and comprehensive test coverage for the new functionality.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 31, 2026

📈 Test Coverage Report

Branch Coverage
This PR 73.8%
Main 73.4%
Diff ✅ +0.4%

Coverage calculated from unit tests only

@aviavraham aviavraham marked this pull request as ready for review May 31, 2026 11:32
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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/attributes.md`:
- Around line 273-275: Update the "tsconfig strict" attribute description in
docs/attributes.md to list all excluded paths recognized by the assessor (not
just node_modules); specifically add vendor and testdata to the excluded-paths
documentation and ensure the scoring note about proportional strict-enabled
configs (e.g., "2/3 strict = 67%") and any partial-credit or pass/fail rules
remain consistent with the assessor logic. Match wording/format to the existing
bullets so the docs stay in sync with the assessor’s recognized paths and
scoring rules.

In `@src/agentready/assessors/code_quality.py`:
- Around line 336-344: The current _find_tsconfig_files method uses
repository.path.rglob which still descends into large excluded trees; change it
to a prunable walk (e.g., use os.walk(repository.path) or Path.iterdir with
recursive stack) and remove "node_modules", "vendor", and "testdata" from the
directories list before recursing so those trees are never traversed; collect
any tsconfig.json files you encounter into found (preserving return of sorted
list) and keep function name _find_tsconfig_files and repository.path as the
location to modify.
- Around line 187-214: The code currently skips malformed tsconfig files by
continuing inside the except block which prevents them from affecting
total_count; instead, in the except (OSError, json.JSONDecodeError) handler
(referencing the errors list, total_count, strict_count, evidence variables),
stop using continue and increment total_count for that file, append a failure
evidence entry (e.g. f"{rel_path}: parse error ({e})") and treat it as
non-strict (do not increment strict_count) so malformed configs count against
the measured ratio; ensure the later score/status calculation
(calculate_proportional_score and status logic) naturally penalizes these files,
or alternatively if you prefer to surface hard failures return a Finding.error
when errors is non-empty after processing all files (adjust the final
total_count==0 check accordingly).
- Around line 181-197: The evaluator currently reads each tsconfig file directly
and checks compilerOptions.strict without resolving "extends"; update the logic
that iterates over tsconfig_files (the loop using tsconfig_path, rel_path, raw,
cleaned and json.loads and calling self._strip_json_comments) to resolve and
merge extended configs so the effective compilerOptions.strict is computed
(handle relative extends, absolute paths, node-style package references, merge
parent compilerOptions into child, detect and prevent circular extends), then
use that effective compilerOptions.strict for strict_count/evidence; also add
unit tests in tests/unit/test_assessors_typescript.py that include a base
tsconfig with "strict": true and a child that extends it to assert the assessor
treats the child as strict.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 809945c2-3d31-4ed1-8556-91c4fdae42fa

📥 Commits

Reviewing files that changed from the base of the PR and between 6470c9f and 4ee5350.

📒 Files selected for processing (3)
  • docs/attributes.md
  • src/agentready/assessors/code_quality.py
  • tests/unit/test_assessors_typescript.py

Comment on lines +181 to +197
for tsconfig_path in tsconfig_files:
rel_path = str(tsconfig_path.relative_to(repository.path))
try:
raw = tsconfig_path.read_text(encoding="utf-8")
cleaned = self._strip_json_comments(raw)
tsconfig = json.loads(cleaned)
except (OSError, json.JSONDecodeError) as e:
errors.append(f"{rel_path}: parse error ({e})")
continue

total_count += 1
strict = tsconfig.get("compilerOptions", {}).get("strict", False)

if strict:
return Finding(
attribute=self.attribute,
status="pass",
score=100.0,
measured_value="strict mode enabled",
threshold="strict mode enabled",
evidence=["tsconfig.json has strict: true"],
remediation=None,
error_message=None,
)
strict_count += 1
evidence.append(f"{rel_path}: strict: true")
else:
return Finding(
attribute=self.attribute,
status="fail",
score=50.0,
measured_value="strict mode disabled",
threshold="strict mode enabled",
evidence=["tsconfig.json missing strict: true"],
remediation=self._create_remediation(),
error_message=None,
)
evidence.append(f"{rel_path}: strict mode disabled")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "TypeScript assessor logic:"
sed -n '181,197p' src/agentready/assessors/code_quality.py

echo
echo 'Search for any tsconfig "extends" handling in the assessor and tests:'
rg -n --type=py '\bextends\b|compilerOptions.*strict|_strip_json_comments|_find_tsconfig_files' \
  src/agentready/assessors/code_quality.py \
  tests/unit/test_assessors_typescript.py

Repository: ambient-code/agentready

Length of output: 2357


Fix TypeScript strict scoring to account for tsconfig inheritance (extends).

src/agentready/assessors/code_quality.py only scores strict from each tsconfig.json’s direct compilerOptions.strict (tsconfig.get("compilerOptions", {}).get("strict", False), lines 181-197). There’s no "extends" handling in the assessor (or in tests/unit/test_assessors_typescript.py), so leaf configs that inherit strict from a base config will be incorrectly treated as non-strict. Add extends resolution (effective compilerOptions) and cover this with unit tests for inherited strict.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/agentready/assessors/code_quality.py` around lines 181 - 197, The
evaluator currently reads each tsconfig file directly and checks
compilerOptions.strict without resolving "extends"; update the logic that
iterates over tsconfig_files (the loop using tsconfig_path, rel_path, raw,
cleaned and json.loads and calling self._strip_json_comments) to resolve and
merge extended configs so the effective compilerOptions.strict is computed
(handle relative extends, absolute paths, node-style package references, merge
parent compilerOptions into child, detect and prevent circular extends), then
use that effective compilerOptions.strict for strict_count/evidence; also add
unit tests in tests/unit/test_assessors_typescript.py that include a base
tsconfig with "strict": true and a child that extends it to assert the assessor
treats the child as strict.

Comment thread src/agentready/assessors/code_quality.py Outdated
Comment on lines +336 to +344
def _find_tsconfig_files(self, repository: Repository) -> list:
"""Find all tsconfig.json files, excluding node_modules/vendor/testdata."""
found = []
for tsconfig in repository.path.rglob("tsconfig.json"):
parts = tsconfig.parts
if "node_modules" in parts or "vendor" in parts or "testdata" in parts:
continue
found.append(tsconfig)
return sorted(found)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Prune excluded directories during traversal.

This still walks node_modules / vendor / testdata and only filters matching files afterward. On large monorepos, descending into those trees can dominate assessor runtime and defeats the intended exclusion behavior. Use a prunable walk (os.walk/Path.walk) and remove excluded dirs before recursing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/agentready/assessors/code_quality.py` around lines 336 - 344, The current
_find_tsconfig_files method uses repository.path.rglob which still descends into
large excluded trees; change it to a prunable walk (e.g., use
os.walk(repository.path) or Path.iterdir with recursive stack) and remove
"node_modules", "vendor", and "testdata" from the directories list before
recursing so those trees are never traversed; collect any tsconfig.json files
you encounter into found (preserving return of sorted list) and keep function
name _find_tsconfig_files and repository.path as the location to modify.

- Document all excluded paths (node_modules, vendor, testdata) in attributes.md
- Count malformed tsconfig.json as non-strict instead of silently skipping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aviavraham
Copy link
Copy Markdown
Contributor Author

Thanks for the review! Addressed #1 and #3 in the latest push. For the remaining two:

Re: extends resolution (#2):
Valid point — configs that inherit strict via extends will be missed. This is a larger change (relative path resolution, node package references, circular detection) and out of scope for this PR which targets #431 and #383. I'll open a follow-up issue to track it.

Re: Pruning excluded dirs during traversal (#4):
The current rglob + filter approach matches the existing pattern used by _find_go_module_roots() in base.py. For a one-time assessment the performance impact is negligible. Happy to optimize if it becomes a bottleneck.

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/attributes.md`:
- Around line 273-275: Update the tsconfig strict-mode scoring description in
the listed bullets so it states that only 100% strict-enabled tsconfig.json
files result in a "pass" (partial scores like "2/3 = 67%" are reported but do
not pass), and explicitly note that malformed tsconfig.json files are treated as
non-strict; edit the lines that currently read "Scoring: proportional to
strict-enabled configs (e.g., 2/3 strict = 67%)" to mention the proportional
score is shown but the assessor requires 100% to return pass and malformed
configs count as non-strict so readers see the implementation matches the docs.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 9b144d19-d675-4aa3-ba9a-c10e764f2bbd

📥 Commits

Reviewing files that changed from the base of the PR and between 4ee5350 and 4665a07.

📒 Files selected for processing (3)
  • docs/attributes.md
  • src/agentready/assessors/code_quality.py
  • tests/unit/test_assessors_typescript.py

Comment thread docs/attributes.md
Comment on lines +273 to +275
- `strict` mode enabled in tsconfig.json (supports JSONC with comments)
- All tsconfig.json files checked (monorepo support: root + subdirectories, excluding node_modules, vendor, testdata)
- Scoring: proportional to strict-enabled configs (e.g., 2/3 strict = 67%)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Document that partial strict scores still fail.

This now reads like 2/3 strict = 67% is the user-facing outcome, but the assessor only returns pass when every discovered tsconfig.json is strict and treats malformed configs as non-strict. Please add that 100% is required to pass so the docs match the implementation.

As per coding guidelines, "Keep docs/attributes.md in sync when changing assessor scoring logic, thresholds, partial credit rules, recognized paths, or pass/fail conditions"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/attributes.md` around lines 273 - 275, Update the tsconfig strict-mode
scoring description in the listed bullets so it states that only 100%
strict-enabled tsconfig.json files result in a "pass" (partial scores like "2/3
= 67%" are reported but do not pass), and explicitly note that malformed
tsconfig.json files are treated as non-strict; edit the lines that currently
read "Scoring: proportional to strict-enabled configs (e.g., 2/3 strict = 67%)"
to mention the proportional score is shown but the assessor requires 100% to
return pass and malformed configs count as non-strict so readers see the
implementation matches the docs.

@aviavraham
Copy link
Copy Markdown
Contributor Author

Verification against reported repos

Ran the updated assessor against both repos from the original issues:

renovatebot/renovate (#383):

status=pass, score=100.0, value=1/1 strict
  - tsconfig.json: strict: true

podman-desktop/extension-bootc (#431):

status=pass, score=100.0, value=4/4 strict
  - packages/backend/tsconfig.json: strict: true
  - packages/frontend/tsconfig.json: strict: true
  - packages/shared/tsconfig.json: strict: true
  - tests/playwright/tsconfig.json: strict: true

Both previously scored 0/100.

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.

[BUG] Fail to find tsconfig.json in monorepo projects

1 participant