Skip to content

fix(utils,core,action): normalize path handling and test guards#2809

Merged
srod merged 1 commit intodevelopfrom
codex/fix-review-findings
Feb 9, 2026
Merged

fix(utils,core,action): normalize path handling and test guards#2809
srod merged 1 commit intodevelopfrom
codex/fix-review-findings

Conversation

@srod
Copy link
Owner

@srod srod commented Feb 9, 2026

Summary:\nFixes path-handling issues found in review and hardens related tests.\n\nChanges:\n- normalize publicFolder handling in utils (setPublicFolder, wildcards, setFileNameMin) so trailing slashes are no longer required\n- avoid false positives when checking whether an input is already inside publicFolder\n- make core output directory creation support both POSIX and Windows separators\n- relax action manifest test to assert direct fast-glob dependency presence without pinning an exact version string\n- add regression tests, including a Windows-separator coverage test for core\n\nTesting:\n- bun run test packages/utils packages/core packages/action\n- bun run --filter @node-minify/utils typecheck\n- bun run --filter @node-minify/core typecheck\n- bun run --filter @node-minify/action typecheck\n- bun run --filter @node-minify/utils lint\n- bun run --filter @node-minify/core lint\n- bun run --filter @node-minify/action lint


Summary by cubic

Normalize path handling across utils and core for consistent cross-platform behavior. Trailing slashes are optional, globs use forward slashes, Windows-style paths are supported, and core preserves original separators when creating output directories (including mixed separators).

  • Bug Fixes
    • setPublicFolder: use path.relative guard and path.join; no trailing slash required; avoid substring false positives.
    • wildcards: build patterns with path.posix.join; normalize backslashes; support string/backslash publicFolder; convert Windows patterns.
    • setFileNameMin: use path.posix.parse/join; normalize backslashes; support in-place and publicFolder paths.
    • core createDirectory: resolve dir with path.dirname and win32 fallback; preserve dirname separators for mkdir; support backslash and mixed-separator outputs.
    • tests: add cross-platform cases for compress dir creation, wildcards, filename normalization; action manifest asserts fast-glob is a non-empty string.

Written for commit 1d5e3ee. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of Windows and POSIX path separators for outputs and public-folder logic to avoid duplicated prefixes and preserve directories
    • More robust filename validation and error reporting; preserves original directories when requested
  • Tests

    • Added tests for path handling, public-folder variations, and filename normalization across input shapes
    • Relaxed a brittle dependency-version assertion to be less strict

@changeset-bot
Copy link

changeset-bot bot commented Feb 9, 2026

🦋 Changeset detected

Latest commit: 1d5e3ee

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 31 packages
Name Type
@node-minify/core Patch
@node-minify/utils Patch
@node-minify/action Patch
@node-minify/benchmark Patch
@node-minify/cli Patch
@node-minify/imagemin Patch
@node-minify/sharp Patch
@node-minify/examples Patch
@node-minify/babel-minify Patch
@node-minify/clean-css Patch
@node-minify/crass Patch
@node-minify/cssnano Patch
@node-minify/csso Patch
@node-minify/esbuild Patch
@node-minify/google-closure-compiler Patch
@node-minify/html-minifier Patch
@node-minify/jsonminify Patch
@node-minify/lightningcss Patch
@node-minify/minify-html Patch
@node-minify/no-compress Patch
@node-minify/oxc Patch
@node-minify/sqwish Patch
@node-minify/svgo Patch
@node-minify/swc Patch
@node-minify/terser Patch
@node-minify/uglify-es Patch
@node-minify/uglify-js Patch
@node-minify/yui Patch
@node-minify/docs Patch
@node-minify/run Patch
@node-minify/types Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@changeset-bot
Copy link

changeset-bot bot commented Feb 9, 2026

⚠️ No Changeset found

Latest commit: 99dd26d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

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

Replaces ad-hoc string path handling with Node path utilities across utils and core; adds getDirectoryPath and directory batching in compress; normalizes Windows backslashes to POSIX paths; extends tests for backslash/publicFolder cases; relaxes one fast-glob version assertion.

Changes

Cohort / File(s) Summary
Path utility updates
packages/utils/src/setFileNameMin.ts, packages/utils/src/setPublicFolder.ts, packages/utils/src/wildcards.ts
Import path, add toPosixPath, use path.posix parsing/join and path.relative to detect in-public-folder; normalize backslashes and replace manual string concatenation.
Compress directory handling
packages/core/src/compress.ts
Add getDirectoryPath (using path.dirname with Windows fallback), rename loop var to outputPath, skip invalid paths, collect unique dirs and call fs.mkdir in parallel.
New and adjusted tests
packages/core/__tests__/compress-paths.test.ts, packages/utils/__tests__/setPublicFolder.test.ts, packages/utils/__tests__/utils.test.ts, packages/utils/__tests__/wildcards-ignore.test.ts
Add/adjust tests covering Windows/backslash normalization, publicFolder edge cases, and compress mkdir/compress interactions; update spies and assertions.
Test assertion relaxation
packages/action/__tests__/package-manifest.test.ts
Relax fast-glob dependency assertion to check for a non-empty string rather than an exact version.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant CLI as CLI/Caller
  participant Compress as packages/core/compress
  participant FS as node:fs/promises
  participant Compressor as compressSingleFile
  CLI->>Compress: run compress(settings)
  Compress->>Compress: for each outputPath → getDirectoryPath(outputPath)
  Compress->>FS: mkdir(uniqueDirs..., { recursive: true })
  Compress->>Compressor: compressSingleFile(input, outputPath)
  Compressor-->>Compress: { code: "ok" }
  Compress->>FS: writeFile(outputPath, code)
  Compress-->>CLI: results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

Review effort 3/5

Poem

🐰
I hopped through slashes, swapped each one,
POSIX paths to make things run.
Windows backslashes now align,
directories batched, outputs fine—
carrots for tests, code neatly done. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: normalizing path handling across utils, core, and action packages while hardening test guards.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-review-findings

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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

 ____________________________________________
< Forcing bugs to surrender unconditionally. >
 --------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).

✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.

Tip

You can disable the changed files summary in the walkthrough.

Disable the reviews.changed_files_summary setting to disable the changed files summary in the walkthrough.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-review-findings

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.

2 similar comments
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

 ____________________________________________
< Forcing bugs to surrender unconditionally. >
 --------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).

✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.

Tip

You can disable the changed files summary in the walkthrough.

Disable the reviews.changed_files_summary setting to disable the changed files summary in the walkthrough.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-review-findings

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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

 ____________________________________________
< Forcing bugs to surrender unconditionally. >
 --------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).

✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.

Tip

You can disable the changed files summary in the walkthrough.

Disable the reviews.changed_files_summary setting to disable the changed files summary in the walkthrough.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-review-findings

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.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 9 files

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR standardizes path handling across utils and core so callers no longer need trailing slashes and Windows-style separators are accepted. In utils, setPublicFolder() switches from substring matching to a path.relative()-based guard and uses path.join(), setFileNameMin() now parses/joins with path.posix after normalizing backslashes, and wildcards() builds glob patterns via path.posix.join() with backslash normalization (plus expanded regression tests). In core, output directory creation now derives directories using path.dirname() with a path.win32.dirname() fallback, and tests cover backslash outputs; the action manifest test is relaxed to check that fast-glob is present without pinning an exact version.

Confidence Score: 3/5

  • This PR is close to merge-ready but has a Windows path handling bug in core directory creation that can break valid absolute output paths.
  • Most changes are test-backed and improve cross-platform normalization. The remaining concern is packages/core/src/compress.ts rewriting backslashes to forward slashes before mkdir, which undermines the stated Windows support for absolute paths.
  • packages/core/src/compress.ts

Important Files Changed

Filename Overview
.changeset/tiny-crabs-jump.md Adds a changeset bumping core/utils with notes about cross-platform path normalization.
packages/action/tests/package-manifest.test.ts Relaxes dependency assertion to require fast-glob is present as a non-empty string.
packages/core/tests/compress-paths.test.ts Adds regression tests ensuring output directory creation handles Windows-style separators and normalizes before mkdir.
packages/core/src/compress.ts Updates output directory derivation to use path.dirname with win32 fallback and normalizes separators; potential bug: replaces backslashes with '/' before mkdir which can break Windows absolute paths.
packages/utils/tests/setPublicFolder.test.ts Adds tests for publicFolder without trailing slash and avoiding substring false positives when publicFolder appears mid-path.
packages/utils/tests/utils.test.ts Extends setFileNameMin tests for no trailing slash and Windows separator normalization; adjusts generic-error test to mock path.posix.parse.
packages/utils/tests/wildcards-ignore.test.ts Adds coverage for publicFolder without trailing slash and backslash normalization in wildcard patterns.
packages/utils/src/setFileNameMin.ts Switches to path.posix.parse/join and normalizes backslashes; looks correct for producing forward-slash outputs.
packages/utils/src/setPublicFolder.ts Replaces substring check with path.relative guard and uses path.join for prefixing; fixes false positives when folder name is a substring elsewhere.
packages/utils/src/wildcards.ts Builds glob patterns using posix joins and normalizes backslashes; supports string publicFolder and improves cross-platform glob behavior.

Sequence Diagram

sequenceDiagram
    participant Caller as User/Action/CLI
    participant Core as @node-minify/core compress()
    participant Dir as createDirectory()/getDirectoryPath()
    participant FS as node:fs/promises.mkdir
    participant Utils as @node-minify/utils

    Caller->>Core: compress(settings)
    alt settings.output provided
        Core->>Dir: createDirectory(settings.output)
        Dir->>Dir: getDirectoryPath(outputPath)
        Dir->>FS: mkdir(dirPath, {recursive:true})
    end
    alt output is array
        Core->>Utils: run({settings, content, index}) (per file)
    else output is string/undefined
        Core->>Utils: compressSingleFile(settings)
    end
Loading

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR improves path handling across utils and core packages by replacing string manipulation with proper node:path module APIs, eliminating the requirement for trailing slashes in publicFolder parameters.

Key Changes

  • setPublicFolder: Now uses path.relative() to correctly detect if a file is already in the public folder, preventing false positives when the folder name appears in the middle of a path (e.g., "dist" vs "distribute")
  • setFileNameMin: Replaced lastIndexOf() string manipulation with path.parse() for cleaner cross-platform path handling
  • wildcards: Changed from string concatenation to path.join() for combining paths with publicFolder
  • core/compress: Updated createDirectory() to support both POSIX (/) and Windows (\) separators by checking both path.posix.dirname() and path.win32.dirname()

Testing

  • Added regression tests for trailing slash handling in setPublicFolder, wildcards, and setFileNameMin
  • Added test for false positive prevention when folder name appears in middle of path
  • New test file compress-paths.test.ts ensures Windows backslash paths work correctly
  • Relaxed action manifest test to check for fast-glob presence rather than exact version

Notes

  • All changes maintain backward compatibility
  • Improved consistency by using Node.js path APIs throughout instead of manual string operations

Confidence Score: 4/5

  • This PR is safe to merge with minor optimization opportunity in the core createDirectory logic
  • The changes properly address path handling issues by using standard Node.js path APIs instead of string manipulation. Comprehensive test coverage demonstrates the fixes work correctly. Score is 4 instead of 5 due to the slightly complex fallback logic in compress.ts that could be simplified to just use path.dirname() directly rather than trying both POSIX and Windows variants
  • packages/core/src/compress.ts - the createDirectory function's path handling could be simplified

Important Files Changed

Filename Overview
packages/utils/src/setPublicFolder.ts Improved path handling by using path.join() and path.relative() to correctly check if files are already in publicFolder, preventing false positives when folder name appears in middle of path
packages/utils/src/setFileNameMin.ts Replaced manual string manipulation with path.parse() and path.join() for cross-platform path handling, supporting both POSIX and Windows paths
packages/utils/src/wildcards.ts Changed from string concatenation to path.join() for combining publicFolder with paths, eliminating need for trailing slashes
packages/core/src/compress.ts Replaced naive lastIndexOf('/') logic with path.posix.dirname() and path.win32.dirname() to handle both separator types, though the fallback logic could be simplified

Sequence Diagram

sequenceDiagram
    participant User
    participant compress
    participant utils
    participant path_module as node:path
    participant fs as node:fs/promises

    User->>compress: compress(settings)
    
    alt output specified
        compress->>compress: createDirectory(output)
        compress->>path_module: path.posix.dirname(outputPath)
        path_module-->>compress: dirPath (POSIX)
        compress->>path_module: path.win32.dirname(outputPath)
        path_module-->>compress: dirPath (Windows)
        compress->>compress: choose first non-trivial dirPath
        compress->>fs: mkdir(dirPath, {recursive: true})
        fs-->>compress: directory created
    end

    alt single file
        compress->>utils: compressSingleFile(settings)
        utils-->>compress: result
    else multiple files
        compress->>compress: compressArrayOfFiles(settings)
        loop for each input file
            compress->>utils: getContentFromFilesAsync(input)
            utils-->>compress: content
            compress->>utils: run({settings, content, index})
            utils-->>compress: compressed result
        end
    end

    User->>utils: setPublicFolder(input, publicFolder)
    utils->>path_module: path.normalize(publicFolder)
    path_module-->>utils: normalized path
    utils->>path_module: path.relative(publicFolder, filePath)
    path_module-->>utils: relativePath
    alt already in publicFolder
        utils->>utils: return normalized path
    else not in publicFolder
        utils->>path_module: path.join(publicFolder, filePath)
        path_module-->>utils: joined path
    end
    utils-->>User: {input: processedPaths}

    User->>utils: wildcards(pattern, publicFolder)
    utils->>path_module: path.join(publicFolder, pattern)
    path_module-->>utils: fullPath
    utils->>fg: fg.globSync(fullPath, options)
    fg-->>utils: matched files
    utils-->>User: {input: files}

    User->>utils: setFileNameMin(file, output, publicFolder)
    utils->>path_module: path.parse(file)
    path_module-->>utils: {dir, name, ext}
    alt publicFolder specified
        utils->>path_module: path.join(publicFolder, name)
        path_module-->>utils: fileWithoutExtension
    end
    alt replaceInPlace
        utils->>path_module: path.join(dir, fileWithoutExtension)
        path_module-->>utils: fileWithoutExtension
    end
    utils->>utils: output.replace("$1", fileWithoutExtension)
    utils-->>User: minified filename
Loading

3 similar comments
@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR improves path handling across utils and core packages by replacing string manipulation with proper node:path module APIs, eliminating the requirement for trailing slashes in publicFolder parameters.

Key Changes

  • setPublicFolder: Now uses path.relative() to correctly detect if a file is already in the public folder, preventing false positives when the folder name appears in the middle of a path (e.g., "dist" vs "distribute")
  • setFileNameMin: Replaced lastIndexOf() string manipulation with path.parse() for cleaner cross-platform path handling
  • wildcards: Changed from string concatenation to path.join() for combining paths with publicFolder
  • core/compress: Updated createDirectory() to support both POSIX (/) and Windows (\) separators by checking both path.posix.dirname() and path.win32.dirname()

Testing

  • Added regression tests for trailing slash handling in setPublicFolder, wildcards, and setFileNameMin
  • Added test for false positive prevention when folder name appears in middle of path
  • New test file compress-paths.test.ts ensures Windows backslash paths work correctly
  • Relaxed action manifest test to check for fast-glob presence rather than exact version

Notes

  • All changes maintain backward compatibility
  • Improved consistency by using Node.js path APIs throughout instead of manual string operations

Confidence Score: 4/5

  • This PR is safe to merge with minor optimization opportunity in the core createDirectory logic
  • The changes properly address path handling issues by using standard Node.js path APIs instead of string manipulation. Comprehensive test coverage demonstrates the fixes work correctly. Score is 4 instead of 5 due to the slightly complex fallback logic in compress.ts that could be simplified to just use path.dirname() directly rather than trying both POSIX and Windows variants
  • packages/core/src/compress.ts - the createDirectory function's path handling could be simplified

Important Files Changed

Filename Overview
packages/utils/src/setPublicFolder.ts Improved path handling by using path.join() and path.relative() to correctly check if files are already in publicFolder, preventing false positives when folder name appears in middle of path
packages/utils/src/setFileNameMin.ts Replaced manual string manipulation with path.parse() and path.join() for cross-platform path handling, supporting both POSIX and Windows paths
packages/utils/src/wildcards.ts Changed from string concatenation to path.join() for combining publicFolder with paths, eliminating need for trailing slashes
packages/core/src/compress.ts Replaced naive lastIndexOf('/') logic with path.posix.dirname() and path.win32.dirname() to handle both separator types, though the fallback logic could be simplified

Sequence Diagram

sequenceDiagram
    participant User
    participant compress
    participant utils
    participant path_module as node:path
    participant fs as node:fs/promises

    User->>compress: compress(settings)
    
    alt output specified
        compress->>compress: createDirectory(output)
        compress->>path_module: path.posix.dirname(outputPath)
        path_module-->>compress: dirPath (POSIX)
        compress->>path_module: path.win32.dirname(outputPath)
        path_module-->>compress: dirPath (Windows)
        compress->>compress: choose first non-trivial dirPath
        compress->>fs: mkdir(dirPath, {recursive: true})
        fs-->>compress: directory created
    end

    alt single file
        compress->>utils: compressSingleFile(settings)
        utils-->>compress: result
    else multiple files
        compress->>compress: compressArrayOfFiles(settings)
        loop for each input file
            compress->>utils: getContentFromFilesAsync(input)
            utils-->>compress: content
            compress->>utils: run({settings, content, index})
            utils-->>compress: compressed result
        end
    end

    User->>utils: setPublicFolder(input, publicFolder)
    utils->>path_module: path.normalize(publicFolder)
    path_module-->>utils: normalized path
    utils->>path_module: path.relative(publicFolder, filePath)
    path_module-->>utils: relativePath
    alt already in publicFolder
        utils->>utils: return normalized path
    else not in publicFolder
        utils->>path_module: path.join(publicFolder, filePath)
        path_module-->>utils: joined path
    end
    utils-->>User: {input: processedPaths}

    User->>utils: wildcards(pattern, publicFolder)
    utils->>path_module: path.join(publicFolder, pattern)
    path_module-->>utils: fullPath
    utils->>fg: fg.globSync(fullPath, options)
    fg-->>utils: matched files
    utils-->>User: {input: files}

    User->>utils: setFileNameMin(file, output, publicFolder)
    utils->>path_module: path.parse(file)
    path_module-->>utils: {dir, name, ext}
    alt publicFolder specified
        utils->>path_module: path.join(publicFolder, name)
        path_module-->>utils: fileWithoutExtension
    end
    alt replaceInPlace
        utils->>path_module: path.join(dir, fileWithoutExtension)
        path_module-->>utils: fileWithoutExtension
    end
    utils->>utils: output.replace("$1", fileWithoutExtension)
    utils-->>User: minified filename
Loading

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR improves path handling across utils and core packages by replacing string manipulation with proper node:path module APIs, eliminating the requirement for trailing slashes in publicFolder parameters.

Key Changes

  • setPublicFolder: Now uses path.relative() to correctly detect if a file is already in the public folder, preventing false positives when the folder name appears in the middle of a path (e.g., "dist" vs "distribute")
  • setFileNameMin: Replaced lastIndexOf() string manipulation with path.parse() for cleaner cross-platform path handling
  • wildcards: Changed from string concatenation to path.join() for combining paths with publicFolder
  • core/compress: Updated createDirectory() to support both POSIX (/) and Windows (\) separators by checking both path.posix.dirname() and path.win32.dirname()

Testing

  • Added regression tests for trailing slash handling in setPublicFolder, wildcards, and setFileNameMin
  • Added test for false positive prevention when folder name appears in middle of path
  • New test file compress-paths.test.ts ensures Windows backslash paths work correctly
  • Relaxed action manifest test to check for fast-glob presence rather than exact version

Notes

  • All changes maintain backward compatibility
  • Improved consistency by using Node.js path APIs throughout instead of manual string operations

Confidence Score: 4/5

  • This PR is safe to merge with minor optimization opportunity in the core createDirectory logic
  • The changes properly address path handling issues by using standard Node.js path APIs instead of string manipulation. Comprehensive test coverage demonstrates the fixes work correctly. Score is 4 instead of 5 due to the slightly complex fallback logic in compress.ts that could be simplified to just use path.dirname() directly rather than trying both POSIX and Windows variants
  • packages/core/src/compress.ts - the createDirectory function's path handling could be simplified

Important Files Changed

Filename Overview
packages/utils/src/setPublicFolder.ts Improved path handling by using path.join() and path.relative() to correctly check if files are already in publicFolder, preventing false positives when folder name appears in middle of path
packages/utils/src/setFileNameMin.ts Replaced manual string manipulation with path.parse() and path.join() for cross-platform path handling, supporting both POSIX and Windows paths
packages/utils/src/wildcards.ts Changed from string concatenation to path.join() for combining publicFolder with paths, eliminating need for trailing slashes
packages/core/src/compress.ts Replaced naive lastIndexOf('/') logic with path.posix.dirname() and path.win32.dirname() to handle both separator types, though the fallback logic could be simplified

Sequence Diagram

sequenceDiagram
    participant User
    participant compress
    participant utils
    participant path_module as node:path
    participant fs as node:fs/promises

    User->>compress: compress(settings)
    
    alt output specified
        compress->>compress: createDirectory(output)
        compress->>path_module: path.posix.dirname(outputPath)
        path_module-->>compress: dirPath (POSIX)
        compress->>path_module: path.win32.dirname(outputPath)
        path_module-->>compress: dirPath (Windows)
        compress->>compress: choose first non-trivial dirPath
        compress->>fs: mkdir(dirPath, {recursive: true})
        fs-->>compress: directory created
    end

    alt single file
        compress->>utils: compressSingleFile(settings)
        utils-->>compress: result
    else multiple files
        compress->>compress: compressArrayOfFiles(settings)
        loop for each input file
            compress->>utils: getContentFromFilesAsync(input)
            utils-->>compress: content
            compress->>utils: run({settings, content, index})
            utils-->>compress: compressed result
        end
    end

    User->>utils: setPublicFolder(input, publicFolder)
    utils->>path_module: path.normalize(publicFolder)
    path_module-->>utils: normalized path
    utils->>path_module: path.relative(publicFolder, filePath)
    path_module-->>utils: relativePath
    alt already in publicFolder
        utils->>utils: return normalized path
    else not in publicFolder
        utils->>path_module: path.join(publicFolder, filePath)
        path_module-->>utils: joined path
    end
    utils-->>User: {input: processedPaths}

    User->>utils: wildcards(pattern, publicFolder)
    utils->>path_module: path.join(publicFolder, pattern)
    path_module-->>utils: fullPath
    utils->>fg: fg.globSync(fullPath, options)
    fg-->>utils: matched files
    utils-->>User: {input: files}

    User->>utils: setFileNameMin(file, output, publicFolder)
    utils->>path_module: path.parse(file)
    path_module-->>utils: {dir, name, ext}
    alt publicFolder specified
        utils->>path_module: path.join(publicFolder, name)
        path_module-->>utils: fileWithoutExtension
    end
    alt replaceInPlace
        utils->>path_module: path.join(dir, fileWithoutExtension)
        path_module-->>utils: fileWithoutExtension
    end
    utils->>utils: output.replace("$1", fileWithoutExtension)
    utils-->>User: minified filename
Loading

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR improves path handling across utils and core packages by replacing string manipulation with proper node:path module APIs, eliminating the requirement for trailing slashes in publicFolder parameters.

Key Changes

  • setPublicFolder: Now uses path.relative() to correctly detect if a file is already in the public folder, preventing false positives when the folder name appears in the middle of a path (e.g., "dist" vs "distribute")
  • setFileNameMin: Replaced lastIndexOf() string manipulation with path.parse() for cleaner cross-platform path handling
  • wildcards: Changed from string concatenation to path.join() for combining paths with publicFolder
  • core/compress: Updated createDirectory() to support both POSIX (/) and Windows (\) separators by checking both path.posix.dirname() and path.win32.dirname()

Testing

  • Added regression tests for trailing slash handling in setPublicFolder, wildcards, and setFileNameMin
  • Added test for false positive prevention when folder name appears in middle of path
  • New test file compress-paths.test.ts ensures Windows backslash paths work correctly
  • Relaxed action manifest test to check for fast-glob presence rather than exact version

Notes

  • All changes maintain backward compatibility
  • Improved consistency by using Node.js path APIs throughout instead of manual string operations

Confidence Score: 4/5

  • This PR is safe to merge with minor optimization opportunity in the core createDirectory logic
  • The changes properly address path handling issues by using standard Node.js path APIs instead of string manipulation. Comprehensive test coverage demonstrates the fixes work correctly. Score is 4 instead of 5 due to the slightly complex fallback logic in compress.ts that could be simplified to just use path.dirname() directly rather than trying both POSIX and Windows variants
  • packages/core/src/compress.ts - the createDirectory function's path handling could be simplified

Important Files Changed

Filename Overview
packages/utils/src/setPublicFolder.ts Improved path handling by using path.join() and path.relative() to correctly check if files are already in publicFolder, preventing false positives when folder name appears in middle of path
packages/utils/src/setFileNameMin.ts Replaced manual string manipulation with path.parse() and path.join() for cross-platform path handling, supporting both POSIX and Windows paths
packages/utils/src/wildcards.ts Changed from string concatenation to path.join() for combining publicFolder with paths, eliminating need for trailing slashes
packages/core/src/compress.ts Replaced naive lastIndexOf('/') logic with path.posix.dirname() and path.win32.dirname() to handle both separator types, though the fallback logic could be simplified

Sequence Diagram

sequenceDiagram
    participant User
    participant compress
    participant utils
    participant path_module as node:path
    participant fs as node:fs/promises

    User->>compress: compress(settings)
    
    alt output specified
        compress->>compress: createDirectory(output)
        compress->>path_module: path.posix.dirname(outputPath)
        path_module-->>compress: dirPath (POSIX)
        compress->>path_module: path.win32.dirname(outputPath)
        path_module-->>compress: dirPath (Windows)
        compress->>compress: choose first non-trivial dirPath
        compress->>fs: mkdir(dirPath, {recursive: true})
        fs-->>compress: directory created
    end

    alt single file
        compress->>utils: compressSingleFile(settings)
        utils-->>compress: result
    else multiple files
        compress->>compress: compressArrayOfFiles(settings)
        loop for each input file
            compress->>utils: getContentFromFilesAsync(input)
            utils-->>compress: content
            compress->>utils: run({settings, content, index})
            utils-->>compress: compressed result
        end
    end

    User->>utils: setPublicFolder(input, publicFolder)
    utils->>path_module: path.normalize(publicFolder)
    path_module-->>utils: normalized path
    utils->>path_module: path.relative(publicFolder, filePath)
    path_module-->>utils: relativePath
    alt already in publicFolder
        utils->>utils: return normalized path
    else not in publicFolder
        utils->>path_module: path.join(publicFolder, filePath)
        path_module-->>utils: joined path
    end
    utils-->>User: {input: processedPaths}

    User->>utils: wildcards(pattern, publicFolder)
    utils->>path_module: path.join(publicFolder, pattern)
    path_module-->>utils: fullPath
    utils->>fg: fg.globSync(fullPath, options)
    fg-->>utils: matched files
    utils-->>User: {input: files}

    User->>utils: setFileNameMin(file, output, publicFolder)
    utils->>path_module: path.parse(file)
    path_module-->>utils: {dir, name, ext}
    alt publicFolder specified
        utils->>path_module: path.join(publicFolder, name)
        path_module-->>utils: fileWithoutExtension
    end
    alt replaceInPlace
        utils->>path_module: path.join(dir, fileWithoutExtension)
        path_module-->>utils: fileWithoutExtension
    end
    utils->>utils: output.replace("$1", fileWithoutExtension)
    utils-->>User: minified filename
Loading

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

📝 Walkthrough

Walkthrough

The changes enhance cross-platform path handling throughout the codebase by replacing string concatenation with Node's path utilities and improving directory creation logic. Tests are expanded to cover edge cases like public folders without trailing slashes and Windows-style path separators.

Changes

Cohort / File(s) Summary
Path Utilities Source
packages/utils/src/setFileNameMin.ts, packages/utils/src/setPublicFolder.ts, packages/utils/src/wildcards.ts
Replaced string-based path concatenation with path.join() and path.parse() for improved cross-platform compatibility. Added helper function isAlreadyInPublicFolder() for more robust public folder path detection.
Path Utilities Tests
packages/utils/__tests__/setPublicFolder.test.ts, packages/utils/__tests__/utils.test.ts, packages/utils/__tests__/wildcards-ignore.test.ts
Added test cases covering public folders without trailing slashes and nested path scenarios. Refactored error-handling test to mock path.parse instead of string methods.
Core Compress
packages/core/src/compress.ts, packages/core/__tests__/compress-paths.test.ts
Enhanced createDirectory to support both POSIX and Windows path separators via path.posix.dirname and path.win32.dirname. Added comprehensive test for directory creation with Windows-style paths.
Package Tests
packages/action/__tests__/package-manifest.test.ts
Relaxed test assertion for fast-glob dependency version from exact match to non-empty string validation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • #2721: Modifies the same path-handling utilities and tests across packages/utils, with direct code-level overlap in setFileNameMin.ts, setPublicFolder.ts, and wildcards.ts.
  • #2733: Updates createDirectory in packages/core/src/compress.ts with async/parallel directory creation patterns similar to this PR's enhancements.
  • #2715: Modifies createDirectory logic for non-blocking parallel mkdir operations, converging on related cross-platform path handling improvements.

Suggested labels

Review effort 3/5

Poem

🐰 Cross-platform paths, now aligned,
No more string dancing, properly designed,
Windows and POSIX in harmony blend,
With path.join() as our trusted friend,
Directory creation flows smooth as can be!

🚥 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 accurately captures the main changes: normalizing path handling across utils and core packages, and updating test guards in the action package.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-review-findings

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
packages/utils/src/setPublicFolder.ts (1)

9-13: Missing @returns JSDoc tag on exported function.

Coding guidelines require all exported functions to have JSDoc comments with @param and @returns tags. The @returns tag is missing here.

📝 Proposed fix
 /**
  * Prepend the public folder to each file.
  * `@param` input Path to file(s)
  * `@param` publicFolder Path to the public folder
+ * `@returns` An object with the updated input path(s), or an empty object if publicFolder is invalid
  */

As per coding guidelines, packages/*/src/**/*.ts: "All exported functions MUST have JSDoc comments with @param and @returns tags."


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.

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR improves path handling across utils and core packages by replacing string manipulation with proper node:path module APIs, eliminating the requirement for trailing slashes in publicFolder parameters.

Key Changes

  • setPublicFolder: Now uses path.relative() to correctly detect if a file is already in the public folder, preventing false positives when the folder name appears in the middle of a path (e.g., "dist" vs "distribute")
  • setFileNameMin: Replaced lastIndexOf() string manipulation with path.parse() for cleaner cross-platform path handling
  • wildcards: Changed from string concatenation to path.join() for combining paths with publicFolder
  • core/compress: Updated createDirectory() to support both POSIX (/) and Windows (\) separators by checking both path.posix.dirname() and path.win32.dirname()

Testing

  • Added regression tests for trailing slash handling in setPublicFolder, wildcards, and setFileNameMin
  • Added test for false positive prevention when folder name appears in middle of path
  • New test file compress-paths.test.ts ensures Windows backslash paths work correctly
  • Relaxed action manifest test to check for fast-glob presence rather than exact version

Notes

  • All changes maintain backward compatibility
  • Improved consistency by using Node.js path APIs throughout instead of manual string operations

Confidence Score: 4/5

  • This PR is safe to merge with minor optimization opportunity in the core createDirectory logic
  • The changes properly address path handling issues by using standard Node.js path APIs instead of string manipulation. Comprehensive test coverage demonstrates the fixes work correctly. Score is 4 instead of 5 due to the slightly complex fallback logic in compress.ts that could be simplified to just use path.dirname() directly rather than trying both POSIX and Windows variants
  • packages/core/src/compress.ts - the createDirectory function's path handling could be simplified

Important Files Changed

Filename Overview
packages/utils/src/setPublicFolder.ts Improved path handling by using path.join() and path.relative() to correctly check if files are already in publicFolder, preventing false positives when folder name appears in middle of path
packages/utils/src/setFileNameMin.ts Replaced manual string manipulation with path.parse() and path.join() for cross-platform path handling, supporting both POSIX and Windows paths
packages/utils/src/wildcards.ts Changed from string concatenation to path.join() for combining publicFolder with paths, eliminating need for trailing slashes
packages/core/src/compress.ts Replaced naive lastIndexOf('/') logic with path.posix.dirname() and path.win32.dirname() to handle both separator types, though the fallback logic could be simplified

Sequence Diagram

sequenceDiagram
    participant User
    participant compress
    participant utils
    participant path_module as node:path
    participant fs as node:fs/promises

    User->>compress: compress(settings)
    
    alt output specified
        compress->>compress: createDirectory(output)
        compress->>path_module: path.posix.dirname(outputPath)
        path_module-->>compress: dirPath (POSIX)
        compress->>path_module: path.win32.dirname(outputPath)
        path_module-->>compress: dirPath (Windows)
        compress->>compress: choose first non-trivial dirPath
        compress->>fs: mkdir(dirPath, {recursive: true})
        fs-->>compress: directory created
    end

    alt single file
        compress->>utils: compressSingleFile(settings)
        utils-->>compress: result
    else multiple files
        compress->>compress: compressArrayOfFiles(settings)
        loop for each input file
            compress->>utils: getContentFromFilesAsync(input)
            utils-->>compress: content
            compress->>utils: run({settings, content, index})
            utils-->>compress: compressed result
        end
    end

    User->>utils: setPublicFolder(input, publicFolder)
    utils->>path_module: path.normalize(publicFolder)
    path_module-->>utils: normalized path
    utils->>path_module: path.relative(publicFolder, filePath)
    path_module-->>utils: relativePath
    alt already in publicFolder
        utils->>utils: return normalized path
    else not in publicFolder
        utils->>path_module: path.join(publicFolder, filePath)
        path_module-->>utils: joined path
    end
    utils-->>User: {input: processedPaths}

    User->>utils: wildcards(pattern, publicFolder)
    utils->>path_module: path.join(publicFolder, pattern)
    path_module-->>utils: fullPath
    utils->>fg: fg.globSync(fullPath, options)
    fg-->>utils: matched files
    utils-->>User: {input: files}

    User->>utils: setFileNameMin(file, output, publicFolder)
    utils->>path_module: path.parse(file)
    path_module-->>utils: {dir, name, ext}
    alt publicFolder specified
        utils->>path_module: path.join(publicFolder, name)
        path_module-->>utils: fileWithoutExtension
    end
    alt replaceInPlace
        utils->>path_module: path.join(dir, fileWithoutExtension)
        path_module-->>utils: fileWithoutExtension
    end
    utils->>utils: output.replace("$1", fileWithoutExtension)
    utils-->>User: minified filename
