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

  • New Features

    • Added a strip option for uncompress operations to remove leading path components during extraction, improving resulting file layout.
  • Tests

    • Expanded test coverage for uncompress with multiple strip values across archive formats and refined assertions to better validate extraction outcomes.
  • Documentation

    • Updated docs to describe the new strip option in extraction parameters.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

📝 Walkthrough

Walkthrough

Adds numeric strip support to uncompression: makeUncompressFn now extracts strip from options, removes it before creating UncompressStream, and computes extraction destinations with stripFileName(strip, header.name, header.type). Tests for tar/tgz stripping were added and a zip test assertion message was improved.

Changes

Cohort / File(s) Summary
Core strip functionality
lib/utils.js
Derive strip as `Number(opts.strip)
Tar strip tests
test/tar/index.test.js
Add tests for tar.uncompress(source, dest, { strip: 1 }) and { strip: 2 }, asserting file/dir counts and content equality against expected fixtures.
Tgz strip tests
test/tgz/index.test.js
Add tests for tgz.uncompress(..., { strip: 1 }) and { strip: 2 }, validating stripped extraction results and comparing against fixtures.
Zip test assertion
test/zip/index.test.js
Change file mode assertion to assert.equal(stat.mode, originStat.mode, 'file mode should be same after uncompress') (adds message).
Docs
README.md
Document opts.strip {Number} option for uncompress params and FileStream sections.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as makeUncompressFn
    participant Stream as UncompressStream
    participant Stripper as stripFileName
    participant FS as FileSystem

    Caller->>Caller: strip = Number(opts.strip) || 0\ndelete opts.strip
    Caller->>Stream: create UncompressStream(cleaned opts)
    Stream-->>Caller: emit entry(header)
    Caller->>Stripper: stripFileName(strip, header.name, header.type)
    Stripper-->>Caller: normalizedPath
    Caller->>FS: write entry to dest/normalizedPath
    FS-->>Caller: write complete
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • fengmk2
  • MichaelDeBoey

Poem

🐰 I hopped through paths and gave them a skip,

I nibbled prefixes and tightened each strip.
Tar, tgz, zip — tidy, trimmed, and bright,
Files now land true, neat as moonlight.
🥕✨

🚥 Pre-merge checks | ✅ 3
✅ 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 'feat: support strip for all archive uncompress' accurately describes the main change: adding strip option support across all archive uncompress operations (tar, tgz, zip).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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

@bytemain bytemain changed the title WIP: feat: support strip for all archive feat: support strip for all archive Jan 28, 2026
@bytemain bytemain changed the title feat: support strip for all archive feat: support strip for all archive uncompress Jan 28, 2026
@bytemain
Copy link
Member Author

@fengmk2 Hello, this pr is ready, please take a look at this pull request when you have time.

@fengmk2 fengmk2 added this pull request to the merge queue Jan 28, 2026
Merged via the queue into node-modules:master with commit 15d24cd Jan 28, 2026
16 checks passed
fengmk2 pushed a commit that referenced this pull request Jan 28, 2026
[skip ci]

## 2.1.0 (2026-01-28)

* feat: support strip for all archive `uncompress` (#117) ([15d24cd](15d24cd)), closes [#117](#117) [hi#level](https://github.com/hi/issues/level)
@github-actions
Copy link

🎉 This PR is included in version 2.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants