Skip to content

fix(resolve): treat .mjs/.cjs/.mts/.cts as source files for symbol tracing - #85

Merged
shaharkazaz merged 8 commits into
mainfrom
fix/esm-cjs-source-extensions
Jul 27, 2026
Merged

fix(resolve): treat .mjs/.cjs/.mts/.cts as source files for symbol tracing#85
shaharkazaz merged 8 commits into
mainfrom
fix/esm-cjs-source-extensions

Conversation

@shaharkazaz

@shaharkazaz shaharkazaz commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

Problem

Only ts/tsx/js/jsx were treated as source files. A changed .mts/.cts/.mjs/.cjs module (strict-ESM monorepos, dual-package libs, vite.config.mjs…) was classified as an asset: its own project got marked affected, but its exports were never traced — downstream consumer projects were silently missed. Found in the full repo review (finding #5).

Solution

Add the four extensions as first-class source files everywhere. The implementation found four divergent hardcoded extension lists (the review had only found two):

  • src/utils.rs SOURCE_EXTENSIONS (gates source-vs-asset classification)
  • src/semantic/analyzer.rs collect_file_paths (had its own inline matches! filter — without this, .mts files were never parsed at all); now delegates to the shared is_source_file
  • src/semantic/resolve_options.rs: resolver extensions (TS variants before their JS counterparts, mirroring the existing .ts-before-.js precedent, plus .d.mts/.d.cts) and extension_alias entries .mjs→[.mts,.mjs], .cjs→[.cts,.cjs] for TypeScript's import-with-output-extension convention — deliberately NOT letting ESM- and CJS-explicit specifiers cross-resolve
  • src/semantic/mod.rs simple_resolve_relative (the fallback resolver — a previously-unknown third divergent list) mirrored to stay in sync

Testing

TDD: integration tests written first and shown failing (proj-b should be affected... Got: ["proj-a"]): .mts/.mjs traced across projects, ./util.mjsutil.mts and ./helper.cjshelper.cts through extension_alias, plus unit tests proving the simple-resolve fallback additions are load-bearing (shown red against main's version of that file). All tests assert absence of an unrelated project as well as presence.

Second-model review did differential testing against main: confirmed non-vacuous tests, load-bearing extension_alias, behavior-identical is_source_file swap, and disproved a hypothesized require() regression by building the scenario on both revisions.

Tallies (--no-default-features, fixture populated): lib 215; integration 66/67 (failure = test_three_dot_diff_behavior, broken on unmodified main, addressed by #82); cli 15; clippy/fmt clean.

Notes

  • Deliberate over-approximation: extension-less ./utils can resolve to utils.mts (real TS under node16/nodenext wouldn't) — safe direction for affected detection, documented on the tests
  • Resolution probe list grew 5→11; .d.mts/.d.cts sit last so they only cost on failure paths
  • CLAUDE.md Module Resolution section updated

Part of the repo-review fix wave (#83, #84).

Summary by CodeRabbit

  • New Features

    • Expanded module resolution support for .mts, .cts, .mjs, and .cjs files.
    • Improved TypeScript-aware resolution for ESM and CommonJS import extensions.
    • Source analysis now recognizes additional modern module file types.
  • Bug Fixes

    • Fixed cross-project change detection and import tracing for strict ESM/CJS extension conventions.
    • Improved resolution of extensionless imports and .mjs/.cjs imports targeting TypeScript modules.
  • Documentation

    • Updated module resolution guidance with supported extensions and TypeScript preference behavior.

…acing

Changed .mts/.cts/.mjs/.cjs files were classified as "assets" instead of
source files, so their own project was marked affected but their exports
were never traced through the semantic import index — silently dropping
downstream consumer projects (false negatives) in strict-ESM monorepos
and dual-package (ESM+CJS) libraries.

- utils.rs: add the four extensions to SOURCE_EXTENSIONS/is_source_file
- semantic/analyzer.rs: collect_file_paths now delegates to is_source_file
  instead of using its own separate, now-stale hardcoded extension filter
- semantic/resolve_options.rs: add the extensions to the oxc_resolver
  extensions list (TS variants before their JS counterparts, plus
  .d.mts/.d.cts), and add extension_alias entries so a .mjs/.cjs
  specifier resolves to its .mts/.cts source (TypeScript's "import with
  output extension" convention), kept separate from .js/.jsx so ESM- and
  CJS-explicit specifiers can't cross-resolve into each other
- semantic/mod.rs: mirror the same extensions/aliases in
  simple_resolve_relative, the fallback resolver used when oxc_resolver
  fails

Adds integration tests tracing symbol changes across projects through
.mts and .mjs source files (using extension-less imports so the naive
asset filename-text-match fallback can't mask a still-broken fix), plus
a dedicated test for the .mjs-specifier-resolves-to-.mts-source alias,
and unit test coverage for is_source_file with the new extensions.
Closes code-review blocking items on the .mjs/.cjs/.mts/.cts extension
support branch:

- Add unit tests for the simple_resolve_relative fallback (used only
  when oxc_resolver fails), mirroring the existing js->ts remapping
  test: `./utils.mjs` -> on-disk `utils.mts` and `./helper.cjs` ->
  on-disk `helper.cts`. Verified these fail against main's
  src/semantic/mod.rs (fallback logic unmodified) and pass against
  the branch's version.
- Add an integration test exercising the real oxc_resolver
  extension_alias for .cjs -> .cts, mirroring the existing
  .mjs -> .mts test, including an unrelated third project asserted
  as NOT affected.
- Add the same unrelated-third-project assertion to the existing
  .mjs -> .mts extension_alias integration test.
- Document, on the two extension-less source-tracing tests, that
  they rely on domino's deliberately-permissive extension-less
  resolution (real TS under node16/nodenext would require the
  explicit extension).
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@shaharkazaz, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 58 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0218e122-0d2a-41c9-9acf-18f13e84e257

📥 Commits

Reviewing files that changed from the base of the PR and between 3effdbd and f5bb3f0.

📒 Files selected for processing (1)
  • tests/integration_test.rs
📝 Walkthrough

Walkthrough

Module discovery and resolution now recognize .mts, .cts, .mjs, and .cjs, including TypeScript-equivalent aliases and index probing. Unit and integration tests cover fallback resolution and affected-project tracing across project boundaries.

Changes

Strict extension resolution

Layer / File(s) Summary
Source classification and resolver configuration
src/utils.rs, src/semantic/analyzer.rs, src/semantic/resolve_options.rs, CLAUDE.md
Source discovery includes strict ESM/CJS extensions, resolver search paths include MTS/CTS variants, and .mjs/.cjs aliases prefer .mts/.cts.
Fallback remapping and probing
src/semantic/mod.rs, src/semantic/reference_finder.rs
Relative resolution remaps .mjs and .cjs, probes MTS/CTS files and index paths, and tests both mappings.
Affected-project tracing coverage
tests/integration_test.rs
Integration tests cover MTS/MJS source tracking and MJS-to-MTS and CJS-to-CTS imports across projects.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: itayper, nirsky

Sequence Diagram(s)

sequenceDiagram
  participant find_affected
  participant WorkspaceAnalyzer
  participant Resolver
  participant ProjectGraph
  find_affected->>WorkspaceAnalyzer: collect source files
  WorkspaceAnalyzer-->>find_affected: include MTS, CTS, MJS, and CJS files
  find_affected->>Resolver: resolve extension-based imports
  Resolver-->>find_affected: map MJS/CJS to MTS/CTS sources
  find_affected->>ProjectGraph: mark dependent projects affected
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: expanding source-file handling for .mjs, .cjs, .mts, and .cts in symbol tracing.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/esm-cjs-source-extensions

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.

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

📦 Preview Release Available

A preview release has been published for commit f5bb3f0.

Installation

npm install https://github.com/frontops-dev/domino/releases/download/pr-85-f5bb3f0/front-ops-domino-2.0.0.tgz

Running the preview

npx https://github.com/frontops-dev/domino/releases/download/pr-85-f5bb3f0/front-ops-domino-2.0.0.tgz affected

Details

@shaharkazaz
shaharkazaz requested a review from EladBezalel July 26, 2026 11:40
…gin/main

The ort merge strategy interleaved test_mts_source_file_traced_across_projects
(this branch) with test_batch_asset_scan_attributes_references_per_project
(origin/main, from #84) into a single malformed function without leaving
conflict markers. Restored both functions to their original, independent
bodies and ran cargo fmt.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/integration_test.rs (1)

2441-2577: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Share the common repo-scaffolding between the new extension-resolution tests.

The new .mts/.mjs/.cts tests all replicate the same TempDir + git flow + Project construction. Reuse an existing per-test helper where it matches, or add a small shared helper parameterized by the project layout and extension pair, so these variants don’t drift apart.

🤖 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 `@tests/integration_test.rs` around lines 2441 - 2577, Share the repeated
TempDir setup, git initialization/commit flow, project configuration, and
affected-project assertions across the extension-resolution tests at
tests/integration_test.rs:2441-2577, 2722-2852, 2853-2977, and 2978-3102. Add or
reuse a small helper parameterized for each project layout and extension pair,
while preserving each test’s distinct source contents and expected affected
projects.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@tests/integration_test.rs`:
- Around line 2441-2577: Share the repeated TempDir setup, git
initialization/commit flow, project configuration, and affected-project
assertions across the extension-resolution tests at
tests/integration_test.rs:2441-2577, 2722-2852, 2853-2977, and 2978-3102. Add or
reuse a small helper parameterized for each project layout and extension pair,
while preserving each test’s distinct source contents and expected affected
projects.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6f944cfb-1465-480f-8c9b-e7445a148482

📥 Commits

Reviewing files that changed from the base of the PR and between 8d83c99 and 3effdbd.

📒 Files selected for processing (7)
  • CLAUDE.md
  • src/semantic/analyzer.rs
  • src/semantic/mod.rs
  • src/semantic/reference_finder.rs
  • src/semantic/resolve_options.rs
  • src/utils.rs
  • tests/integration_test.rs

…ests

#83 removed root_ts_config/include/ignored_paths; the tests added on this
branch still set them, so the integration test binary stopped compiling
once #83 landed on main.
@shaharkazaz
shaharkazaz merged commit 75a2c74 into main Jul 27, 2026
25 checks passed
@shaharkazaz
shaharkazaz deleted the fix/esm-cjs-source-extensions branch July 27, 2026 20:19
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