Loading

3 similar comments
@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR improves path handling across utils and core packages by replacing string manipulation with proper node:path module APIs, eliminating the requirement for trailing slashes in publicFolder parameters.

Key Changes

  • setPublicFolder: Now uses path.relative() to correctly detect if a file is already in the public folder, preventing false positives when the folder name appears in the middle of a path (e.g., "dist" vs "distribute")
  • setFileNameMin: Replaced lastIndexOf() string manipulation with path.parse() for cleaner cross-platform path handling
  • wildcards: Changed from string concatenation to path.join() for combining paths with publicFolder
  • core/compress: Updated createDirectory() to support both POSIX (/) and Windows (\) separators by checking both path.posix.dirname() and path.win32.dirname()

Testing

  • Added regression tests for trailing slash handling in setPublicFolder, wildcards, and setFileNameMin
  • Added test for false positive prevention when folder name appears in middle of path
  • New test file compress-paths.test.ts ensures Windows backslash paths work correctly
  • Relaxed action manifest test to check for fast-glob presence rather than exact version

Notes

  • All changes maintain backward compatibility
  • Improved consistency by using Node.js path APIs throughout instead of manual string operations

Confidence Score: 4/5

  • This PR is safe to merge with minor optimization opportunity in the core createDirectory logic
  • The changes properly address path handling issues by using standard Node.js path APIs instead of string manipulation. Comprehensive test coverage demonstrates the fixes work correctly. Score is 4 instead of 5 due to the slightly complex fallback logic in compress.ts that could be simplified to just use path.dirname() directly rather than trying both POSIX and Windows variants
  • packages/core/src/compress.ts - the createDirectory function's path handling could be simplified

Important Files Changed

Filename Overview
packages/utils/src/setPublicFolder.ts Improved path handling by using path.join() and path.relative() to correctly check if files are already in publicFolder, preventing false positives when folder name appears in middle of path
packages/utils/src/setFileNameMin.ts Replaced manual string manipulation with path.parse() and path.join() for cross-platform path handling, supporting both POSIX and Windows paths
packages/utils/src/wildcards.ts Changed from string concatenation to path.join() for combining publicFolder with paths, eliminating need for trailing slashes
packages/core/src/compress.ts Replaced naive lastIndexOf('/') logic with path.posix.dirname() and path.win32.dirname() to handle both separator types, though the fallback logic could be simplified

Sequence Diagram

sequenceDiagram
    participant User
    participant compress
    participant utils
    participant path_module as node:path
    participant fs as node:fs/promises

    User->>compress: compress(settings)
    
    alt output specified
        compress->>compress: createDirectory(output)
        compress->>path_module: path.posix.dirname(outputPath)
        path_module-->>compress: dirPath (POSIX)
        compress->>path_module: path.win32.dirname(outputPath)
        path_module-->>compress: dirPath (Windows)
        compress->>compress: choose first non-trivial dirPath
        compress->>fs: mkdir(dirPath, {recursive: true})
        fs-->>compress: directory created
    end

    alt single file
        compress->>utils: compressSingleFile(settings)
        utils-->>compress: result
    else multiple files
        compress->>compress: compressArrayOfFiles(settings)
        loop for each input file
            compress->>utils: getContentFromFilesAsync(input)
            utils-->>compress: content
            compress->>utils: run({settings, content, index})
            utils-->>compress: compressed result
        end
    end

    User->>utils: setPublicFolder(input, publicFolder)
    utils->>path_module: path.normalize(publicFolder)
    path_module-->>utils: normalized path
    utils->>path_module: path.relative(publicFolder, filePath)
    path_module-->>utils: relativePath
    alt already in publicFolder
        utils->>utils: return normalized path
    else not in publicFolder
        utils->>path_module: path.join(publicFolder, filePath)
        path_module-->>utils: joined path
    end
    utils-->>User: {input: processedPaths}

    User->>utils: wildcards(pattern, publicFolder)
    utils->>path_module: path.join(publicFolder, pattern)
    path_module-->>utils: fullPath
    utils->>fg: fg.globSync(fullPath, options)
    fg-->>utils: matched files
    utils-->>User: {input: files}

    User->>utils: setFileNameMin(file, output, publicFolder)
    utils->>path_module: path.parse(file)
    path_module-->>utils: {dir, name, ext}
    alt publicFolder specified
        utils->>path_module: path.join(publicFolder, name)
        path_module-->>utils: fileWithoutExtension
    end
    alt replaceInPlace
        utils->>path_module: path.join(dir, fileWithoutExtension)
        path_module-->>utils: fileWithoutExtension
    end
    utils->>utils: output.replace("$1", fileWithoutExtension)
    utils-->>User: minified filename
Loading

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR improves path handling across utils and core packages by replacing string manipulation with proper node:path module APIs, eliminating the requirement for trailing slashes in publicFolder parameters.

Key Changes

  • setPublicFolder: Now uses path.relative() to correctly detect if a file is already in the public folder, preventing false positives when the folder name appears in the middle of a path (e.g., "dist" vs "distribute")
  • setFileNameMin: Replaced lastIndexOf() string manipulation with path.parse() for cleaner cross-platform path handling
  • wildcards: Changed from string concatenation to path.join() for combining paths with publicFolder
  • core/compress: Updated createDirectory() to support both POSIX (/) and Windows (\) separators by checking both path.posix.dirname() and path.win32.dirname()

Testing

  • Added regression tests for trailing slash handling in setPublicFolder, wildcards, and setFileNameMin
  • Added test for false positive prevention when folder name appears in middle of path
  • New test file compress-paths.test.ts ensures Windows backslash paths work correctly
  • Relaxed action manifest test to check for fast-glob presence rather than exact version

Notes

  • All changes maintain backward compatibility
  • Improved consistency by using Node.js path APIs throughout instead of manual string operations

Confidence Score: 4/5

  • This PR is safe to merge with minor optimization opportunity in the core createDirectory logic
  • The changes properly address path handling issues by using standard Node.js path APIs instead of string manipulation. Comprehensive test coverage demonstrates the fixes work correctly. Score is 4 instead of 5 due to the slightly complex fallback logic in compress.ts that could be simplified to just use path.dirname() directly rather than trying both POSIX and Windows variants
  • packages/core/src/compress.ts - the createDirectory function's path handling could be simplified

Important Files Changed

Filename Overview
packages/utils/src/setPublicFolder.ts Improved path handling by using path.join() and path.relative() to correctly check if files are already in publicFolder, preventing false positives when folder name appears in middle of path
packages/utils/src/setFileNameMin.ts Replaced manual string manipulation with path.parse() and path.join() for cross-platform path handling, supporting both POSIX and Windows paths
packages/utils/src/wildcards.ts Changed from string concatenation to path.join() for combining publicFolder with paths, eliminating need for trailing slashes
packages/core/src/compress.ts Replaced naive lastIndexOf('/') logic with path.posix.dirname() and path.win32.dirname() to handle both separator types, though the fallback logic could be simplified

Sequence Diagram

