Skip to content

fix: handle empty content and output routing regressions#2810

Merged
srod merged 6 commits intodevelopfrom
codex/fix-review-findings
Mar 8, 2026
Merged

fix: handle empty content and output routing regressions#2810
srod merged 6 commits intodevelopfrom
codex/fix-review-findings

Conversation

@srod
Copy link
Copy Markdown
Owner

@srod srod commented Mar 8, 2026

Summary

  • treat empty string content as valid in-memory input instead of falling back to file mode
  • resolve multi-format outputs against the current input entry for indexed runs
  • make the benchmark CLI use benchmark defaults unless --compressors is passed
  • wait for Java subprocess close before reading final stdout/stderr

Testing

  • bun run test packages/core/tests/core.test.ts packages/utils/tests/utils.test.ts packages/run/tests/run.test.ts packages/cli/tests/cli.test.ts packages/cli/tests/cli-benchmark-bin.test.ts
  • bun run lint

Summary by cubic

Fixes regressions across @node-minify/core, @node-minify/utils, @node-minify/run, and @node-minify/cli. Accept empty in-memory content, route multi-format outputs per input with $1, preserve explicit extensions, and append missing format extensions for array targets; benchmark JSON is clean and subprocesses resolve on close.

  • Bug Fixes
    • @node-minify/core: Treat "" as valid content; use in-memory mode when content !== undefined.
    • @node-minify/utils: Expand $1 in per-format arrays and indexed runs; route outputs by current input; append missing extensions for array targets and $1 patterns; avoid double-append for indexed $1; preserve explicit extensions for single-string outputs.
    • @node-minify/run: Resolve on close to capture late stdout/stderr.
    • @node-minify/cli: Benchmark uses defaults unless --compressors is set; read --type from global options; suppress spinner for JSON and non‑TTY.

Written for commit badb0db. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Per-input multi-format outputs with flexible output path templating for batch runs.
  • Bug Fixes

    • Treat empty string as valid in in-memory mode.
    • Wait for child-process close before resolving output.
    • CLI benchmark: avoid fallback compressor behavior and make progress spinner safe for JSON/non‑TTY runs.
  • Tests

    • Added tests for CLI benchmarking, empty-content in-memory, child close behavior, and multi-input/multi-format outputs.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 8, 2026

🦋 Changeset detected

Latest commit: badb0db

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/cli Patch
@node-minify/core Patch
@node-minify/run Patch
@node-minify/utils Patch
@node-minify/action Patch
@node-minify/benchmark Patch
@node-minify/imagemin Patch
@node-minify/sharp Patch
@node-minify/examples Patch
@node-minify/google-closure-compiler Patch
@node-minify/yui 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/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/docs 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

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Fix empty content handling, output routing, and subprocess event handling

🐞 Bug fix 🧪 Tests

Grey Divider

Walkthroughs

Description
• Handle empty string content as valid in-memory input mode
• Fix multi-format output routing for indexed array inputs
• Wait for subprocess close event before reading final output
• Use benchmark defaults when compressors not specified
Diagram
flowchart LR
  A["Empty String Content"] -->|"Check !== undefined"| B["Valid In-Memory Mode"]
  C["Multi-Format Outputs"] -->|"Use Current Index"| D["Route to Correct Input"]
  E["Subprocess Exit"] -->|"Wait for Close Event"| F["Read Final Output"]
  G["Benchmark CLI"] -->|"No Compressors Arg"| H["Apply Defaults"]
Loading

Grey Divider

File Changes

1. packages/core/src/index.ts 🐞 Bug fix +4/-1

Check content !== undefined for in-memory mode

packages/core/src/index.ts


2. packages/core/src/setup.ts 🐞 Bug fix +2/-2

Validate empty string as valid in-memory content

packages/core/src/setup.ts


3. packages/utils/src/compressSingleFile.ts 🐞 Bug fix +1/-1

Handle undefined check for empty content

packages/utils/src/compressSingleFile.ts


View more (7)
4. packages/utils/src/run.ts 🐞 Bug fix +28/-12

Fix multi-format output routing for indexed inputs

packages/utils/src/run.ts


5. packages/run/src/index.ts 🐞 Bug fix +1/-1

Wait for close event instead of exit event

packages/run/src/index.ts


6. packages/cli/src/bin/cli.ts 🐞 Bug fix +2/-5

Use benchmark defaults when compressors omitted

packages/cli/src/bin/cli.ts


7. packages/core/__tests__/core.test.ts 🧪 Tests +9/-0

Test empty string content in memory mode

packages/core/tests/core.test.ts


8. packages/run/__tests__/run.test.ts 🧪 Tests +35/-2

Update exit to close event and add close test

packages/run/tests/run.test.ts


9. packages/utils/__tests__/utils.test.ts 🧪 Tests +57/-0

Test multi-format output for input arrays

packages/utils/tests/utils.test.ts


10. packages/cli/__tests__/cli-benchmark-bin.test.ts 🧪 Tests +47/-0

Test benchmark defaults without compressors

packages/cli/tests/cli-benchmark-bin.test.ts


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Mar 8, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. settings uses as any📘 Rule violation ✓ Correctness
Description
New test code introduces as any, suppressing TypeScript type checking and potentially hiding real
issues. This violates the project rule forbidding type suppression in changed code.
Code

packages/utils/tests/utils.test.ts[1501]

+            } as any;
Evidence
PR Compliance ID 4 forbids any use of as any in changed code, and the new test explicitly casts
settings with as any.

AGENTS.md
packages/utils/tests/utils.test.ts[1501-1501]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new test uses `as any` to coerce `settings`, which suppresses TypeScript type checking and violates the no-type-suppression rule.
## Issue Context
The compliance checklist disallows `as any` in changed code; tests should still maintain type safety.
## Fix Focus Areas
- packages/utils/__tests__/utils.test.ts[1494-1502]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. No changeset added 📘 Rule violation ⛯ Reliability
Description
This PR includes user-facing behavior changes but does not add a changeset file for release
notes/versioning. This violates the requirement to include a changeset for user-facing changes.
Code

packages/core/src/index.ts[R25-28]

+    const method =
+        compressorSettings.content !== undefined
+            ? compressSingleFile
+            : compress;
Evidence
PR Compliance ID 10 requires a changeset for user-facing changes; the PR description and code diffs
indicate user-facing behavior updates (e.g., empty string content handling) but no changeset file is
included in the provided PR diff.

AGENTS.md
packages/core/src/index.ts[25-28]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
User-facing behavior changes were made without adding a changeset file.
## Issue Context
Changeset files are required for release notes/versioning whenever user-facing behavior changes.
## Fix Focus Areas
- packages/core/src/index.ts[25-28]
- packages/cli/src/bin/cli.ts[96-112]
- packages/utils/src/run.ts[176-233]
- packages/run/src/index.ts[99-99]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Brittle benchmark JSON parse🐞 Bug ⛯ Reliability
Description
The new benchmark bin test extracts JSON by slicing stdout from the first "{" without validating it
exists, and it will accept/ignore any leading non-JSON output as long as a "{" appears later. This
makes failures harder to diagnose and can mask regressions where the benchmark command no longer
emits clean JSON on stdout.
Code

packages/cli/tests/cli-benchmark-bin.test.ts[R36-38]

