Skip to content

Conversation

@justin808
Copy link
Member

@justin808 justin808 commented Nov 2, 2025

Summary

This PR adds support for the exact parameter to the add method, allowing packages to be installed with exact version numbers (without ^ or ~ prefixes).

Changes

  • Added exact parameter to add() and add!() methods in the Base class
  • Implemented exact_flag() helper method in all package manager classes:
    • yarn (classic & berry): --exact
    • npm: --save-exact
    • pnpm: --save-exact
    • bun: --exact
  • Added comprehensive tests for all package managers verifying:
    • Exact version flag works with production dependencies
    • Exact version flag works with dev dependencies
    • Packages are saved with exact versions (e.g., 0.0.0 instead of ^0.0.0)

API Usage

# Install with exact version
package_json.manager.add(["[email protected]"], exact: true)

# Install dev dependency with exact version
package_json.manager.add(["[email protected]"], type: :dev, exact: true)

Test Results

  • ✅ All 286 examples pass (0 failures)
  • ✅ 100% line coverage (1777/1777 LOC)
  • ✅ 100% branch coverage
  • ✅ No RuboCop violations in changed files

Related

Resolves #25

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added an exact option to install dependencies with exact version pinning across npm, yarn, pnpm, and bun-like managers.
  • Documentation

    • Updated README with examples and expanded options table for the new exact behavior.
    • Updated CHANGELOG and project docs to note the new exact install capability.
  • Tests

    • Added tests validating exact-version installs across package managers.

@coderabbitai
Copy link

coderabbitai bot commented Nov 2, 2025

Walkthrough

Adds an optional exact parameter to Manager.add/add! and implementations (npm, pnpm, yarn classic/berry, bun) so callers can request manager-specific exact-install flags (--exact / --save-exact) when adding packages; updates signatures, tests, RBS, README and changelog.

Changes

Cohort / File(s) Summary
Base Manager Interface
sig/package_json/managers/base.rbs, lib/package_json/managers/base.rb
Added optional exact parameter to add and add! signatures.
npm-like & pnpm-like
lib/package_json/managers/npm_like.rb, lib/package_json/managers/pnpm_like.rb, sig/package_json/managers/npm_like.rbs, sig/package_json/managers/pnpm_like.rbs
add(..., exact: false) added; introduced exact_flag(exact)--save-exact and include it when building flags passed to raw install command.
Yarn classic & yarn berry
lib/package_json/managers/yarn_classic_like.rb, lib/package_json/managers/yarn_berry_like.rb, sig/package_json/managers/yarn_classic_like.rbs, sig/package_json/managers/yarn_berry_like.rbs
add(..., exact: false) added; introduced exact_flag(exact)--exact and include it when building flags passed to raw add command.
Bun-like
lib/package_json/managers/bun_like.rb, sig/package_json/managers/bun_like.rbs
add(..., exact: false) added; introduced exact_flag(exact)--exact and include it when building flags for raw add command.
Tests
spec/package_json/managers/*.rb (bun_like_spec, npm_like_spec, pnpm_like_spec, yarn_berry_like_spec, yarn_classic_like_spec)
Added specs for exact:true across production/dev/optional/multi-package cases asserting correct CLI flags and exact ("0.0.0") versions in package.json.
Docs & Changelog
README.md, CHANGELOG.md, CLAUDE.md
README documents exact option and example; changelog notes Unreleased "Added" entry; CLAUDE.md updated with RBS/type guidance.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Manager
    participant CLI as "Package Manager CLI"

    User->>Manager: add(["[email protected]"], exact: true)
    Manager->>Manager: exact_flag(true) => "--exact" / "--save-exact"
    Manager->>Manager: build flags = [type_flag, exact_flag].compact
    Manager->>CLI: raw("add" / "install", flags + packages)
    CLI-->>Manager: install result (success/failure)
    Manager-->>User: return result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas to inspect:
    • Correct flag strings per manager (--exact vs --save-exact) and ordering (flags before packages).
    • RBS signature changes match runtime signatures and visibility (private vs public for exact_flag).
    • Tests assert expected CLI invocation and package.json contents consistently across managers.

Poem

🐇 I hopped through code to add a flag so true,
--exact for some, --save-exact for a few,
No more carets, no chomping range,
Versions steady, neat and strange,
A small hop for code — a tidy view.

Pre-merge checks and finishing touches

✅ 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 'feat: add support for exact version flag in add method' clearly and specifically summarizes the main change in the changeset.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from issue #25: adds exact parameter to add/add! methods across all managers, normalizes flags (--exact for yarn/bun, --save-exact for npm/pnpm), adds comprehensive tests, updates type signatures, and documentation.
Out of Scope Changes check ✅ Passed All changes are in scope: the exact parameter implementation in managers and base class, exact_flag helpers, comprehensive test coverage, RBS type signatures, README documentation, CHANGELOG updates, and CLAUDE.md guidance are all directly related to issue #25 requirements.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch justin808/add-exact-version-flag

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.

@G-Rath
Copy link
Collaborator

G-Rath commented Nov 2, 2025

I'm on the fence about this because using exact versions shouldn't be required

@justin808
Copy link
Member Author

@claude review this PR

@claude
Copy link

claude bot commented Nov 2, 2025

Claude finished @justin808's task —— View job


PR Review Complete

Tasks

  • Read repository guidelines (CLAUDE.md)
  • Review implementation files
  • Review test files
  • Analyze code quality and consistency
  • Provide comprehensive feedback

Code Review

I've reviewed this PR and the implementation looks excellent overall. The code is clean, consistent, and well-tested. Here are my findings:

Strengths

  1. Consistent Implementation Pattern: The exact_flag() method is implemented identically across all package managers, following the established pattern for other helper methods like package_type_install_flag().

  2. Comprehensive Test Coverage: Each package manager has two dedicated tests covering:

    • Production dependencies with exact versions (lib/package_json/managers/npm_like.rb:153-164)
    • Dev dependencies with exact versions (lib/package_json/managers/npm_like.rb:167-179)
    • Tests verify both the correct flag is used and that the version is saved without ^ prefix
  3. Correct Flag Usage: Each package manager uses the appropriate flag:

    • npm/pnpm: --save-exact (lib/package_json/managers/npm_like.rb:70-74)
    • yarn classic/berry: --exact (lib/package_json/managers/yarn_classic_like.rb:82-86)
    • bun: --exact (lib/package_json/managers/bun_like.rb:66-70)
  4. Proper Parameter Threading: The exact parameter is correctly passed through both add() and add!() methods in the base class (lib/package_json/managers/base.rb:43-50) with sensible defaults (exact: false).

  5. Test Quality: Tests verify the actual behavior (exact version in package.json) not just the flag being passed, which is excellent practice.

Minor Observations

  1. Flag Ordering: The implementation places exact_flag after package_type_install_flag in the flags array:

    flags = [package_type_install_flag(type), exact_flag(exact)].compact

    This is fine and consistent across all implementations. The .compact correctly removes nil values when exact: false.

  2. Return Value Pattern: The exact_flag() methods consistently return nil when exact is false rather than using an empty array (unlike some other helper methods like with_frozen_flag). This is fine since .compact handles it, but there's a slight inconsistency in the codebase's approach.

Suggestions for Consideration

  1. Documentation: Consider adding YARD documentation to the exact parameter explaining its purpose:

    # @param exact [Boolean] if true, saves packages with exact versions (no ^ or ~ prefix)
  2. Edge Case - Multiple Packages: While the current tests use single packages, it might be worth adding a test that verifies exact: true works correctly when adding multiple packages at once, e.g., manager.add(["pkg1", "pkg2"], exact: true).

  3. Reviewer's Concern: I noticed G-Rath's comment about exact versions not being required. While this is a valid point about npm ecosystem best practices, having this as an optional feature (defaulting to false) seems like a reasonable approach for users who have specific requirements for exact versions.

Summary

This PR is well-implemented with:

  • Clean, consistent code across all package managers
  • Excellent test coverage (100% line and branch coverage maintained)
  • Correct usage of package manager flags
  • No breaking changes (backward compatible with exact: false default)
  • Zero RuboCop violations

The implementation follows established patterns in the codebase and integrates seamlessly with existing functionality. I recommend approval with the optional documentation enhancement noted above.


@claude
Copy link

claude bot commented Nov 2, 2025

Code Review for PR #29

Summary

This PR adds support for the exact parameter to the add method, enabling packages to be installed with exact version numbers (without ^ or ~ prefixes). The implementation is clean, well-tested, and solves a legitimate use case for React on Rails and similar projects requiring version pinning.


✅ Strengths

1. Excellent Test Coverage

  • Comprehensive tests across all 5 package managers (yarn classic, yarn berry, npm, pnpm, bun)
  • Tests verify both the command generation and actual package.json modification
  • Edge cases covered: production deps, dev deps, and multiple packages
  • Maintained 100% line and branch coverage (287 examples, 0 failures)

2. Consistent Implementation Pattern

  • The exact_flag(exact) helper method follows the same pattern as existing helpers like package_type_install_flag(type)
  • Proper use of Array#compact to handle optional flags cleanly
  • Implementation is identical across all manager classes (good for maintainability)

3. Good Documentation

4. API Design

  • The exact: false default parameter is sensible (maintains backward compatibility)
  • Consistent with existing API patterns (similar to type: parameter)
  • The keyword argument approach is idiomatic Ruby

💡 Observations & Minor Suggestions

1. Documentation Enhancement

The README.md hasn't been updated to document this new feature. Consider adding an entry to the "Adding dependencies" section:

# adds react-on-rails with exact version (no ^ or ~)
package_json.manager.add(["[email protected]"], exact: true)

This would help users discover the feature. Reference: README.md:169-184

2. Potential Edge Case

The implementation correctly passes the exact flag through in add!() at base.rb:55:

raise_exited_with_non_zero_code_error unless add(packages, type: type, exact: exact)

This is correct, but I notice there's a minor inconsistency in the remove! method formatting (lines 64-66) which has unusual line breaks. Not related to this PR, but worth noting for consistency.

3. Implementation Consistency

All implementations correctly use:

flags = [package_type_install_flag(type), exact_flag(exact)].compact
raw("add", flags + packages)

This is excellent - the ordering ensures flags come before package names, which is what all package managers expect.

4. Test Quality

The test for multiple packages in yarn_classic_like_spec.rb:182-195 using %w[example example2] is excellent and follows RuboCop style guidelines. This test only appears in the yarn_classic spec - while not strictly necessary, having it in all manager specs would provide extra confidence.


🔒 Security Considerations

No security concerns identified:

  • No user input is directly interpolated into shell commands
  • The exact parameter is a boolean, preventing injection attacks
  • Package names are passed as array arguments to Kernel.system, which properly escapes them
  • The implementation follows the same safe patterns as existing code

⚡ Performance Considerations

No performance issues:

  • The Array#compact call has negligible overhead
  • No additional system calls introduced
  • Flag generation is done inline without extra method calls

🐛 Potential Bugs

No bugs identified:

  • All package managers use the correct flags:
    • yarn (classic & berry): --exact
    • npm & pnpm: --save-exact
    • bun: --exact
  • Flag ordering is correct (flags before packages)
  • The exact parameter is properly threaded through add!()

📊 Overall Assessment

Recommendation: ✅ APPROVE

This is a well-implemented feature that:

The only minor improvement would be updating the README.md to document the new exact parameter, but this is optional and could be done in a follow-up if preferred.

Great work! 🎉

Copy link

@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: 3

🧹 Nitpick comments (2)
spec/package_json/managers/bun_like_spec.rb (1)

152-178: Consider adding test for multiple packages with exact flag.

The tests cover production and dev dependencies with exact versions, but yarn_classic_like_spec.rb includes an additional test case for multiple packages (lines 181-194 in that file). Adding a similar test here would provide consistent coverage across all package managers.

Example test case:

it "supports adding multiple packages with exact version" do
  with_package_json_file do
    result = manager.add(%w[example example2], exact: true)

    expect(result).to be(true)
    expect_manager_to_be_invoked_with("add --exact example example2")
    expect_package_json_with_content({
      "dependencies" => {
        "example" => "0.0.0",
        "example2" => "0.0.0"
      }
    })
  end
end
spec/package_json/managers/pnpm_like_spec.rb (1)

155-181: Consider adding test for multiple packages with exact flag.

Similar to the bun_like tests, this file would benefit from a test case for multiple packages with exact versions for consistency with yarn_classic_like_spec.rb (lines 181-194).

Example test case:

it "supports adding multiple packages with exact version" do
  with_package_json_file do
    result = manager.add(%w[example example2], exact: true)

    expect(result).to be(true)
    expect_manager_to_be_invoked_with("add --save-prod --save-exact example example2")
    expect_package_json_with_content({
      "dependencies" => {
        "example" => "0.0.0",
        "example2" => "0.0.0"
      }
    })
  end
end
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d32d6fa and 37297fb.

⛔ Files ignored due to path filters (1)
  • Gemfile.lock is excluded by !**/*.lock
📒 Files selected for processing (18)
  • .editorconfig (1 hunks)
  • .gitattributes (1 hunks)
  • .github/workflows/claude-code-review.yml (1 hunks)
  • .github/workflows/claude.yml (0 hunks)
  • .gitignore (1 hunks)
  • README.md (1 hunks)
  • lib/package_json/managers/base.rb (1 hunks)
  • lib/package_json/managers/bun_like.rb (2 hunks)
  • lib/package_json/managers/npm_like.rb (2 hunks)
  • lib/package_json/managers/pnpm_like.rb (2 hunks)
  • lib/package_json/managers/yarn_berry_like.rb (2 hunks)
  • lib/package_json/managers/yarn_classic_like.rb (2 hunks)
  • package.json (1 hunks)
  • spec/package_json/managers/bun_like_spec.rb (1 hunks)
  • spec/package_json/managers/npm_like_spec.rb (1 hunks)
  • spec/package_json/managers/pnpm_like_spec.rb (1 hunks)
  • spec/package_json/managers/yarn_berry_like_spec.rb (1 hunks)
  • spec/package_json/managers/yarn_classic_like_spec.rb (1 hunks)