sequenceDiagram
    participant User
    participant compress
    participant utils
    participant path_module as node:path
    participant fs as node:fs/promises

    User->>compress: compress(settings)
    
    alt output specified
        compress->>compress: createDirectory(output)
        compress->>path_module: path.posix.dirname(outputPath)
        path_module-->>compress: dirPath (POSIX)
        compress->>path_module: path.win32.dirname(outputPath)
        path_module-->>compress: dirPath (Windows)
        compress->>compress: choose first non-trivial dirPath
        compress->>fs: mkdir(dirPath, {recursive: true})
        fs-->>compress: directory created
    end

    alt single file
        compress->>utils: compressSingleFile(settings)
        utils-->>compress: result
    else multiple files
        compress->>compress: compressArrayOfFiles(settings)
        loop for each input file
            compress->>utils: getContentFromFilesAsync(input)
            utils-->>compress: content
            compress->>utils: run({settings, content, index})
            utils-->>compress: compressed result
        end
    end

    User->>utils: setPublicFolder(input, publicFolder)
    utils->>path_module: path.normalize(publicFolder)
    path_module-->>utils: normalized path
    utils->>path_module: path.relative(publicFolder, filePath)
    path_module-->>utils: relativePath
    alt already in publicFolder
        utils->>utils: return normalized path
    else not in publicFolder
        utils->>path_module: path.join(publicFolder, filePath)
        path_module-->>utils: joined path
    end
    utils-->>User: {input: processedPaths}

    User->>utils: wildcards(pattern, publicFolder)
    utils->>path_module: path.join(publicFolder, pattern)
    path_module-->>utils: fullPath
    utils->>fg: fg.globSync(fullPath, options)
    fg-->>utils: matched files
    utils-->>User: {input: files}

    User->>utils: setFileNameMin(file, output, publicFolder)
    utils->>path_module: path.parse(file)
    path_module-->>utils: {dir, name, ext}
    alt publicFolder specified
        utils->>path_module: path.join(publicFolder, name)
        path_module-->>utils: fileWithoutExtension
    end
    alt replaceInPlace
        utils->>path_module: path.join(dir, fileWithoutExtension)
        path_module-->>utils: fileWithoutExtension
    end
    utils->>utils: output.replace("$1", fileWithoutExtension)
    utils-->>User: minified filename
Loading

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR improves path handling across utils and core packages by replacing string manipulation with proper node:path module APIs, eliminating the requirement for trailing slashes in publicFolder parameters.

Key Changes

  • setPublicFolder: Now uses path.relative() to correctly detect if a file is already in the public folder, preventing false positives when the folder name appears in the middle of a path (e.g., "dist" vs "distribute")
  • setFileNameMin: Replaced lastIndexOf() string manipulation with path.parse() for cleaner cross-platform path handling
  • wildcards: Changed from string concatenation to path.join() for combining paths with publicFolder
  • core/compress: Updated createDirectory() to support both POSIX (/) and Windows (\) separators by checking both path.posix.dirname() and path.win32.dirname()

Testing

  • Added regression tests for trailing slash handling in setPublicFolder, wildcards, and setFileNameMin
  • Added test for false positive prevention when folder name appears in middle of path
  • New test file compress-paths.test.ts ensures Windows backslash paths work correctly
  • Relaxed action manifest test to check for fast-glob presence rather than exact version

Notes

  • All changes maintain backward compatibility
  • Improved consistency by using Node.js path APIs throughout instead of manual string operations

Confidence Score: 4/5

  • This PR is safe to merge with minor optimization opportunity in the core createDirectory logic
  • The changes properly address path handling issues by using standard Node.js path APIs instead of string manipulation. Comprehensive test coverage demonstrates the fixes work correctly. Score is 4 instead of 5 due to the slightly complex fallback logic in compress.ts that could be simplified to just use path.dirname() directly rather than trying both POSIX and Windows variants
  • packages/core/src/compress.ts - the createDirectory function's path handling could be simplified

Important Files Changed

Filename Overview
packages/utils/src/setPublicFolder.ts Improved path handling by using path.join() and path.relative() to correctly check if files are already in publicFolder, preventing false positives when folder name appears in middle of path
packages/utils/src/setFileNameMin.ts Replaced manual string manipulation with path.parse() and path.join() for cross-platform path handling, supporting both POSIX and Windows paths
packages/utils/src/wildcards.ts Changed from string concatenation to path.join() for combining publicFolder with paths, eliminating need for trailing slashes
packages/core/src/compress.ts Replaced naive lastIndexOf('/') logic with path.posix.dirname() and path.win32.dirname() to handle both separator types, though the fallback logic could be simplified

Sequence Diagram

sequenceDiagram
    participant User
    participant compress
    participant utils
    participant path_module as node:path
    participant fs as node:fs/promises

    User->>compress: compress(settings)
    
    alt output specified
        compress->>compress: createDirectory(output)
        compress->>path_module: path.posix.dirname(outputPath)
        path_module-->>compress: dirPath (POSIX)
        compress->>path_module: path.win32.dirname(outputPath)
        path_module-->>compress: dirPath (Windows)
        compress->>compress: choose first non-trivial dirPath
        compress->>fs: mkdir(dirPath, {recursive: true})
        fs-->>compress: directory created
    end

    alt single file
        compress->>utils: compressSingleFile(settings)
        utils-->>compress: result
    else multiple files
        compress->>compress: compressArrayOfFiles(settings)
        loop for each input file
            compress->>utils: getContentFromFilesAsync(input)
            utils-->>compress: content
            compress->>utils: run({settings, content, index})
            utils-->>compress: compressed result
        end
    end

    User->>utils: setPublicFolder(input, publicFolder)
    utils->>path_module: path.normalize(publicFolder)
    path_module-->>utils: normalized path
    utils->>path_module: path.relative(publicFolder, filePath)
    path_module-->>utils: relativePath
    alt already in publicFolder
        utils->>utils: return normalized path
    else not in publicFolder
        utils->>path_module: path.join(publicFolder, filePath)
        path_module-->>utils: joined path
    end
    utils-->>User: {input: processedPaths}

    User->>utils: wildcards(pattern, publicFolder)
    utils->>path_module: path.join(publicFolder, pattern)
    path_module-->>utils: fullPath
    utils->>fg: fg.globSync(fullPath, options)
    fg-->>utils: matched files
    utils-->>User: {input: files}

    User->>utils: setFileNameMin(file, output, publicFolder)
    utils->>path_module: path.parse(file)
    path_module-->>utils: {dir, name, ext}
    alt publicFolder specified
        utils->>path_module: path.join(publicFolder, name)
        path_module-->>utils: fileWithoutExtension
    end
    alt replaceInPlace
        utils->>path_module: path.join(dir, fileWithoutExtension)
        path_module-->>utils: fileWithoutExtension
    end
    utils->>utils: output.replace("$1", fileWithoutExtension)
    utils-->>User: minified filename
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 114 to 122
// Support POSIX and Windows path separators consistently.
const posixDirPath = path.posix.dirname(outputPath);
const windowsDirPath = path.win32.dirname(outputPath);
const dirPath =
posixDirPath !== "." && posixDirPath !== ""
? posixDirPath
: windowsDirPath !== "." && windowsDirPath !== ""
? windowsDirPath
: "";
Copy link

Choose a reason for hiding this comment

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

simplified approach using path.dirname() directly

The current logic tries both path.posix.dirname() and path.win32.dirname() and picks the first non-trivial result. This can be simplified to just use path.dirname() which automatically uses the correct separator for the current platform:

