Skip to content

Preserve pnpm resolved dependencies when peer ranges overlap - #22

Merged
JosephMaynard merged 7 commits into
masterfrom
fix/investigate-missing-dependencies
Mar 3, 2026
Merged

JosephMaynard merged 7 commits into
masterfrom
fix/investigate-missing-dependencies

Conversation

@JosephMaynard

@JosephMaynard JosephMaynard commented Mar 3, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • stop traversing peerDependencies ranges when building the pnpm dependency graph so resolved nodes are retained
  • add a regression test covering pnpm peer ranges that declare the same package as a resolved dependency

Testing

  • Not run (not requested)

Summary by CodeRabbit

  • Bug Fixes

    • Prevented peer dependency entries from overwriting already-resolved dependencies in the dependency tree.
  • Improvements

    • Smoother graph interactions: consistent hover/clickable state, cleared hover on end events, pointer cursor for clickable nodes, and grab cursor while panning across mouse and touch flows.
  • Tests

    • Added a test ensuring resolved pnpm dependencies are preserved when peer ranges declare the same package.

@coderabbitai

coderabbitai Bot commented Mar 3, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Centralizes hover/cursor state and boundary-aware hit-testing in report-ui graph view; prevents treating pnpm peerDependencies as resolved child refs when building lockfile nodes; adds a test ensuring pnpm-resolved deps are preserved when peer ranges declare the same package.

Changes

Cohort / File(s) Summary
UI Cursor & Interaction
report-ui/graphView.ts, report-ui/style.css
Add bounding checks to hit-testing; introduce setCanvasClickableCursor, resetInteractionVisualState, updateHoverFromClientPosition, and clearHover; replace direct findNode usage with the centralized hover updater across mouse/touch/pan lifecycles; add #graph-canvas.is-clickable { cursor: pointer; }.
pnpm Lockfile Resolution & Tests
src/runners/lockfileGraph.ts, src/runners/npmLs.test.ts
Change buildPnpmNode to merge snapshot.dependencies with only snapshot.optionalDependencies (exclude peerDependencies) to preserve resolved child refs; add test verifying pnpm resolution when peer ranges declare the same package.

Sequence Diagram(s)

sequenceDiagram
    participant User as User (pointer)
    participant Canvas as Canvas DOM
    participant Graph as GraphView
    participant Renderer as Renderer/Popover

    User->>Canvas: pointer move / down / up
    Canvas->>Graph: updateHoverFromClientPosition(clientX, clientY)
    Graph->>Graph: check canvas bounding rect -> findNode or null
    Graph-->>Canvas: setCanvasClickableCursor(true/false)
    Graph->>Renderer: show/hide popover or focus/clear node
    Renderer-->>User: UI update (cursor / hover / popover)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰
I hop where pixels meet the light,
I check the bounds before a bite,
I keep resolved paths snug and tight,
I nudge the cursor—soft and bright,
A tiny hop to set things right.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.76% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective: preserving pnpm resolved dependencies when peer ranges overlap, which aligns with the core changes in lockfileGraph.ts and the regression test added.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/investigate-missing-dependencies

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

@coderabbitai

coderabbitai Bot commented Mar 3, 2026 •

Copy link
Copy Markdown
Contributor

Note

Docstrings generation - SUCCESS
Generated docstrings and committed to branch fix/investigate-missing-dependencies (commit: 77a6d7fafdb26c0814ffca9f14bf833e6773e86e)

Docstrings generation was requested by @JosephMaynard.

The following files were modified:

* `report-ui/graphView.ts`

These files were kept as they were:
* `src/runners/lockfileGraph.ts`

These files were ignored:
* `src/runners/npmLs.test.ts`

These file types are not supported:
* `report-ui/style.css`

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
report-ui/graphView.ts (1)

1753-1753: Consider consolidating cursor/reset calls into one helper.

setCanvasClickableCursor(false) is repeated across multiple lifecycle handlers; a small resetInteractionVisualState() helper would reduce drift risk in future edits.

Also applies to: 1767-1767, 1831-1831, 1946-1946, 1994-1994

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

In `@report-ui/graphView.ts` at line 1753, Create a small helper named
resetInteractionVisualState() that encapsulates the repeated reset behavior (at
minimum calling setCanvasClickableCursor(false) and any related cursor/reset
calls), then replace the multiple inline setCanvasClickableCursor(false)
occurrences with a single call to resetInteractionVisualState() from the
lifecycle handlers where they appear; update references to use the new helper to
avoid drift and keep visual-reset logic centralized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@report-ui/graphView.ts`:
- Line 1753: Create a small helper named resetInteractionVisualState() that
encapsulates the repeated reset behavior (at minimum calling
setCanvasClickableCursor(false) and any related cursor/reset calls), then
replace the multiple inline setCanvasClickableCursor(false) occurrences with a
single call to resetInteractionVisualState() from the lifecycle handlers where
they appear; update references to use the new helper to avoid drift and keep
visual-reset logic centralized.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69d40b4 and 77a6d7f.

📒 Files selected for processing (1)
  • report-ui/graphView.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@report-ui/graphView.ts`:
- Around line 1801-1804: After a pan (when moved is true) you only update the
cursor via setCanvasClickableCursor(Boolean(findNode(event.clientX,
event.clientY))) which leaves hover/selection highlights stale; call the same
hover-update logic that your mousemove handler uses (or explicitly update hover
state at the current coordinates) after setting the cursor so nodes/edges under
the cursor are re-evaluated. Locate the mousemove handler or hover updater used
elsewhere (the function that computes hover from event.clientX/event.clientY)
and invoke it here (or call it indirectly by dispatching the same handler)
immediately after setCanvasClickableCursor to refresh hover highlights.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77a6d7f and 25de384.

📒 Files selected for processing (1)
  • report-ui/graphView.ts

Comment thread report-ui/graphView.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
report-ui/graphView.ts (1)

1814-1818: ⚠️ Potential issue | 🟡 Minor

Clear hover when focus is dismissed on empty click/tap.

When focused, updateHover(...) is intentionally skipped. In the empty-target paths, clearFocus() runs but hover can remain stale until the next move event. Explicitly clearing hover here avoids stale highlight.

💡 Suggested patch
   const node = updateHoverFromClientPosition(event.clientX, event.clientY);
   if (!node) {
     clearFocus();
     hidePopover();
+    updateHover(null);
     return;
   }
       if (!panState.moved && event.changedTouches.length === 1) {
         const node = findNode(
           event.changedTouches[0].clientX,
           event.changedTouches[0].clientY,
         );
         if (!node) {
           clearFocus();
           hidePopover();
+          updateHover(null);
         } else {
           applyFocus(node.slug);
           showPopover(node.slug);
         }
       }

Also applies to: 1935-1943

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

In `@report-ui/graphView.ts` around lines 1814 - 1818, The empty-click path leaves
a stale hover because updateHoverFromClientPosition(...) is skipped when
focused; modify the branches where you do "const node =
updateHoverFromClientPosition(event.clientX, event.clientY); if (!node) {
clearFocus(); hidePopover(); return; }" to also call clearHover() (or the
project's hover-clear helper) before returning so hover state is cleared; apply
the same change for the other analogous block around the updateHover call (the
similar branch later in the file).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@report-ui/graphView.ts`:
- Around line 1814-1818: The empty-click path leaves a stale hover because
updateHoverFromClientPosition(...) is skipped when focused; modify the branches
where you do "const node = updateHoverFromClientPosition(event.clientX,
event.clientY); if (!node) { clearFocus(); hidePopover(); return; }" to also
call clearHover() (or the project's hover-clear helper) before returning so
hover state is cleared; apply the same change for the other analogous block
around the updateHover call (the similar branch later in the file).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 25de384 and c4a6c02.

📒 Files selected for processing (1)
  • report-ui/graphView.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
report-ui/graphView.ts (1)

1315-1319: Consider adding requestRender() for standalone use.

Unlike updateHover(null) which triggers a render, clearHover() silently resets state without marking dirty or requesting a render. Currently this works because callers (handleWindowMouseUp, handleTouchEnd) immediately call clearFocus() which handles rendering. However, this creates a subtle coupling - if clearHover() is called standalone in the future, the UI won't update.

💡 Suggested improvement for robustness
 function clearHover(): void {
   hoverSlug = null;
   hoverNodes = new Set();
   hoverEdges = new Set();
+  dirty = true;
+  requestRender();
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@report-ui/graphView.ts` around lines 1315 - 1319, The clearHover function
currently resets hover state but does not trigger a render, creating a hidden
coupling to callers; modify clearHover() to mark the view dirty and request a
render by calling the same render path used in updateHover (e.g., invoke
requestRender() or markDirty()/requestRender() as appropriate) so that it
behaves standalone, and ensure this change remains consistent with clearFocus
and updateHover(null) behavior to avoid duplicate renders.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@report-ui/graphView.ts`:
- Around line 1315-1319: The clearHover function currently resets hover state
but does not trigger a render, creating a hidden coupling to callers; modify
clearHover() to mark the view dirty and request a render by calling the same
render path used in updateHover (e.g., invoke requestRender() or
markDirty()/requestRender() as appropriate) so that it behaves standalone, and
ensure this change remains consistent with clearFocus and updateHover(null)
behavior to avoid duplicate renders.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4a6c02 and dfd7143.

📒 Files selected for processing (1)
  • report-ui/graphView.ts

@JosephMaynard
JosephMaynard merged commit 2c14871 into master Mar 3, 2026
1 check passed
@JosephMaynard
JosephMaynard deleted the fix/investigate-missing-dependencies branch March 3, 2026 22:13
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.

1 participant