💤 Files with no reviewable changes (1)
  • .github/workflows/claude.yml
🧰 Additional context used
🧬 Code graph analysis (11)
lib/package_json/managers/yarn_berry_like.rb (5)
lib/package_json/managers/base.rb (2)
  • add (46-48)
  • raw (119-121)
lib/package_json/managers/bun_like.rb (3)
  • add (19-22)
  • package_type_install_flag (72-83)
  • exact_flag (66-70)
lib/package_json/managers/npm_like.rb (3)
  • add (25-28)
  • package_type_install_flag (76-87)
  • exact_flag (70-74)
lib/package_json/managers/pnpm_like.rb (3)
  • add (19-22)
  • package_type_install_flag (77-88)
  • exact_flag (71-75)
lib/package_json/managers/yarn_classic_like.rb (3)
  • add (19-22)
  • package_type_install_flag (88-99)
  • exact_flag (82-86)
spec/package_json/managers/yarn_classic_like_spec.rb (4)
spec/support/temp_helpers.rb (1)
  • with_package_json_file (14-22)
lib/package_json/managers/base.rb (1)
  • add (46-48)
lib/package_json/managers/yarn_classic_like.rb (1)
  • add (19-22)
spec/support/expect_helpers.rb (2)
  • expect_manager_to_be_invoked_with (69-76)
  • expect_package_json_with_content (63-67)
lib/package_json/managers/yarn_classic_like.rb (5)
lib/package_json/managers/base.rb (2)
  • add (46-48)
  • raw (119-121)
lib/package_json/managers/bun_like.rb (3)
  • add (19-22)
  • package_type_install_flag (72-83)
  • exact_flag (66-70)
lib/package_json/managers/npm_like.rb (3)
  • add (25-28)
  • package_type_install_flag (76-87)
  • exact_flag (70-74)
lib/package_json/managers/pnpm_like.rb (3)
  • add (19-22)
  • package_type_install_flag (77-88)
  • exact_flag (71-75)
lib/package_json/managers/yarn_berry_like.rb (3)
  • add (19-22)
  • package_type_install_flag (74-85)
  • exact_flag (68-72)
lib/package_json/managers/pnpm_like.rb (3)
lib/package_json/managers/base.rb (2)
  • add (46-48)
  • raw (119-121)
lib/package_json/managers/bun_like.rb (3)
  • add (19-22)
  • package_type_install_flag (72-83)
  • exact_flag (66-70)
lib/package_json/managers/npm_like.rb (3)
  • add (25-28)
  • package_type_install_flag (76-87)
  • exact_flag (70-74)
spec/package_json/managers/bun_like_spec.rb (4)
spec/support/temp_helpers.rb (1)
  • with_package_json_file (14-22)
lib/package_json/managers/base.rb (1)
  • add (46-48)
lib/package_json/managers/bun_like.rb (1)
  • add (19-22)
spec/support/expect_helpers.rb (2)
  • expect_manager_to_be_invoked_with (69-76)
  • expect_package_json_with_content (63-67)
spec/package_json/managers/pnpm_like_spec.rb (8)
spec/support/temp_helpers.rb (1)
  • with_package_json_file (14-22)
lib/package_json/managers/base.rb (1)
  • add (46-48)
lib/package_json/managers/bun_like.rb (1)
  • add (19-22)
lib/package_json/managers/npm_like.rb (1)
  • add (25-28)
lib/package_json/managers/pnpm_like.rb (1)
  • add (19-22)
lib/package_json/managers/yarn_berry_like.rb (1)
  • add (19-22)
lib/package_json/managers/yarn_classic_like.rb (1)
  • add (19-22)
spec/support/expect_helpers.rb (2)
  • expect_manager_to_be_invoked_with (69-76)
  • expect_package_json_with_content (63-67)
lib/package_json/managers/bun_like.rb (5)
lib/package_json/managers/base.rb (2)
  • add (46-48)
  • raw (119-121)
lib/package_json/managers/npm_like.rb (3)
  • add (25-28)
  • package_type_install_flag (76-87)
  • exact_flag (70-74)
lib/package_json/managers/pnpm_like.rb (3)
  • add (19-22)
  • package_type_install_flag (77-88)
  • exact_flag (71-75)
lib/package_json/managers/yarn_berry_like.rb (3)
  • add (19-22)
  • package_type_install_flag (74-85)
  • exact_flag (68-72)
lib/package_json/managers/yarn_classic_like.rb (3)
  • add (19-22)
  • package_type_install_flag (88-99)
  • exact_flag (82-86)
lib/package_json/managers/npm_like.rb (5)
lib/package_json/managers/base.rb (2)
  • add (46-48)
  • raw (119-121)
lib/package_json/managers/bun_like.rb (3)
  • add (19-22)
  • package_type_install_flag (72-83)
  • exact_flag (66-70)
lib/package_json/managers/pnpm_like.rb (3)
  • add (19-22)
  • package_type_install_flag (77-88)
  • exact_flag (71-75)
lib/package_json/managers/yarn_berry_like.rb (3)
  • add (19-22)
  • package_type_install_flag (74-85)
  • exact_flag (68-72)
lib/package_json/managers/yarn_classic_like.rb (3)
  • add (19-22)
  • package_type_install_flag (88-99)
  • exact_flag (82-86)
lib/package_json/managers/base.rb (5)
lib/package_json/managers/bun_like.rb (1)
  • add (19-22)
lib/package_json/managers/npm_like.rb (1)
  • add (25-28)
lib/package_json/managers/pnpm_like.rb (1)
  • add (19-22)
lib/package_json/managers/yarn_berry_like.rb (1)
  • add (19-22)
lib/package_json/managers/yarn_classic_like.rb (1)
  • add (19-22)
spec/package_json/managers/npm_like_spec.rb (3)
spec/support/temp_helpers.rb (1)
  • with_package_json_file (14-22)
lib/package_json/managers/npm_like.rb (1)
  • add (25-28)
spec/support/expect_helpers.rb (2)
  • expect_manager_to_be_invoked_with (69-76)
  • expect_package_json_with_content (63-67)
spec/package_json/managers/yarn_berry_like_spec.rb (3)
spec/support/temp_helpers.rb (1)
  • with_package_json_file (14-22)
lib/package_json/managers/yarn_berry_like.rb (1)
  • add (19-22)
spec/support/expect_helpers.rb (2)
  • expect_manager_to_be_invoked_with (69-76)
  • expect_package_json_with_content (63-67)
🔇 Additional comments (19)
.gitattributes (1)

1-4: Good infrastructure setup for Yarn monorepo tooling.

The .gitattributes configuration properly marks Yarn-related files and directories with appropriate attributes. Marking .yarn/ as linguist-vendored excludes it from language statistics (standard practice for vendor directories), and tagging Yarn releases, plugins, and PnP files as binary and linguist-generated correctly reflects their nature as build/tooling artifacts.