+        const jsonStart = stdout.indexOf("{");
+        const parsed = JSON.parse(stdout.slice(jsonStart)) as {
+            files: Array<{
Evidence
The test finds the first '{' and parses from there without checking that the JSON actually starts at
position 0 or that '{' exists at all. Separately, the benchmark command always starts an ora spinner
before printing the reporter output, which increases the risk of non-JSON bytes being emitted during
a JSON-formatted run (depending on where ora writes), making the test’s "find the first {" approach
both brittle and permissive.

packages/cli/tests/cli-benchmark-bin.test.ts[36-41]
packages/cli/src/bin/cli.ts[98-119]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new benchmark CLI bin test parses stdout by slicing from the first `{` and calling `JSON.parse` without verifying that JSON exists or starts at the beginning. This can:
- Produce confusing failures when `{` is not present (`slice(-1)` behavior).
- Mask regressions where extra output precedes JSON (the test still passes as long as a `{` appears).
## Issue Context
The benchmark command unconditionally starts an `ora` spinner and then prints the reporter output. For `--format json`, it’s preferable that stdout be clean JSON.
## Fix Focus Areas
- packages/cli/__tests__/cli-benchmark-bin.test.ts[36-41]
- packages/cli/src/bin/cli.ts[98-119]
## Suggested changes
1) In the test:
- Assert `jsonStart &amp;gt;= 0` with a helpful error that includes stdout/stderr.
- Prefer `JSON.parse(stdout.trim())` if you intend to enforce clean JSON.
2) In the CLI benchmark command:
- Don’t start a spinner when `options.format === &amp;quot;json&amp;quot;` (and/or when `!process.stderr.isTTY`).
- Ensure any progress/spinner output goes to stderr so stdout remains machine-readable.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

4. Misleading getInputFile docs🐞 Bug ✓ Correctness
Description
The JSDoc above getInputFile still claims it returns the “first input file path”, but the function
now returns the indexed input when an index is provided. This mismatch can mislead maintainers and
cause incorrect future usage.
Code

packages/utils/src/run.ts[R149-165]

