Skip to content

Conversation

@bytemain
Copy link
Member

@bytemain bytemain commented Nov 17, 2025

Previous, only zip stream support strip option, now support for all uncompress stream

todo:

  • add test for tgz

Summary by CodeRabbit

Release Notes

  • New Features

    • Added strip option to uncompress operations, allowing removal of leading path components from extracted file structures.
  • Tests

    • Expanded test coverage to validate strip functionality across multiple archive formats, ensuring correct extraction behavior.

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

Walkthrough

This pull request implements file path stripping functionality during decompression operations. The core change adds support for a strip option in makeUncompressFn that normalizes extracted file paths by removing leading directory components, with corresponding test coverage for tar and tgz formats.

Changes

Cohort / File(s) Summary
Core strip functionality
lib/utils.js
Extracts strip option from opts (default 0), removes it before passing to UncompressStream, and uses stripFileName() to normalize destination paths based on the strip level.
Assertion improvement
test/zip/index.test.js
Updates file mode assertion from strict equality check to assert.equal() with descriptive message for better test output.
Strip option test coverage
test/tar/index.test.js, test/tgz/index.test.js
Adds new test cases for uncompress() with strip: 1 and strip: 2 options, validating path normalization behavior and resulting directory structure for both tar and tgz formats.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant makeUncompressFn
    participant stripFileName
    participant UncompressStream
    participant FS as File System

    User->>makeUncompressFn: uncompress(source, dest, {strip: 1})
    makeUncompressFn->>makeUncompressFn: derive strip from opts.strip
    makeUncompressFn->>makeUncompressFn: remove strip from opts
    makeUncompressFn->>UncompressStream: create stream with cleaned opts
    UncompressStream->>UncompressStream: emit entry events
    makeUncompressFn->>stripFileName: normalize path (strip=1, header.name)
    stripFileName-->>makeUncompressFn: return normalized path
    makeUncompressFn->>FS: write file to normalized destination
    FS-->>User: extraction complete with paths stripped
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Core implementation (lib/utils.js): Requires understanding the stripFileName() function behavior and how it interacts with the existing uncompression flow
  • New test cases (test files): Multiple similar test cases added across tar and tgz formats, each requiring verification of expected behavior and assertions; consistency check across formats
  • Assertion change (test/zip/index.test.js): Straightforward style improvement with minimal risk

Possibly related PRs

Suggested reviewers

  • fengmk2

Poem

🐰 Hopping through archives with stripping delight,
Nested paths shortened, extraction feels right!
Tar, tgz, zip files now skip what's not needed,
The strip option blooms where recursion proceeded. 🎀

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'WIP: feat: support strip for all archive' is partially related to the changeset. It correctly identifies the main feature being added (strip support for all archive types), but contains 'WIP' prefix and has a grammatical issue ('archive' should be 'archives'). The core message is clear and specific enough.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@bytemain
Copy link
Member Author

似乎 windows 上的 dircompare 是不稳定的

@bytemain bytemain marked this pull request as ready for review November 17, 2025 07:07
Copilot AI review requested due to automatic review settings November 17, 2025 07:07
@bytemain bytemain closed this Nov 17, 2025
Copilot finished reviewing on behalf of bytemain November 17, 2025 07:13
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR extends the strip functionality to support all archive types (tar, tgz, and zip) by implementing it uniformly in the makeUncompressFn utility function.

Key Changes:

  • Adds centralized strip handling in makeUncompressFn for all archive types
  • Improves test reliability with better synchronization
  • Enhances assertion messages for clearer test failure diagnostics

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
lib/utils.js Implements strip parameter extraction and application in makeUncompressFn, enabling strip functionality for tar and tgz archives while maintaining compatibility with zip's existing implementation
test/zip/uncompress_stream.test.js Addresses test timing issue by deferring assertions and improves error messages with descriptive assert.equal statement
test/zip/index.test.js Enhances assertion with descriptive error message for file mode comparison

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@bytemain bytemain reopened this Nov 17, 2025
@bytemain bytemain changed the title feat: support strip for all archive WIP: feat: support strip for all archive Nov 17, 2025
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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2d231b and 0ef2c58.

📒 Files selected for processing (3)
  • lib/utils.js (2 hunks)
  • test/zip/index.test.js (1 hunks)
  • test/zip/uncompress_stream.test.js (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
test/zip/index.test.js (1)
test/zip/file_stream.test.js (1)
  • assert (9-9)
test/zip/uncompress_stream.test.js (1)
test/util.js (2)
  • stream (1-1)
  • pipelinePromise (3-3)
⏰ 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). (2)
  • GitHub Check: Node.js / Test (windows-latest, 24)
  • GitHub Check: Node.js / Test (windows-latest, 18)
🔇 Additional comments (6)
lib/utils.js (2)

92-93: Good practice: removing strip from opts before passing to UncompressStream.

Correctly removes the strip option after extraction to avoid passing it to the underlying UncompressStream constructor, which handles entry emission but not path stripping.


115-115: stripFileName correctly handles all entry types—verification passed.