.github/workflows/claude-code-review.yml (1)

1-59: Scope concern: workflow configuration changes not related to PR objectives.

This PR is titled "feat: add support for exact version flag in add method," but the only file under review is a GitHub Actions workflow configuration. Per the PR summary, changes should be in the Base class, package manager implementations, and test files. Please verify if this workflow file change is intentional or if the actual implementation files are missing from this review.

README.md (2)

181-182: LGTM! Clear example of exact flag usage.

The example effectively demonstrates the practical use case mentioned in issue #25 (React on Rails requiring exact version matching between gem and npm package).


185-189: LGTM! Documentation clearly describes the exact option.

The updated table properly documents the new exact parameter, its default behavior, and its effect on version prefixes.

lib/package_json/managers/base.rb (1)

43-56: LGTM! Base class correctly defines the exact parameter.

The implementation properly:

  • Adds the exact parameter with a sensible default (false) for backward compatibility
  • Documents the parameter via @param comments
  • Forwards the parameter from add!() to add()
  • Follows the same pattern as the existing type parameter
spec/package_json/managers/yarn_classic_like_spec.rb (1)

153-194: LGTM! Comprehensive test coverage for exact flag.

The tests thoroughly validate:

  • Production dependencies with exact version
  • Dev dependencies with exact version
  • Multiple packages with exact version
  • Correct command invocation (with --exact flag)
  • Correct package.json content (version without ^ prefix)
.editorconfig (1)

4-8: The review comment contradicts its own evidence.

The code snippet labeled "final state" explicitly shows charset = utf-8 is present at line 4, yet the comment claims this setting was removed. The current .editorconfig file matches the provided code snippet exactly and contains charset = utf-8. Additionally, trim_trailing_whitespace does not appear in the current file or the snippet provided.

The concern about removal of these settings is not supported by the code changes shown.

Likely an incorrect or invalid review comment.

spec/package_json/managers/yarn_berry_like_spec.rb (1)

158-184: LGTM! Comprehensive test coverage for exact version installation.

The test cases properly verify both production and dev dependency installation with exact versions. The assertions correctly check command invocation (add --exact and add --dev --exact) and package.json content ("0.0.0" instead of "^0.0.0").

spec/package_json/managers/npm_like_spec.rb (1)

153-179: LGTM! Tests correctly verify npm's exact version flag.

The test cases properly exercise the npm-specific --save-exact flag and verify both command invocation and package.json updates. The implementation correctly distinguishes npm's flag from yarn/bun's --exact.

lib/package_json/managers/yarn_classic_like.rb (2)

19-21: LGTM! Clean implementation of exact version support.

The method properly integrates the exact parameter with the existing type parameter, using .compact to cleanly handle optional flags.


82-86: LGTM! Correct flag for Yarn Classic.

The helper correctly returns --exact for Yarn Classic, consistent with the package manager's documented behavior.

lib/package_json/managers/bun_like.rb (2)

19-21: LGTM! Consistent implementation across managers.

The implementation follows the established pattern used in other package managers, ensuring a consistent API surface.


66-70: LGTM! Correct flag for Bun.

The helper correctly returns --exact for Bun, aligning with Bun's package manager behavior.

lib/package_json/managers/npm_like.rb (2)

25-27: LGTM! Proper integration with npm's install command.

The implementation correctly combines the exact flag with npm's existing install command structure.


70-74: LGTM! Correct flag for npm.

The helper correctly returns --save-exact for npm, which differs from yarn/bun's --exact flag. This is the proper npm-specific flag for saving exact versions.

lib/package_json/managers/yarn_berry_like.rb (2)

19-21: LGTM! Consistent implementation for Yarn Berry.

The implementation maintains consistency with other managers while properly supporting Yarn Berry's exact version flag.


68-72: LGTM! Correct flag for Yarn Berry.

The helper correctly returns --exact for Yarn Berry, consistent with both classic and modern Yarn versions.

lib/package_json/managers/pnpm_like.rb (2)

19-21: LGTM! Proper integration with pnpm's add command.

The implementation correctly integrates the exact flag with pnpm's existing command structure, following the same pattern as other managers.


71-75: LGTM! Correct flag for pnpm.

The helper correctly returns --save-exact for pnpm, which follows npm's flag convention rather than yarn/bun's --exact.

.gitignore Outdated
Comment on lines 1 to 17
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

node_modules/
.idea/
.vscode/
# Whether you use PnP or not, the node_modules folder is often used to store
# build artifacts that should be gitignored
node_modules

# rspec failure tracking
.rspec_status
# Swap the comments on the following lines if you wish to use zero-installs
# In that case, don't forget to run `yarn config set enableGlobalCache false`!
# Documentation here: https://yarnpkg.com/features/caching#zero-installs

#!.yarn/cache
.pnp.*
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Yarn zero-installs infrastructure changes not mentioned in PR objectives.

The .gitignore changes introduce comprehensive support for Yarn's zero-installs feature, including patterns for .yarn/*, PnP artifacts, and related documentation. While these are valid infrastructure improvements, they appear unrelated to the exact version flag feature and aren't mentioned in the PR description or linked issue #25.

Consider either:

  • Updating the PR description to explain these infrastructure changes
  • Moving these changes to a separate PR focused on Yarn setup

I'll verify the review comment by investigating the PR context and whether the .gitignore changes are actually scope creep.

</script>

🏁 Script executed:

#!/bin/bash
# Extract PR and git context to understand the actual scope
echo "=== Git log (recent commits) ==="
git log --oneline -10

echo -e "\n=== Git show HEAD (current commit details) ==="
git show --stat HEAD

echo -e "\n=== Git diff HEAD^ (changes in latest commit) ==="
git diff HEAD^ --name-only 2>/dev/null || echo "No previous commit available"

echo -e "\n=== Check for PR/commit metadata or description files ==="
if [ -f ".github/pull_request_template.md" ]; then
  echo "Found PR template:"
  head -20 .github/pull_request_template.md
fi

echo -e "\n=== Look for recent commits mentioning .gitignore or Yarn ==="
git log --oneline --all --grep="gitignore\|yarn\|Yarn" -10 2>/dev/null || echo "No matching commits found"

Length of output: 1750


I need to find when and if the .gitignore changes mentioned in the review actually exist in this PR branch.


🏁 Script executed:

#!/bin/bash
# Check current .gitignore and its history
echo "=== Current .gitignore content ==="
cat .gitignore 2>/dev/null || echo "File not found"

echo -e "\n=== Git log for .gitignore (last 15 commits touching it) ==="
git log --oneline -15 -- .gitignore 2>/dev/null || echo "No history found"

echo -e "\n=== Git blame on .gitignore (first 20 lines) ==="
git blame .gitignore 2>/dev/null | head -20 || echo "Cannot blame file"

echo -e "\n=== Check if .gitignore is modified/staged in current branch ==="
git status .gitignore 2>/dev/null || echo "Not tracked or no changes"

echo -e "\n=== Git show for .gitignore on recent commits ==="
git show HEAD:.gitignore 2>/dev/null | head -20 || echo "Not in HEAD"
git show HEAD~5:.gitignore 2>/dev/null | head -20 || echo "Not in HEAD~5"