* @param input - A single file path, an array of paths, or undefined
* @returns The first input file path, or an empty string if none available
*/
-function getFirstInputFile(input: string | string[] | undefined): string {
+function getInputFile(
+    input: string | string[] | undefined,
+    index?: number
+): string {
   if (typeof input === "string") {
       return input;
   }
   if (Array.isArray(input) && input.length > 0) {
+        if (index !== undefined) {
+            return input[index] ?? "";
+        }
       return input[0] ?? "";
   }
   return "";
Evidence
The comment documents only “first input” semantics, but the implementation now uses index (when
provided) to select the current input entry.

packages/utils/src/run.ts[146-165]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getInputFile` is now index-aware, but its JSDoc still describes only “first input” behavior.
## Issue Context
This function is used to derive output paths for multi-output compressors and now must reflect indexed runs.
## Fix Focus Areas
- packages/utils/src/run.ts[146-165]
## Suggested changes
- Update the comment title and `@returns` to reflect indexed selection.
- Add an `@param index` entry describing its meaning (current input index when processing arrays).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 8, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b161dc1d-2809-414a-b7f6-af328054201d

📥 Commits

Reviewing files that changed from the base of the PR and between 0422816 and badb0db.

📒 Files selected for processing (2)
  • packages/utils/__tests__/utils.test.ts
  • packages/utils/src/run.ts

📝 Walkthrough

Walkthrough

Refactors input/output resolution and in-memory content checks (empty string now treated as provided), switches child-process finalization from exit to close, tightens CLI benchmark compressors sourcing and guards spinner usage, and adds tests covering these behaviors across packages.

Changes

Cohort / File(s) Summary
CLI Benchmark
packages/cli/__tests__/cli-benchmark-bin.test.ts, packages/cli/src/bin/cli.ts
Adds benchmark integration test; benchmark now reads compressors only from command options, sources type from program.opts(), and avoids creating/updating a spinner when format is json or stderr is not a TTY.
Content Validation & In‑Memory
packages/core/__tests__/core.test.ts, packages/core/src/index.ts, packages/core/src/setup.ts, packages/utils/src/compressSingleFile.ts
Switches content presence checks from truthiness to !== undefined, so empty-string content is treated as provided; adds test asserting in-memory minify returns "" for empty content.
Child Process Finalization
packages/run/__tests__/run.test.ts, packages/run/src/index.ts
Finalization now triggers on child close instead of exit; tests updated to emit close and a new test ensures stdout is awaited until close.
Multi‑Input / Multi‑Output Pathing
packages/utils/__tests__/utils.test.ts, packages/utils/src/run.ts
Renames getFirstInputFilegetInputFile(input, index?); refactors writeMultipleOutputs to support indexed inputs, per-format outputs ($1 expansion), conditional format extensions, and more granular target resolution; adds related tests and typings.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI (benchmark)
  participant Program as Runner/Utils
  participant Child as ChildProcess
  participant FS as FileSystem

  CLI->>Program: run benchmark with options (compressors, type, format)
  Program->>Child: spawn worker process
  Child-->>Program: stdout chunks
  Child-->>Program: close event
  Program->>Program: finalize buffers, resolve result on close
  Program->>FS: writeMultipleOutputs (resolve targets, expand "$1", append extensions)
  FS-->>Program: write complete
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰
I nibbled bytes and found a clue,
Empty strings are valid too.
Close the child, then read the stream,
Paths expand $1 like a dream.
Hop—tests pass, carrots for two. 🥕

🚥 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 clearly summarizes the main changes: handling empty content in in-memory mode and fixing output routing regressions across multiple packages.
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 (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 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
Copy Markdown

@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 10 files

Comment on lines +25 to +28
const method =
compressorSettings.content !== undefined
? compressSingleFile
: compress;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. No changeset added 📘 Rule violation ⛯ Reliability

This PR includes user-facing behavior changes but does not add a changeset file for release
notes/versioning. This violates the requirement to include a changeset for user-facing changes.
Agent Prompt
## Issue description
User-facing behavior changes were made without adding a changeset file.

## Issue Context
Changeset files are required for release notes/versioning whenever user-facing behavior changes.

## Fix Focus Areas
- packages/core/src/index.ts[25-28]
- packages/cli/src/bin/cli.ts[96-112]
- packages/utils/src/run.ts[176-233]
- packages/run/src/index.ts[99-99]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 8, 2026

Greptile Summary

This PR fixes four independent regressions across the monorepo with targeted test coverage.

  • Empty-string in-memory content (packages/core, packages/utils): All if (settings.content) truthy guards are replaced with if (settings.content !== undefined). The old falsy check caused content: "" to bypass the in-memory path and fall into file mode, where it would immediately throw because input and output were not provided. content is also removed from validateMandatoryFields.
  • Multi-format output routing for indexed runs (packages/utils/src/run.ts): getFirstInputFile is replaced with getInputFile(input, index), which returns the nth input file when index is supplied. writeMultipleOutputs now distinguishes between per-format outputs (one explicit path per format when index === undefined) and per-input-entry outputs (one base path per input with format extension appended when index is defined). Before this fix, all indexed runs resolved output paths from input[0] regardless of which input was being processed.
  • Java subprocess stdout completeness (packages/run/src/index.ts): The promise resolution point is moved from the exit event to the close event. Node.js's exit fires when the child process terminates but stdio streams may not yet be fully flushed; close fires only after all streams are closed and all buffered data is available. The new test confirms that stdout data emitted after exit (but before close) is correctly captured.
  • Benchmark CLI defaults (packages/cli/src/bin/cli.ts): The benchmark subcommand action was falling back to the parent program's --compressor flag when --compressors was not passed. This capped benchmark runs to a single compressor instead of using the benchmark package's own defaults. The fallback is removed; passing undefined now lets the benchmark function apply its internal defaults.

All four fixes are well-scoped, directly address documented regressions, and are covered by new tests.

Confidence Score: 5/5

  • This PR is safe to merge — all four fixes are well-scoped, directly address documented regressions, and are covered by new tests.
  • Each change is minimal and surgical: falsy-to-undefined-check conversions, an exit-to-close event swap for proper stream handling, an index-aware input resolver, and removal of an incorrect CLI fallback. All are accompanied by targeted regression tests that previously would have failed. The fixes directly match the described regressions in the PR summary.
  • No files require special attention

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["minify(settings)"] --> B["setup(settings)"]
    B --> C{settings.content\n!== undefined?}
    C -- Yes --> D["validateMandatoryFields\n(['compressor'])"]
    D --> E["compressSingleFile(settings)"]
    C -- No --> F["validateMandatoryFields\n(['compressor','input','output'])"]
    F --> G["enhanceSettings(settings)"]
    G --> H["compress(settings)"]

    E --> I["determineContent(settings)"]
    I --> J{content\n!== undefined?}
    J -- Yes, even empty string --> K["return settings.content"]
    J -- No --> L["read from input file(s)"]
    K --> M["run({ settings, content })"]
    L --> M

    M --> N["compressor(...)"]
    N --> O["writeOutput(result, settings, index)"]
    O --> P{settings.content\n!== undefined?}
    P -- Yes, in-memory → skip write --> Q["return result.code"]
    P -- No --> R{result.outputs?}
    R -- Yes --> S["writeMultipleOutputs(outputs, settings, index)"]
    R -- No --> T["writeFileAsync(output, code)"]
    S --> U{index defined?}
    U -- Yes --> V["currentOutput = output[index]\nauto-append .format extension"]
    U -- No, perFormatOutputs --> W["arrayItem = output[i]\nuse explicit path per format"]
    V --> Q
    W --> Q
    T --> Q

    subgraph "run/src/index.ts — Java subprocess"
    X["spawn java"] --> Y["listen to stdout/stderr data"]
    Y --> Z["child.on('close', ...)"]
    Z --> AA["resolve(stdout)"]
    end
Loading

Last reviewed commit: a50e294

srod added 2 commits March 8, 2026 16:27
Treat empty string content as valid in-memory input, resolve multi-format outputs against the current input entry, make benchmark CLI use benchmark defaults, and wait for java processes to close before reading final output.
Suppress spinner output for JSON benchmark runs, add the required changeset, remove the new type suppression in utils tests, and update the indexed input helper docs.
@srod srod force-pushed the codex/fix-review-findings branch from 82b7fc6 to 43c11f7 Compare March 8, 2026 15:27
Copy link
Copy Markdown
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/utils/src/run.ts`:
- Around line 202-228: The per-format output branch (using perFormatOutputs /
arrayItem / output[i]) treats entries like "dist/$1.webp" as literal paths and
skips $1 substitution; update the logic in the initial branch that sets
targetFile from arrayItem so that if arrayItem is a string containing "$1" you
replace all "$1" with the computed inputBase (falling back to "output") before
deciding targetFile, and if the resulting value does not already include the
format extension append `.${format}` when appropriate (mirror the behavior in
the currentOutput includes("$1") branch), using the same helpers (inputBase,
inputDir, format, join) and preserving the existing checks for
undefined/trim/"$1".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3ce67335-e139-434a-953d-f74ac250d5d8

📥 Commits

Reviewing files that changed from the base of the PR and between a50e294 and 43c11f7.

⛔ Files ignored due to path filters (1)
  • .changeset/fresh-tomatoes-crash.md is excluded by !.changeset/**
📒 Files selected for processing (10)
  • packages/cli/__tests__/cli-benchmark-bin.test.ts
  • packages/cli/src/bin/cli.ts
  • packages/core/__tests__/core.test.ts
  • packages/core/src/index.ts
  • packages/core/src/setup.ts
  • packages/run/__tests__/run.test.ts
  • packages/run/src/index.ts
  • packages/utils/__tests__/utils.test.ts
  • packages/utils/src/compressSingleFile.ts
  • packages/utils/src/run.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/run/src/index.ts
  • packages/cli/tests/cli-benchmark-bin.test.ts
  • packages/core/src/index.ts
  • packages/core/tests/core.test.ts
  • packages/utils/tests/utils.test.ts

Copy link
Copy Markdown
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/utils/src/run.ts`:
- Around line 229-235: The code handling indexed `$1` output patterns (in the
branch using currentOutput.includes("$1") in run.ts) blindly appends
`.${format}` after replacing `$1`, causing doubled extensions like
`dist/foo.webp.webp`; update the logic that sets targetFile (after const
outputFile = currentOutput.replace(/\$1/g, baseName)) to only append
`.${format}` when outputFile does not already end with `.${format}` (use a
case-sensitive endsWith check), and ensure this mirrors the extension-guard
behavior used in the per-format-array branch; also add a regression test for an
indexed pattern like "dist/$1.webp" with index set to confirm no
double-extension occurs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f3ad6992-168f-4604-8820-c792de50cec5

📥 Commits

Reviewing files that changed from the base of the PR and between 43c11f7 and 15a765c.

📒 Files selected for processing (2)
  • packages/utils/__tests__/utils.test.ts
  • packages/utils/src/run.ts

Copy link
Copy Markdown
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/utils/src/run.ts`:
- Around line 236-240: The branch handling a single string output currently
appends `.${format}` directly causing duplicated extensions for explicit
filenames like "dist/foo.webp"; update the branch that sets `targetFile` (using
the variables `currentOutput`, `format`, and `targetFile`) to call the existing
helper `withFormatExtension(currentOutput, format)` instead of
string-concatenating `.${format}` so explicit extensions are preserved; ensure
you reuse `withFormatExtension()` logic exactly as used elsewhere in this module
to normalize both plain-string and indexed multi-format outputs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9804469c-5b2e-45bc-a0a8-4f3e1accf5dc

📥 Commits

Reviewing files that changed from the base of the PR and between 15a765c and bf8f3fe.

📒 Files selected for processing (2)
  • packages/utils/__tests__/utils.test.ts
  • packages/utils/src/run.ts

Copy link
Copy Markdown
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/utils/src/run.ts`:
- Around line 207-219: The per-format array branch currently uses explicit array
entries (arrayItem) as-is and therefore skips appending the format extension;
update the branch inside the perFormatOutputs handling so that after computing
targetFile (both in the arrayItem.includes("$1") and the "else" explicit path)
you pass the resolved path through withFormatExtension(targetFile, format) (or
call withFormatExtension on arrayItem before assigning to targetFile) ensuring
entries like "dist/foo" become "dist/foo.webp" or "dist/foo.avif"; also add a
regression test for an array-style per-format target with no extension (e.g.,
["dist/foo"]) verifying the correct format extension is appended.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f3d8e9dc-b783-4ff5-9f5a-f2e1d39d843c

📥 Commits

Reviewing files that changed from the base of the PR and between bf8f3fe and 0422816.

📒 Files selected for processing (2)
  • packages/utils/__tests__/utils.test.ts
  • packages/utils/src/run.ts

Comment on lines 207 to +219
if (
isArrayOutput &&
perFormatOutputs &&
arrayItem !== undefined &&
arrayItem !== "$1" &&
arrayItem.trim() !== ""
) {
// Explicit output path provided in array - use as-is
targetFile = arrayItem;
} else if (typeof output === "string" && output === "$1") {
if (arrayItem.includes("$1")) {
const outputFile = arrayItem.replace(/\$1/g, baseName);
targetFile = withFormatExtension(outputFile, format);
} else {
// Explicit output path provided in array - use as-is
targetFile = arrayItem;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Append the format for explicit per-format array targets too.

In this branch, entries like ["dist/foo", "dist/bar"] still bypass withFormatExtension(), so they write to dist/foo/dist/bar instead of dist/foo.webp/dist/bar.avif. That leaves per-format output arrays inconsistent with the single-string and indexed branches, and it misses the PR’s auto-extension behavior.

Suggested fix
         if (
             perFormatOutputs &&
-            arrayItem !== undefined &&
+            typeof arrayItem === "string" &&
             arrayItem !== "$1" &&
             arrayItem.trim() !== ""
         ) {
             if (arrayItem.includes("$1")) {
                 const outputFile = arrayItem.replace(/\$1/g, baseName);
                 targetFile = withFormatExtension(outputFile, format);
             } else {
-                // Explicit output path provided in array - use as-is
-                targetFile = arrayItem;
+                targetFile = withFormatExtension(arrayItem, format);
             }
         } else if (

Please add a regression test for the no-extension per-format-array case alongside this.

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

In `@packages/utils/src/run.ts` around lines 207 - 219, The per-format array
branch currently uses explicit array entries (arrayItem) as-is and therefore
skips appending the format extension; update the branch inside the
perFormatOutputs handling so that after computing targetFile (both in the
arrayItem.includes("$1") and the "else" explicit path) you pass the resolved
path through withFormatExtension(targetFile, format) (or call
withFormatExtension on arrayItem before assigning to targetFile) ensuring
entries like "dist/foo" become "dist/foo.webp" or "dist/foo.avif"; also add a
regression test for an array-style per-format target with no extension (e.g.,
["dist/foo"]) verifying the correct format extension is appended.

@srod
Copy link
Copy Markdown
Owner Author

srod commented Mar 8, 2026

@coderabbitai

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 8, 2026

@srod Sure! I'll review the PR now.


🧠 Learnings used
Learnt from: CR
Repo: srod/node-minify PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-22T16:14:03.026Z
Learning: Applies to packages/{core,cli}/src/**/*.ts : Resolve compressor packages using `resolveCompressor` and `isBuiltInCompressor` utilities from `node-minify/utils`

Learnt from: CR
Repo: srod/node-minify PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-22T16:14:03.026Z
Learning: Applies to packages/node-minify-*-?(compressor)/src/index.ts : Use async file operations from `node-minify/utils` (e.g., `getContentFromFilesAsync`, `isValidFileAsync`) instead of synchronous variants in compressor code

Learnt from: CR
Repo: srod/node-minify PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-22T16:14:03.026Z
Learning: Applies to packages/node-minify-*-?(compressor)/src/index.ts : Use `ensureStringContent(content, "compressor-name")` for input validation in compressor packages

Learnt from: CR
Repo: srod/node-minify PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-22T16:14:03.026Z
Learning: Applies to packages/node-minify-*-?(compressor)/** : All compressor packages follow the standard package structure: `src/index.ts` for main export, `__tests__/` for tests, and use `tsdown` for building

Learnt from: CR
Repo: srod/node-minify PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-22T16:14:03.026Z
Learning: Applies to packages/node-minify-*-?(compressor)/src/index.ts : Compressor packages must export an async function matching the `Compressor` type from `node-minify/types` that receives `{ settings, content }` and returns `{ code, map? }`

Learnt from: CR
Repo: srod/node-minify PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-22T16:14:03.026Z
Learning: Applies to packages/*/src/**/*.ts : Use the `Compressor`, `Settings`, `MinifierOptions`, and `CompressorResult` types from `node-minify/types` for type consistency
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@srod
Copy link
Copy Markdown
Owner Author

srod commented Mar 8, 2026

@coderabbitai resume

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 8, 2026

✅ Actions performed

Reviews resumed.

@srod srod merged commit e8fef5a into develop Mar 8, 2026
9 checks passed
@srod srod deleted the codex/fix-review-findings branch March 8, 2026 16:45
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 8, 2026

Codecov Report

❌ Patch coverage is 97.50000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 95.21%. Comparing base (0197540) to head (badb0db).
⚠️ Report is 7 commits behind head on develop.

Files with missing lines Patch % Lines
packages/utils/src/run.ts 96.96% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #2810      +/-   ##
===========================================
- Coverage    95.22%   95.21%   -0.01%     
===========================================
  Files           73       73              
  Lines         1739     1757      +18     
  Branches       527      543      +16     
===========================================
+ Hits          1656     1673      +17     
- Misses          83       84       +1     

☔ 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