Suggested change
// Support POSIX and Windows path separators consistently.
const posixDirPath = path.posix.dirname(outputPath);
const windowsDirPath = path.win32.dirname(outputPath);
const dirPath =
posixDirPath !== "." && posixDirPath !== ""
? posixDirPath
: windowsDirPath !== "." && windowsDirPath !== ""
? windowsDirPath
: "";
// Extract directory path using platform-appropriate separator handling
const dirPath = path.dirname(outputPath);
// Early return if no directory path (dirname returns "." for files in current dir)
if (!dirPath || dirPath === ".") {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/src/compress.ts
Line: 114:122

Comment:
simplified approach using `path.dirname()` directly

The current logic tries both `path.posix.dirname()` and `path.win32.dirname()` and picks the first non-trivial result. This can be simplified to just use `path.dirname()` which automatically uses the correct separator for the current platform:

```suggestion
        // Extract directory path using platform-appropriate separator handling
        const dirPath = path.dirname(outputPath);

        // Early return if no directory path (dirname returns "." for files in current dir)
        if (!dirPath || dirPath === ".") {
```

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

📝 Walkthrough

Walkthrough

The changes enhance cross-platform path handling throughout the codebase by replacing string concatenation with Node's path utilities and improving directory creation logic. Tests are expanded to cover edge cases like public folders without trailing slashes and Windows-style path separators.

Changes

Cohort / File(s) Summary
Path Utilities Source
packages/utils/src/setFileNameMin.ts, packages/utils/src/setPublicFolder.ts, packages/utils/src/wildcards.ts
Replaced string-based path concatenation with path.join() and path.parse() for improved cross-platform compatibility. Added helper function isAlreadyInPublicFolder() for more robust public folder path detection.
Path Utilities Tests
packages/utils/__tests__/setPublicFolder.test.ts, packages/utils/__tests__/utils.test.ts, packages/utils/__tests__/wildcards-ignore.test.ts
Added test cases covering public folders without trailing slashes and nested path scenarios. Refactored error-handling test to mock path.parse instead of string methods.
Core Compress
packages/core/src/compress.ts, packages/core/__tests__/compress-paths.test.ts
Enhanced createDirectory to support both POSIX and Windows path separators via path.posix.dirname and path.win32.dirname. Added comprehensive test for directory creation with Windows-style paths.
Package Tests
packages/action/__tests__/package-manifest.test.ts
Relaxed test assertion for fast-glob dependency version from exact match to non-empty string validation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • #2721: Modifies the same path-handling utilities and tests across packages/utils, with direct code-level overlap in setFileNameMin.ts, setPublicFolder.ts, and wildcards.ts.
  • #2733: Updates createDirectory in packages/core/src/compress.ts with async/parallel directory creation patterns similar to this PR's enhancements.
  • #2715: Modifies createDirectory logic for non-blocking parallel mkdir operations, converging on related cross-platform path handling improvements.

Suggested labels

Review effort 3/5

Poem

🐰 Cross-platform paths, now aligned,
No more string dancing, properly designed,
Windows and POSIX in harmony blend,
With path.join() as our trusted friend,
Directory creation flows smooth as can be!

🚥 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 accurately captures the main changes: normalizing path handling across utils and core packages, and updating test guards in the action package.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-review-findings

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
packages/utils/src/setPublicFolder.ts (1)

9-13: Missing @returns JSDoc tag on exported function.

Coding guidelines require all exported functions to have JSDoc comments with @param and @returns tags. The @returns tag is missing here.

📝 Proposed fix
 /**
  * Prepend the public folder to each file.
  * `@param` input Path to file(s)
  * `@param` publicFolder Path to the public folder
+ * `@returns` An object with the updated input path(s), or an empty object if publicFolder is invalid
  */

As per coding guidelines, packages/*/src/**/*.ts: "All exported functions MUST have JSDoc comments with @param and @returns tags."


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.

2 similar comments
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

📝 Walkthrough

Walkthrough

The changes enhance cross-platform path handling throughout the codebase by replacing string concatenation with Node's path utilities and improving directory creation logic. Tests are expanded to cover edge cases like public folders without trailing slashes and Windows-style path separators.

Changes

Cohort / File(s) Summary
Path Utilities Source
packages/utils/src/setFileNameMin.ts, packages/utils/src/setPublicFolder.ts, packages/utils/src/wildcards.ts
Replaced string-based path concatenation with path.join() and path.parse() for improved cross-platform compatibility. Added helper function isAlreadyInPublicFolder() for more robust public folder path detection.
Path Utilities Tests
packages/utils/__tests__/setPublicFolder.test.ts, packages/utils/__tests__/utils.test.ts, packages/utils/__tests__/wildcards-ignore.test.ts
Added test cases covering public folders without trailing slashes and nested path scenarios. Refactored error-handling test to mock path.parse instead of string methods.
Core Compress
packages/core/src/compress.ts, packages/core/__tests__/compress-paths.test.ts
Enhanced createDirectory to support both POSIX and Windows path separators via path.posix.dirname and path.win32.dirname. Added comprehensive test for directory creation with Windows-style paths.
Package Tests
packages/action/__tests__/package-manifest.test.ts
Relaxed test assertion for fast-glob dependency version from exact match to non-empty string validation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • #2721: Modifies the same path-handling utilities and tests across packages/utils, with direct code-level overlap in setFileNameMin.ts, setPublicFolder.ts, and wildcards.ts.
  • #2733: Updates createDirectory in packages/core/src/compress.ts with async/parallel directory creation patterns similar to this PR's enhancements.
  • #2715: Modifies createDirectory logic for non-blocking parallel mkdir operations, converging on related cross-platform path handling improvements.

Suggested labels

Review effort 3/5

Poem

🐰 Cross-platform paths, now aligned,
No more string dancing, properly designed,
Windows and POSIX in harmony blend,
With path.join() as our trusted friend,
Directory creation flows smooth as can be!

🚥 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 accurately captures the main changes: normalizing path handling across utils and core packages, and updating test guards in the action package.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-review-findings

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
packages/utils/src/setPublicFolder.ts (1)

9-13: Missing @returns JSDoc tag on exported function.

Coding guidelines require all exported functions to have JSDoc comments with @param and @returns tags. The @returns tag is missing here.

📝 Proposed fix
 /**
  * Prepend the public folder to each file.
  * `@param` input Path to file(s)
  * `@param` publicFolder Path to the public folder
+ * `@returns` An object with the updated input path(s), or an empty object if publicFolder is invalid
  */

As per coding guidelines, packages/*/src/**/*.ts: "All exported functions MUST have JSDoc comments with @param and @returns tags."


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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

📝 Walkthrough

Walkthrough

The changes enhance cross-platform path handling throughout the codebase by replacing string concatenation with Node's path utilities and improving directory creation logic. Tests are expanded to cover edge cases like public folders without trailing slashes and Windows-style path separators.

Changes

Cohort / File(s) Summary
Path Utilities Source
packages/utils/src/setFileNameMin.ts, packages/utils/src/setPublicFolder.ts, packages/utils/src/wildcards.ts
Replaced string-based path concatenation with path.join() and path.parse() for improved cross-platform compatibility. Added helper function isAlreadyInPublicFolder() for more robust public folder path detection.
Path Utilities Tests
packages/utils/__tests__/setPublicFolder.test.ts, packages/utils/__tests__/utils.test.ts, packages/utils/__tests__/wildcards-ignore.test.ts
Added test cases covering public folders without trailing slashes and nested path scenarios. Refactored error-handling test to mock path.parse instead of string methods.
Core Compress
packages/core/src/compress.ts, packages/core/__tests__/compress-paths.test.ts
Enhanced createDirectory to support both POSIX and Windows path separators via path.posix.dirname and path.win32.dirname. Added comprehensive test for directory creation with Windows-style paths.
Package Tests
packages/action/__tests__/package-manifest.test.ts
Relaxed test assertion for fast-glob dependency version from exact match to non-empty string validation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • #2721: Modifies the same path-handling utilities and tests across packages/utils, with direct code-level overlap in setFileNameMin.ts, setPublicFolder.ts, and wildcards.ts.
  • #2733: Updates createDirectory in packages/core/src/compress.ts with async/parallel directory creation patterns similar to this PR's enhancements.
  • #2715: Modifies createDirectory logic for non-blocking parallel mkdir operations, converging on related cross-platform path handling improvements.

Suggested labels

Review effort 3/5

Poem

🐰 Cross-platform paths, now aligned,
No more string dancing, properly designed,
Windows and POSIX in harmony blend,
With path.join() as our trusted friend,
Directory creation flows smooth as can be!

🚥 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 accurately captures the main changes: normalizing path handling across utils and core packages, and updating test guards in the action package.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-review-findings

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
packages/utils/src/setPublicFolder.ts (1)

9-13: Missing @returns JSDoc tag on exported function.

Coding guidelines require all exported functions to have JSDoc comments with @param and @returns tags. The @returns tag is missing here.

📝 Proposed fix
 /**
  * Prepend the public folder to each file.
  * `@param` input Path to file(s)
  * `@param` publicFolder Path to the public folder
+ * `@returns` An object with the updated input path(s), or an empty object if publicFolder is invalid
  */

As per coding guidelines, packages/*/src/**/*.ts: "All exported functions MUST have JSDoc comments with @param and @returns tags."


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.

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

packages/core/src/compress.ts, line 122
simplified approach using path.dirname() directly

The current logic tries both path.posix.dirname() and path.win32.dirname() and picks the first non-trivial result. This can be simplified to just use path.dirname() which automatically uses the correct separator for the current platform:

        // Extract directory path using platform-appropriate separator handling
        const dirPath = path.dirname(outputPath);

        // Early return if no directory path (dirname returns "." for files in current dir)
        if (!dirPath || dirPath === ".") {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

8 similar comments
@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

packages/core/src/compress.ts, line 122
simplified approach using path.dirname() directly

The current logic tries both path.posix.dirname() and path.win32.dirname() and picks the first non-trivial result. This can be simplified to just use path.dirname() which automatically uses the correct separator for the current platform:

        // Extract directory path using platform-appropriate separator handling
        const dirPath = path.dirname(outputPath);

        // Early return if no directory path (dirname returns "." for files in current dir)
        if (!dirPath || dirPath === ".") {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

packages/core/src/compress.ts, line 122
simplified approach using path.dirname() directly

The current logic tries both path.posix.dirname() and path.win32.dirname() and picks the first non-trivial result. This can be simplified to just use path.dirname() which automatically uses the correct separator for the current platform:

        // Extract directory path using platform-appropriate separator handling
        const dirPath = path.dirname(outputPath);

        // Early return if no directory path (dirname returns "." for files in current dir)
        if (!dirPath || dirPath === ".") {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

packages/core/src/compress.ts, line 122
simplified approach using path.dirname() directly

The current logic tries both path.posix.dirname() and path.win32.dirname() and picks the first non-trivial result. This can be simplified to just use path.dirname() which automatically uses the correct separator for the current platform:

        // Extract directory path using platform-appropriate separator handling
        const dirPath = path.dirname(outputPath);

        // Early return if no directory path (dirname returns "." for files in current dir)
        if (!dirPath || dirPath === ".") {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

packages/core/src/compress.ts, line 122
simplified approach using path.dirname() directly

The current logic tries both path.posix.dirname() and path.win32.dirname() and picks the first non-trivial result. This can be simplified to just use path.dirname() which automatically uses the correct separator for the current platform:

        // Extract directory path using platform-appropriate separator handling
        const dirPath = path.dirname(outputPath);

        // Early return if no directory path (dirname returns "." for files in current dir)
        if (!dirPath || dirPath === ".") {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

packages/core/src/compress.ts, line 122
simplified approach using path.dirname() directly

The current logic tries both path.posix.dirname() and path.win32.dirname() and picks the first non-trivial result. This can be simplified to just use path.dirname() which automatically uses the correct separator for the current platform:

        // Extract directory path using platform-appropriate separator handling
        const dirPath = path.dirname(outputPath);

        // Early return if no directory path (dirname returns "." for files in current dir)
        if (!dirPath || dirPath === ".") {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

packages/core/src/compress.ts, line 122
simplified approach using path.dirname() directly

The current logic tries both path.posix.dirname() and path.win32.dirname() and picks the first non-trivial result. This can be simplified to just use path.dirname() which automatically uses the correct separator for the current platform:

        // Extract directory path using platform-appropriate separator handling
        const dirPath = path.dirname(outputPath);

        // Early return if no directory path (dirname returns "." for files in current dir)
        if (!dirPath || dirPath === ".") {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

packages/core/src/compress.ts, line 122
simplified approach using path.dirname() directly

The current logic tries both path.posix.dirname() and path.win32.dirname() and picks the first non-trivial result. This can be simplified to just use path.dirname() which automatically uses the correct separator for the current platform:

        // Extract directory path using platform-appropriate separator handling
        const dirPath = path.dirname(outputPath);

        // Early return if no directory path (dirname returns "." for files in current dir)
        if (!dirPath || dirPath === ".") {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

packages/core/src/compress.ts, line 122
simplified approach using path.dirname() directly

The current logic tries both path.posix.dirname() and path.win32.dirname() and picks the first non-trivial result. This can be simplified to just use path.dirname() which automatically uses the correct separator for the current platform:

        // Extract directory path using platform-appropriate separator handling
        const dirPath = path.dirname(outputPath);

        // Early return if no directory path (dirname returns "." for files in current dir)
        if (!dirPath || dirPath === ".") {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps
Copy link

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

packages/core/src/compress.ts, line 122
simplified approach using path.dirname() directly

The current logic tries both path.posix.dirname() and path.win32.dirname() and picks the first non-trivial result. This can be simplified to just use path.dirname() which automatically uses the correct separator for the current platform:

        // Extract directory path using platform-appropriate separator handling
        const dirPath = path.dirname(outputPath);

        // Early return if no directory path (dirname returns "." for files in current dir)
        if (!dirPath || dirPath === ".") {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Contributor

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

🤖 Fix all issues with AI agents
In `@packages/core/__tests__/compress-paths.test.ts`:
- Around line 25-39: The test currently asserts mkdir was called with a
backslash path but if getDirectoryPath is changed to normalize separators,
update the assertion in compress-paths.test.ts to expect the normalized
directory string (e.g., "nested/dir") instead of "nested\\dir"; locate the test
referencing compress(settings) and the mocked mkdir and change the expected path
to match getDirectoryPath's normalized output so
vi.mocked(mkdir).toHaveBeenCalledWith("nested/dir", { recursive: true }) remains
correct.

In `@packages/core/src/compress.ts`:
- Around line 136-148: getDirectoryPath currently may return a Win32 path with
backslashes (from path.win32.dirname) which can create a single directory with a
literal backslash on POSIX; update getDirectoryPath to normalize the win32
result to POSIX separators before returning (e.g., replace backslashes with '/'
and optionally run path.posix.normalize on that string) so mkdir receives a
proper nested path; keep the existing checks for "." and empty string and only
apply the replacement/normalization to the windowsDirPath branch in
getDirectoryPath.
🧹 Nitpick comments (2)
packages/utils/src/wildcards.ts (1)

79-79: Pre-existing: filter callback parameter path shadows the imported path module.

Not introduced by this PR, but the filter callbacks at lines 79 and 108 use path as the parameter name, which shadows the newly imported path module. If the filter body ever needs path.xxx, it would silently use the string instead. Consider renaming to filePath in a follow-up.

Suggested rename
-    const finalPaths = files.filter((path: string) => !path.includes("*"));
+    const finalPaths = files.filter((filePath: string) => !filePath.includes("*"));
-    const finalPaths = processedPaths.filter(
-        (path: string) => !path.includes("*")
-    );
+    const finalPaths = processedPaths.filter(
+        (filePath: string) => !filePath.includes("*")
+    );

Also applies to: 107-108

packages/utils/__tests__/setPublicFolder.test.ts (1)

3-3: Nit: import uses .js extension instead of .ts.

Pre-existing, but the coding guidelines require .ts extensions in local import paths. Consider updating in a follow-up.

As per coding guidelines: "Include .ts file extension in local import paths (e.g., ./setup.ts)"

Suggested fix
-import { setPublicFolder } from "../src/setPublicFolder.js";
+import { setPublicFolder } from "../src/setPublicFolder.ts";

@srod srod force-pushed the codex/fix-review-findings branch from d525471 to 67b8008 Compare February 9, 2026 20:28
@srod
Copy link
Owner Author

srod commented Feb 9, 2026

@greptile

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

10 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 136 to 145
function getDirectoryPath(outputPath: string): string {
const dirPath = path.dirname(outputPath);
if (dirPath && dirPath !== ".") {
return dirPath.replaceAll("\\", "/");
}

const windowsDirPath = path.win32.dirname(outputPath);
if (windowsDirPath && windowsDirPath !== ".") {
return windowsDirPath.replaceAll("\\", "/");
}
Copy link

Choose a reason for hiding this comment

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

Windows absolute paths break

getDirectoryPath() normalizes by doing replaceAll("\\", "/") before calling mkdir(). On Windows, this turns e.g. C:\\out\\file.min.js into C:/out, which is not a valid Windows path for fs.mkdir (it can be interpreted as a relative path and fail). Since this function is specifically meant to support Windows-style output paths, the normalization should preserve Windows absolute-path semantics (or avoid rewriting separators entirely and let Node handle native separators).

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/src/compress.ts
Line: 136:145

Comment:
**Windows absolute paths break**

`getDirectoryPath()` normalizes by doing `replaceAll("\\", "/")` before calling `mkdir()`. On Windows, this turns e.g. `C:\\out\\file.min.js` into `C:/out`, which is not a valid Windows path for `fs.mkdir` (it can be interpreted as a relative path and fail). Since this function is specifically meant to support Windows-style output paths, the normalization should preserve Windows absolute-path semantics (or avoid rewriting separators entirely and let Node handle native separators).

How can I resolve this? If you propose a fix, please make it concise.

Unify path handling for wildcard/public-folder utilities and action manifest checks across POSIX and Windows separators.

In core, preserve dirname separator semantics when creating output folders to avoid ENOENT for mixed-separator outputs (for example tmp\sub/out.js).

Includes regression tests and a patch changeset entry.
@srod srod force-pushed the codex/fix-review-findings branch from e6502df to 1d5e3ee Compare February 9, 2026 20:54
@srod srod merged commit 6a2b193 into develop Feb 9, 2026
15 checks passed
@srod srod deleted the codex/fix-review-findings branch February 9, 2026 21:00
@codecov
Copy link

codecov bot commented Feb 9, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.22%. Comparing base (ee4b1c6) to head (1d5e3ee).
⚠️ Report is 2 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #2809      +/-   ##
===========================================
+ Coverage    95.18%   95.22%   +0.03%     
===========================================
  Files           73       73              
  Lines         1725     1739      +14     
  Branches       523      527       +4     
===========================================
+ Hits          1642     1656      +14     
  Misses          83       83              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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