Length of output: 2841


I need to determine what files are actually new in this PR by finding the merge base.

</script>

🏁 Script executed:

#!/bin/bash
# Determine what's new in this PR vs the base
echo "=== Current branch and merge info ==="
git branch -vv
git log --oneline --decorate -5

echo -e "\n=== Find merge base (PR base commit) ==="
MERGE_BASE=$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main 2>/dev/null || echo "unknown")
echo "Merge base: $MERGE_BASE"

if [ "$MERGE_BASE" != "unknown" ]; then
  echo -e "\n=== Files changed in this PR (from merge base to HEAD) ==="
  git diff --name-only $MERGE_BASE..HEAD
  
  echo -e "\n=== .gitignore changes in this PR ==="
  git diff $MERGE_BASE..HEAD -- .gitignore 2>/dev/null || echo ".gitignore not changed in this PR"
fi

echo -e "\n=== Commit that modified .gitignore (a8cbff1) details ==="
git show a8cbff1 --stat 2>/dev/null | head -30 || echo "Cannot show commit"

Length of output: 960


Let me compare the .gitignore directly between the current branch and main.

</script>

🏁 Script executed:

#!/bin/bash
# Compare .gitignore between branches directly
echo "=== .gitignore on main branch ==="
git show main:.gitignore 2>/dev/null || git show origin/main:.gitignore 2>/dev/null || echo "Cannot access main"

echo -e "\n=== .gitignore on current branch (HEAD) ==="
cat .gitignore

echo -e "\n=== Direct diff: main vs HEAD on .gitignore ==="
git diff main .gitignore 2>/dev/null || git diff origin/main .gitignore 2>/dev/null || echo "Cannot diff with main"

echo -e "\n=== PR description or commit message context ==="
git log --format="%H %s" a8cbff1..37297fb 2>/dev/null | head -20

Length of output: 1688


Let me examine the project context and the actual feature implementation to determine if these .gitignore changes are necessary for the "exact version flag" feature.

</script>

🏁 Script executed:

#!/bin/bash
# Understand the project and feature context
echo "=== package.json content ==="
cat package.json 2>/dev/null || echo "No package.json"

echo -e "\n=== README header to understand project type ==="
head -30 README.md

echo -e "\n=== Check commit 20e1c04 (exact version flag feature) ==="
git show 20e1c04 --stat 2>/dev/null | head -40

echo -e "\n=== Look at lib/yarn_add.rb (likely implementation) ==="
find . -name "*yarn*" -type f -o -name "*add*" -type f | grep -E '\.(rb|js)$' | head -10

Length of output: 3652


Scope creep confirmed: .gitignore infrastructure changes are unrelated to exact version flag feature.

The .gitignore modifications replace Ruby/Rails patterns with Yarn/zero-installs patterns—a complete infrastructure overhaul unrelated to the exact version flag feature added in commit 20e1c04. These changes are new to this PR and represent bundled scope that should either be documented in the PR description or separated into a dedicated infrastructure PR.

Consider updating the PR description to explain these project setup changes or moving them to a separate PR focused on Yarn configuration.

🤖 Prompt for AI Agents
In .gitignore around lines 1 to 17, you added Yarn/zero-install and related
entries that are unrelated to the "exact version flag" feature; either remove
these infrastructure changes from this branch and submit them in a dedicated
infra PR, or keep them but update the current PR description to explicitly
document the .gitignore/Yarn changes and why they belong here (include
rationale, migration steps, and any developer impact). Ensure the PR only
contains feature changes or clearly-labelled infra changes to avoid scope creep.