The function receives the type parameter and uses it appropriately at line 221 to normalize directory paths (adding trailing slash). All three entry types are properly handled in the decompression flow:

  • file (lines 116–127): Creates parent directory, writes file
  • symlink (lines 128–142): Creates parent directory, creates symlink with relative target
  • directory (lines 143–148): Creates directory with recursive flag

No issues found.

test/zip/uncompress_stream.test.js (3)

37-46: Improved error handling with pipelinePromise.

The change from direct stream piping to pipelinePromise with .then(next).catch(done) provides better error propagation. The addition of explicit end event handling for directory entries (line 45) ensures proper flow control.


196-197: Descriptive assertion messages aid debugging.

The change from assert(res.distinct === 0) to assert.equal(res.distinct, 0, 'distinct files count mismatch') improves debugging capabilities, especially given the PR author's comment about dircompare instability on Windows.


187-216: Strip handling in UncompressStream is correctly implemented.

Verification confirms that ZipUncompressStream properly handles the strip option:

  1. The constructor stores the option at line 37: this._strip = Number(opts.strip) || 0;
  2. Before emitting the 'entry' event, the fileName is stripped via the [STRIP_NAME] method (line 110-114), which calls utils.stripFileName()
  3. The header.name passed to the 'entry' event listener is already stripped
  4. The test's expectation (line 205) that header.name is pre-stripped is correct

The implementation is sound.

test/zip/index.test.js (1)

291-291: Improved assertion validates mode preservation dynamically.

The change from assert(stat.mode === 32804) to assert.equal(stat.mode, originStat.mode, 'file mode should be same after uncompress') is an improvement. It validates that the file mode is preserved through compression/uncompression rather than checking against a hardcoded value, making the test more robust across different systems.

@bytemain bytemain changed the title WIP: feat: support strip for all archive feat: support strip for all archive Nov 17, 2025
@bytemain bytemain changed the title feat: support strip for all archive WIP: feat: support strip for all archive Nov 17, 2025
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 (2)
test/tar/index.test.js (1)

247-248: Consider adding assertion messages for consistency.

The strip: 1 test includes helpful error messages like 'distinct files count mismatch' (lines 236-237), but these assertions lack them. Adding messages would improve debugging consistency across tests.

-      assert.equal(res.distinct, 0);
-      assert.equal(res.equal, 4);
+      assert.equal(res.distinct, 0, 'distinct files count mismatch');
+      assert.equal(res.equal, 4, 'equal files count mismatch');
test/tgz/index.test.js (1)

237-246: Same verification and consistency concerns as tar tests.

This test has the same dependencies and concerns as the tar strip: 2 test:

  1. Relies on the fixtures/xxx-strip2 fixture (verification already requested for tar tests)
  2. Subject to the same Windows dircompare instability mentioned in the PR comments
  3. Missing assertion messages for distinct and equal counts (lines 242-243)

For consistency, consider adding descriptive assertion messages:

-      assert.equal(res.distinct, 0);
-      assert.equal(res.equal, 4);
+      assert.equal(res.distinct, 0, 'distinct files count mismatch');
+      assert.equal(res.equal, 4, 'equal files count mismatch');
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ef2c58 and d1e2c10.

📒 Files selected for processing (2)
  • test/tar/index.test.js (1 hunks)
  • test/tgz/index.test.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
test/tgz/index.test.js (1)
test/tgz/uncompress_stream.test.js (8)
  • sourceFile (13-13)
  • path (4-4)
  • os (3-3)
  • uuid (5-5)
  • originalDir (12-12)
  • compressing (10-10)
  • dircompare (8-8)
  • assert (6-6)
test/tar/index.test.js (1)
test/tar/uncompress_stream.test.js (8)
  • sourceFile (14-14)
  • path (4-4)
  • os (3-3)
  • uuid (5-5)
  • originalDir (13-13)
  • compressing (11-11)
  • dircompare (8-8)
  • assert (6-6)
⏰ 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). (1)
  • GitHub Check: Node.js / Test (ubuntu-latest, 24)
🔇 Additional comments (3)
test/tar/index.test.js (2)

230-240: LGTM! Test logic is sound.

The test correctly validates that strip: 1 removes the top-level directory component, and the comparison against originalDir is appropriate since stripping xxx/ from the archive should yield the same structure as the original xxx directory contents.


242-251: I need to investigate whether the Windows dircompare instability mentioned in the original review is a documented issue in the codebase.The web search didn't return specific information about the dircompare npm package and Windows stability. Let me search more specifically.

Based on my verification:

  1. ✓ The xxx-strip2 fixture exists and contains the expected structure (4 files/items)
  2. The dir-compare npm package documentation shows no documented Windows stability issues
  3. The package is actively maintained with no known vulnerabilities
  4. The Windows instability claim in the original review appears unsubstantiated and lacks evidence

The fixture exists and the test is correctly structured.

The xxx-strip2 fixture is present with valid content (bar.txt, bin, foo, test.js). The test correctly expects 4 equal files and 0 directories. The dir-compare package shows no documented Windows instability issues. The original suggestion to add Windows-specific handling lacks concrete evidence and is not warranted.

test/tgz/index.test.js (1)

225-235: LGTM! Consistent with tar tests.

The test correctly validates the strip: 1 functionality for tgz archives, maintaining consistency with the tar implementation.

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