package.json Outdated
Comment on lines 1 to 4
{
"name": "package_json-20251102-36220-vfpcqr",
"packageManager": "[email protected]"
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Remove test artifact from repository.

This package.json file appears to be a test artifact with an auto-generated name (package_json-20251102-36220-vfpcqr) that includes a timestamp and random identifier. Test artifacts should not be committed to the repository.

Please remove this file from the commit. If package.json files are created during testing, ensure they are properly cleaned up or covered by .gitignore patterns.

🤖 Prompt for AI Agents
In package.json around lines 1 to 4, this file is a test artifact
(auto-generated name with timestamp/random id) and must be removed from the
commit; delete the file from the repository (git rm --cached or git rm if
already committed) and update the commit, then add a rule to .gitignore to
prevent auto-generated package.json files (or the test output directory) from
being committed and modify the test or build scripts to clean up temporary
package.json files after tests (or write them to a tmp directory) so they are
not left in the workspace.

@claude
Copy link

claude bot commented Nov 3, 2025

Code Review - PR #29: Add support for exact version flag

Summary

This PR successfully adds support for the exact parameter to the add method across all package managers (npm, yarn classic, yarn berry, pnpm, bun). The implementation is clean, consistent, and well-tested.


✅ Strengths

1. Excellent Code Quality

  • Consistent implementation across all 5 package manager classes with identical patterns
  • Proper abstraction: exact_flag() helper method follows existing patterns like package_type_install_flag()
  • Correct flag mapping for each package manager:
    • Yarn (classic & berry) & Bun: --exact
    • npm & pnpm: --save-exact

2. Comprehensive Documentation

  • YARD documentation added to both add() and add!() methods in base.rb:42-56
  • README updated with clear example and options table (README.md:181-188)
  • Proper parameter descriptions for all three parameters

3. Excellent Test Coverage

  • Tests added for all 5 package managers
  • Each manager has 2-3 test cases covering:
    • Exact version with production dependencies
    • Exact version with dev dependencies
    • Multiple packages with exact flag (yarn_classic only, but sufficient)
  • Tests verify both command construction AND package.json content

4. Backward Compatibility

  • exact parameter defaults to false, maintaining existing behavior
  • No breaking changes to the API

⚠️ Issues to Address

1. CRITICAL: Unrelated File Changes

The PR includes changes to configuration files that appear unrelated to the feature:

  • .editorconfig - Simplified/reformatted (removed comments, reordered)
  • .gitignore - Completely replaced with Yarn-specific ignores
  • .gitattributes - Added Yarn-specific attributes
  • package.json - Added temporary test file with name package_json-20251102-36220-vfpcqr
  • Gemfile.lock - Added platform arm64-darwin-24

These changes should be removed from this PR as they:

  • Appear to be local development artifacts
  • Don't relate to the exact version feature
  • Could cause issues for other contributors
  • Make the PR diff harder to review

Recommend:

git restore .editorconfig .gitignore .gitattributes package.json
git checkout HEAD~1 Gemfile.lock  # or restore original

2. Minor: Test Coverage Gap

Only yarn_classic_like_spec.rb has the "multiple packages with exact version" test (lines 181-194). While one test is sufficient, consider adding it to other managers for consistency.


🔍 Code Analysis

Implementation Pattern (consistent across all managers):

def add(packages, type: :production, exact: false)
  flags = [package_type_install_flag(type), exact_flag(exact)].compact
  raw("add", flags + packages)
end

def exact_flag(exact)
  return "--exact" if exact  # or "--save-exact" for npm/pnpm
  nil
end

Why this is good:

  • Uses .compact to elegantly filter out nil values
  • Flag ordering is consistent (type flag, then exact flag)
  • Returns nil instead of empty string for cleaner code
  • Follows Ruby conventions and existing codebase patterns

🔒 Security Considerations

✅ No security concerns identified

  • No user input is directly interpolated into shell commands
  • Package names are passed as array elements to Kernel.system
  • No injection vulnerabilities introduced

🚀 Performance Considerations

✅ No performance concerns

  • Negligible overhead from parameter passing
  • No additional system calls introduced
  • Flag construction is O(1)

📝 Suggestions (Optional)

1. Consider adding integration test
While unit tests verify command construction, an integration test that actually runs a package manager and verifies the package.json contents would add confidence. (Though this may be out of scope for this gem)

2. Document behavior with version specifiers
Consider adding a note in the README about how exact interacts with version specifiers:

  • add(["[email protected]"], exact: true) → Installs 16.0.0 exactly ✅
  • add(["react@^16.0.0"], exact: true) → What happens? (Package manager behavior may vary)

✅ Checklist Compliance

Based on CLAUDE.md requirements:

  • ✅ RuboCop: Need to verify (command requires approval, but PR description claims 0 violations)
  • ⚠️ Files end with newline: Need to verify the config files if kept
  • ✅ Tests pass: PR description shows 287 examples, 0 failures
  • ✅ 100% coverage maintained (1777/1777 LOC)

🎯 Final Recommendation

APPROVE with changes requested

The core feature implementation is excellent - well-designed, properly tested, and follows Ruby/gem conventions perfectly. However, the unrelated configuration file changes should be removed before merging.

Action items before merge:

  1. Remove unrelated changes to .editorconfig, .gitignore, .gitattributes, package.json
  2. Review Gemfile.lock changes (platform addition may be legitimate)
  3. Verify RuboCop passes on the Ruby implementation files
  4. Consider adding the "multiple packages" test to other managers (optional)

Great work on the feature implementation! The code quality is high and the API design is intuitive. Once the config file changes are cleaned up, this will be ready to merge.


Reviewed by Claude Code

@claude
Copy link

claude bot commented Nov 3, 2025

PR Review: Add Exact Version Flag Support

Thank you for this well-structured PR! The implementation adds valuable functionality for precise dependency version management. Here's my detailed review:

✅ Strengths

  1. Comprehensive Implementation: The feature is consistently implemented across all package managers (npm, yarn classic, yarn berry, pnpm, bun) with correct flag usage for each.

  2. Excellent Test Coverage: All package managers have thorough test coverage including:

    • Production dependencies with exact flag
    • Dev dependencies with exact flag
    • Multiple packages (for yarn classic)
    • Clear verification of both command invocation and package.json content
  3. Good Documentation:

    • Clear YARD documentation added to base class methods
    • README updated with usage example
    • PR description is detailed and informative
  4. API Design: The exact: false default parameter is a good choice - it's backward compatible and non-breaking.

  5. Consistent Code Patterns: The exact_flag method follows the same pattern as existing helper methods like package_type_install_flag.

⚠️ Issues Found

1. CRITICAL: Unintended Configuration Files Committed

The PR includes files that should NOT be committed to the repository:

  • package.json - This appears to be a temporary test file (name: "package_json-20251102-36220-vfpcqr")
  • Changes to .gitignore that completely replace the Ruby gem ignore patterns with Yarn-specific ones
  • Changes to .editorconfig that remove important settings like trim_trailing_whitespace
  • New .gitattributes file for Yarn vendoring

These changes suggest development/testing artifacts were accidentally staged. The original .gitignore was designed for a Ruby gem and included important entries like:

/.bundle/
/coverage/
/pkg/
/spec/reports/
.rspec_status

Action Required: Please revert the changes to .gitignore, .editorconfig, and .gitattributes, and remove the package.json file from this PR.

2. Gemfile.lock Platform Addition

The PR adds arm64-darwin-24 to platforms in Gemfile.lock. While this is likely from your local development environment:

  • If this is a legitimate platform support addition, it's fine to keep
  • If it's incidental, it could be removed, though it's harmless

💡 Minor Suggestions

  1. CHANGELOG Update: According to CLAUDE.md, user-visible features should be documented in CHANGELOG.md. Consider adding an entry like:

    ### Added
    - [PR 29](https://github.com/shakacode/package_json/pull/29) by [justin808](https://github.com/justin808): Add support for `exact` parameter in `add` method to install packages with exact versions
  2. Test Consistency: The yarn_classic_like_spec.rb has an extra test case for multiple packages with exact version, but other managers don't. Consider adding this test to all managers for consistency, or document why it's only needed for yarn classic.

  3. Edge Case Testing: Consider adding a test to verify behavior when both type and exact parameters are used together with optional dependencies (:optional).

🔒 Security & Performance

  • ✅ No security concerns identified
  • ✅ No performance implications - the change only adds an optional flag
  • ✅ Backward compatible - existing code will continue to work unchanged

📝 Before Merging

MUST DO:

  1. Remove accidentally committed files: package.json, revert .gitignore, .editorconfig, and .gitattributes changes
  2. Run bundle exec rubocop to ensure no violations (as per CLAUDE.md requirements)
  3. Verify all tests still pass after removing the extra files

SHOULD DO:

  1. Add CHANGELOG.md entry for this user-facing feature

Summary

The core feature implementation is excellent - well-tested, properly documented, and consistently applied across all package managers. However, there are critical unintended file changes that need to be removed before merging. Once those are reverted, this PR will be ready to merge.

Rating: Approve with required changes ⚠️

justin808 and others added 3 commits November 4, 2025 16:58
- Add exact parameter to add() and add!() methods across all package managers
- Implement exact_flag() helper in each manager:
  - yarn/bun: --exact
  - npm/pnpm: --save-exact
- Add comprehensive tests for all package managers (yarn classic, yarn berry, npm, pnpm, bun)
- Tests verify exact versions are saved without ^ or ~ prefix
- All tests pass with 100% line and branch coverage
- No RuboCop violations in changed files

Resolves #25

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Add YARD documentation to add() and add!() methods explaining all parameters
- Add test for adding multiple packages with exact flag
- Fix RuboCop style issue (use %w instead of array of strings)
- All tests pass: 287 examples, 0 failures, 100% coverage

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Add README documentation with exact flag example
- Add CHANGELOG entry for new feature
- Add multi-package exact test to all manager specs (npm, pnpm, bun, yarn berry)
- Add test for exact with optional dependencies
- All tests pass: 294 examples, 100% coverage

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@justin808 justin808 force-pushed the justin808/add-exact-version-flag branch from 1631700 to 17c97fd Compare November 5, 2025 03:05
@claude
Copy link

claude bot commented Nov 5, 2025

Pull Request Review - PR #29

Summary

This PR adds support for the exact parameter to the add method, allowing packages to be installed with exact version numbers. The implementation is clean, well-tested, and follows the repository's conventions.


✅ Strengths

1. Excellent Code Consistency

  • The exact parameter is implemented uniformly across all package managers (npm, yarn classic, yarn berry, pnpm, bun)
  • Each manager correctly uses the appropriate flag for their package manager:
    • npm/pnpm: --save-exact
    • yarn/bun: --exact
  • The pattern of using [package_type_install_flag(type), exact_flag(exact)].compact is clean and maintainable

2. Comprehensive Test Coverage

  • All 5 package managers have thorough test coverage including:
    • Production dependencies with exact flag
    • Dev dependencies with exact flag
    • Multiple packages with exact flag
    • Optional dependencies with exact flag (yarn classic)
  • Tests verify both command invocation AND the resulting package.json content
  • The PR maintains 100% line and branch coverage

3. Good Documentation

  • README.md updated with clear examples
  • Proper YARD documentation added to method signatures in base.rb
  • CHANGELOG.md follows the project's format correctly

4. Backward Compatibility

  • The exact parameter defaults to false, ensuring no breaking changes
  • Existing code will continue to work without modification

🔍 Code Quality Observations

Implementation Pattern

The implementation follows a consistent pattern across all managers:

def add(packages, type: :production, exact: false)
  flags = [package_type_install_flag(type), exact_flag(exact)].compact
  raw("add", flags + packages)
end

def exact_flag(exact)
  return "--exact" if exact  # or "--save-exact" for npm/pnpm
  nil
end

This is clean and maintainable. The use of .compact elegantly handles the nil case when exact: false.

Method Signatures

The YARD documentation in base.rb:43-56 is clear and helpful:

# @param packages [Array<String>] the packages to add
# @param type [Symbol] the type of dependency (:production, :dev, :optional)
# @param exact [Boolean] if true, saves packages with exact versions (no ^ or ~ prefix)

💭 Minor Suggestions (Optional)

1. Consider Edge Case Testing

While the test coverage is comprehensive, you might consider adding a test for:

  • Mixing exact: true with packages that already have version specifiers (e.g., package_json.manager.add(["react@^18.0.0"], exact: true))
  • This would verify behavior when there's a potential conflict between the version specifier and the exact flag

However, this is a minor point - the current implementation correctly passes the exact flag to the package manager, which will handle this appropriately.

2. CHANGELOG Format Check

The CHANGELOG entry looks good and follows the format:

- Add support for `exact` parameter in `add` method to install packages with
  exact versions ([#29](https://github.com/shakacode/package_json/pull/29) by
  [@justin808](https://github.com/justin808))

This correctly uses #29 in the URL but not as a hash in the text (per CLAUDE.md guidelines).


🔒 Security & Performance

  • Security: No security concerns. The implementation doesn't introduce any new security risks.
  • Performance: No performance impact. The additional parameter is a simple boolean that adds at most one flag to the command.

🎯 Final Assessment

This PR is excellent and ready to merge.

The implementation is:

  • ✅ Clean and maintainable
  • ✅ Thoroughly tested (286 examples passing, 100% coverage)
  • ✅ Well-documented
  • ✅ Consistent across all package managers
  • ✅ Backward compatible
  • ✅ Follows all repository conventions (per CLAUDE.md)

Great work on this feature addition! The uniform implementation across all package managers and comprehensive test coverage demonstrate high code quality.


Recommendation: Approve and merge.

@justin808
Copy link
Member Author

Possible merge commit message:

feat: add support for exact version flag in add method (#29)

Why
Libraries like React on Rails require exact version matching between
Ruby gem and npm package for compatibility.

Summary
Adds exact parameter to add() and add!() methods across all package
managers to install dependencies without semver range prefixes.

Key improvements
- Unified API with exact: true flag works across yarn, npm, pnpm, bun
- Complete YARD documentation for all parameters
- Comprehensive test coverage including multi-package and edge cases

Impact
- Existing: No changes, exact defaults to false (backward compatible)
- New: Users can enforce exact versions via exact: true parameter

Risks
None. Feature is opt-in with safe defaults.

Copy link
Collaborator

@G-Rath G-Rath left a comment

Choose a reason for hiding this comment

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

you need to update the types in the rbs files

- Remove YARD @param documentation from add() and add!() methods
- Add exact parameter to RBS type signatures in base.rbs
- Update CLAUDE.md with RBS documentation guidelines

This project uses RBS for type documentation, not YARD comments.
Types should be defined in sig/*.rbs files, keeping Ruby code clean.

Addresses review feedback from @G-Rath in PR #29

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@claude
Copy link

claude bot commented Nov 5, 2025

Code Review - PR #29: Add support for exact version flag

Summary

This PR successfully implements support for the exact parameter in the add method, allowing packages to be installed with exact version numbers. The implementation is clean, well-tested, and follows the project's conventions.

Positive Aspects ✅

  1. Excellent Test Coverage

    • Comprehensive tests across all 5 package managers (npm, yarn classic, yarn berry, pnpm, bun)
    • Tests cover multiple scenarios: single package, multiple packages, dev dependencies, and optional dependencies
    • Tests verify both command invocation and package.json content
    • 294 examples with 100% line and branch coverage
  2. Consistent Implementation

    • The exact_flag() helper method follows the same pattern across all manager implementations
    • Correct flag mapping for each package manager:
      • yarn/bun: --exact
      • npm/pnpm: --save-exact
    • Clean use of .compact to handle optional flags
  3. Proper Type Signatures

    • RBS file (sig/package_json/managers/base.rbs) correctly updated with the new exact parameter
    • Follows project's convention of using RBS for type documentation instead of YARD comments
  4. Good Documentation

    • README updated with clear usage example
    • CHANGELOG entry follows the project's format
    • CLAUDE.md updated with RBS documentation guidelines (bonus improvement)
  5. API Design

    • Backward compatible (defaults to exact: false)
    • Intuitive parameter name and behavior
    • Consistent with Ruby conventions for optional parameters

Minor Observations 🔍

  1. Code Quality: The implementation is clean and follows Ruby best practices:

    • Uses keyword arguments appropriately
    • Proper nil handling with .compact
    • Consistent error handling across managers
  2. Performance: No performance concerns. The flag logic is O(1) and doesn't add any overhead.

  3. Security: No security concerns. The parameter is a boolean flag that only affects package manager behavior, not arbitrary command execution.

  4. Maintainability:

    • The exact_flag() method is easy to understand and maintain
    • If future package managers need different flags, the pattern is clear
    • Tests provide excellent regression protection

Potential Improvements (Optional, Not Blocking) 💡

These are minor suggestions for consideration, but the PR is ready to merge as-is:

  1. Edge Case Testing: Consider adding a test for add!() with exact flag to ensure the bang variant also works correctly. Current tests only cover add().

  2. Documentation Clarity: The README example shows exact: true with a version like 16.0.0, but it might be worth mentioning that the exact flag affects how the version is saved (without ^ prefix), not the version resolution itself.

  3. Consistency Check: Verify that the flag order is consistent across all managers. Currently:

    • npm/pnpm: [type_flag, exact_flag]
    • yarn/bun: [type_flag, exact_flag]
      This is already consistent! ✅

Verdict ✅

Approved - Excellent work!

This PR demonstrates:

  • Thorough understanding of the codebase architecture
  • Comprehensive testing practices
  • Proper documentation
  • Clean, maintainable code

The implementation correctly addresses issue #25 and adds a valuable feature to the gem. All code quality requirements from CLAUDE.md appear to be met (RuboCop compliance, proper documentation approach, etc.).

Ready to merge! 🚀


Review generated by Claude Code

@claude
Copy link

claude bot commented Nov 5, 2025

Pull Request Review

Excellent work on implementing the exact parameter for the add method! This PR demonstrates solid engineering practices with comprehensive test coverage and consistent implementation across all package managers. Here's my detailed review:

✅ Strengths

1. Consistent Implementation

  • The exact_flag method is implemented consistently across all 5 package manager classes (npm, yarn classic, yarn berry, pnpm, bun)
  • Each manager uses the correct CLI flag for their package manager:
    • npm/pnpm: --save-exact
    • yarn/bun: --exact
  • The pattern of returning nil when exact: false and using .compact to filter flags is clean and maintainable

2. Excellent Test Coverage

  • Comprehensive test coverage for all package managers
  • Tests verify both production and dev dependencies with exact versions
  • Tests confirm the actual behavior (packages saved as 0.0.0 instead of ^0.0.0)
  • Multiple package test cases included
  • All 286 examples passing with 100% coverage is impressive

3. Type Safety

  • RBS type signatures properly updated in all .rbs files
  • The exact_flag private method is correctly typed as (bool exact) -> (String | nil)
  • Base class signatures updated to propagate the exact parameter correctly

4. Documentation

  • CHANGELOG follows the repository conventions perfectly
  • README updated with clear usage example
  • PR description is thorough with clear API usage examples

5. API Design

  • The exact: false default parameter is the right choice (maintains backward compatibility)
  • Parameter propagation through add\! to add is correct
  • Flag ordering in the array construction is logical and consistent

🔍 Code Quality Observations

Implementation Pattern (lib/package_json/managers/npm_like.rb:25-27)

def add(packages, type: :production, exact: false)
  flags = [package_type_install_flag(type), exact_flag(exact)].compact
  raw("install", flags + packages)
end

This is clean and idiomatic Ruby. The use of .compact to remove nil values is elegant.

Helper Method Pattern (lib/package_json/managers/npm_like.rb:70-74)

def exact_flag(exact)
  return "--save-exact" if exact

  nil
end

This follows the existing codebase patterns perfectly. Consistent with package_type_install_flag and other helpers.

📝 Minor Suggestions

1. Consider Guard Clause Simplification (Optional, stylistic)
The exact_flag methods could be written more concisely:

def exact_flag(exact)
  "--save-exact" if exact
end

This is functionally identical (implicit nil return) and slightly more concise, though the current explicit nil return is also perfectly fine and perhaps more clear.

2. CHANGELOG Format
The CHANGELOG entry is correct! It uses #29 (not PR 29) which matches the existing format in the file. Good attention to detail.

🎯 Final Assessment

No blocking issues found. This PR is production-ready.

  • ✅ Code quality: Excellent
  • ✅ Test coverage: Comprehensive
  • ✅ Type signatures: Complete and correct
  • ✅ Documentation: Clear and thorough
  • ✅ Backward compatibility: Maintained
  • ✅ Performance: No concerns (minimal conditional logic)
  • ✅ Security: No concerns
  • ✅ Best practices: Follows Ruby and repository conventions

The implementation is consistent, well-tested, properly typed, and follows the repository's conventions. The feature resolves issue #25 and provides a clean API that works across all supported package managers.

Recommendation: Approve and merge 🚀


Review performed by Claude Code

@G-Rath G-Rath enabled auto-merge (squash) November 5, 2025 22:42
Copy link

@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: 0

🧹 Nitpick comments (1)
CLAUDE.md (1)

82-88: Helpful documentation addition aligning with the RBS signature changes.

The new section clarifies the project's use of RBS for type documentation, which directly supports the signature additions in this PR.

Optional: Address markdown formatting hint.

The linter suggests line 84 uses emphasis (bold text) where a heading might be more appropriate. Consider changing:

-**This project uses RBS (Ruby Signature) files for type documentation**
+### RBS Usage
+
+This project uses RBS (Ruby Signature) files for type documentation.

However, the current format is perfectly readable and this is just a stylistic suggestion.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1fdda5 and be2c4f8.

📒 Files selected for processing (6)
  • CLAUDE.md (1 hunks)
  • sig/package_json/managers/bun_like.rbs (1 hunks)
  • sig/package_json/managers/npm_like.rbs (1 hunks)
  • sig/package_json/managers/pnpm_like.rbs (1 hunks)
  • sig/package_json/managers/yarn_berry_like.rbs (1 hunks)
  • sig/package_json/managers/yarn_classic_like.rbs (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
CLAUDE.md

84-84: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: test (windows-latest, head)
  • GitHub Check: test (windows-latest, 3.1)
  • GitHub Check: test (macos-latest, 3.0)
  • GitHub Check: test (macos-latest, 3.1)
  • GitHub Check: test (windows-latest, 2.7)
  • GitHub Check: test (windows-latest, 3.0)
  • GitHub Check: test (windows-latest, 2.6)
  • GitHub Check: test (macos-latest, 2.6)
  • GitHub Check: test (macos-latest, head)
  • GitHub Check: test (macos-latest, 2.7)
  • GitHub Check: test (ubuntu-latest, head)
  • GitHub Check: test (ubuntu-latest, 2.6)
  • GitHub Check: test (ubuntu-latest, 3.0)
  • GitHub Check: test (ubuntu-latest, 3.1)
  • GitHub Check: test (ubuntu-latest, 2.7)
🔇 Additional comments (5)
sig/package_json/managers/bun_like.rbs (1)

16-17: LGTM! Signature is consistent and correct.

The exact_flag method signature is well-defined and aligns with the implementation pattern across all package managers.

sig/package_json/managers/pnpm_like.rbs (1)

16-17: LGTM! Signature matches the pattern.

The signature is consistent with other package manager implementations.

sig/package_json/managers/yarn_berry_like.rbs (1)

16-17: LGTM! Consistent signature.

The signature correctly follows the established pattern for all package managers.

sig/package_json/managers/npm_like.rbs (1)

14-15: LGTM! Signature is correct.

The signature is consistent with the pattern established across all package manager implementations.

sig/package_json/managers/yarn_classic_like.rbs (1)

18-19: LGTM! Signature follows the pattern.

The signature is consistent with all other package manager implementations.

@G-Rath G-Rath disabled auto-merge November 5, 2025 22:52
@G-Rath G-Rath merged commit d501353 into main Nov 5, 2025
24 checks passed
@G-Rath G-Rath deleted the justin808/add-exact-version-flag branch November 5, 2025 22:53
@claude claude bot mentioned this pull request Nov 5, 2025
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.

Add support for exact version flag in add method

3 participants