Skip to content

fix(sourcemap): preserve unmapped boundaries during composition#10254

Merged
hyfdev merged 1 commit into
mainfrom
codex/sourcemap-unmapped-boundaries
Jul 15, 2026
Merged

fix(sourcemap): preserve unmapped boundaries during composition#10254
hyfdev merged 1 commit into
mainfrom
codex/sourcemap-unmapped-boundaries

Conversation

@hyfdev

@hyfdev hyfdev commented Jul 13, 2026

Copy link
Copy Markdown
Member

Why

This PR is stacked on #10249.

A source-map segment changes the mapping state from its generated column until the next segment. It is not just a label for one character. A segment with a source starts a mapped range; a one-field segment with only a generated column starts an explicitly unmapped range.

For example, the transform fixture returns AAAA,K for this generated line:

columns    012345678901234567
generated  foo(); injected();

column 0   start mapping to main.js
column 5   stop mapping

The intended ranges are therefore:

Mapped    generated 0:0–0:5   -> main.js 0:0
Unmapped  generated 0:5–EOL

What a source-map visualizer shows

The blocks below represent the colored spans that a visualizer associates with the original source. is mapped and is uncolored or explicitly unmapped.

Before this PR, composition dropped the one-field segment at column 5:

input map      AAAA,K
collapsed map  AAAA

generated  foo(); injected();
visualized ██████████████████

With no boundary after column 0, the previous mapping remains active to the end of the line. injected() is colored as if it came from foo(); asking a source-map consumer for the original position of injected() returns the earlier main.js mapping.

After this PR, composition preserves the boundary:

input map      AAAA,K
collapsed map  AAAA,K

generated  foo(); injected();
visualized █████░░░░░░░░░░░░░

The generated foo() remains associated with the original source, while the semicolon and injected() have no original position. A visualizer leaves that range uncolored, and a debugger or other source-map consumer no longer attributes it to foo().

The same rule applies when the unmapped boundary appears in an intermediate map instead of the final map.

Rollup currently drops these one-field segments while collapsing maps. This PR deliberately differs from that behavior so an explicit unmapped range remains explicit after composition.

What changed

  • stop tracing when a final or intermediate token has no source
  • emit an unmapped token at the corresponding final generated position
  • cover final and intermediate boundaries with Rust tests
  • cover a plugin transform returning AAAA,K

Validation

  • cargo test -p rolldown_sourcemap
  • just test-rust
  • just test-node-rolldown-only fixtures-concurrent.test.ts -t plugin/transform/explicit-unmapped-boundary
  • cargo clippy -p rolldown_sourcemap --all-targets -- --deny warnings

hyfdev commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

How to use the Graphite Merge Queue

Add the label graphite: merge-when-ready to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@netlify

netlify Bot commented Jul 13, 2026

Copy link
Copy Markdown

Deploy Preview for rolldown-rs ready!

Name Link
🔨 Latest commit 2e29bfc
🔍 Latest deploy log https://app.netlify.com/projects/rolldown-rs/deploys/6a5746b5b1a8c4000803242e
😎 Deploy Preview https://deploy-preview-10254--rolldown-rs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@hyfdev
hyfdev changed the base branch from main to graphite-base/10254 July 13, 2026 07:50
@hyfdev
hyfdev force-pushed the graphite-base/10254 branch from b3038d4 to d862c77 Compare July 13, 2026 07:50
@hyfdev
hyfdev force-pushed the codex/sourcemap-unmapped-boundaries branch from cf12a71 to 2d55e36 Compare July 13, 2026 07:50
@hyfdev
hyfdev changed the base branch from graphite-base/10254 to codex/issue-10070-root-fix July 13, 2026 07:50
@hyfdev
hyfdev force-pushed the codex/issue-10070-root-fix branch from d862c77 to c931d1e Compare July 13, 2026 07:57
@hyfdev
hyfdev force-pushed the codex/sourcemap-unmapped-boundaries branch 2 times, most recently from 64b4cb3 to f3b2bcb Compare July 13, 2026 09:49
@hyfdev
hyfdev force-pushed the codex/issue-10070-root-fix branch from c931d1e to 584ebca Compare July 13, 2026 09:49
@hyfdev
hyfdev marked this pull request as ready for review July 14, 2026 17:02
Copilot AI review requested due to automatic review settings July 14, 2026 17:02

Copilot AI left a comment

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@hyfdev
hyfdev requested a review from sapphi-red July 14, 2026 17:02
@codspeed-hq

codspeed-hq Bot commented Jul 14, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 7 untouched benchmarks
⏩ 10 skipped benchmarks1


Comparing codex/sourcemap-unmapped-boundaries (2e29bfc) with main (1d3fb15)2

Open in CodSpeed

Footnotes

  1. 10 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (f26ce7a) during the generation of this report, so 1d3fb15 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@pkg-pr-new

pkg-pr-new Bot commented Jul 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

@rolldown/browser

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/browser@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/browser@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/debug

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/debug@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/debug@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

rolldown

pnpm add https://pkg.pr.new/rolldown/rolldown@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown@10254 -D
yarn add https://pkg.pr.new/rolldown/[email protected] -D

@rolldown/binding-android-arm64

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-android-arm64@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-android-arm64@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-darwin-arm64

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-darwin-arm64@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-darwin-arm64@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-darwin-x64

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-darwin-x64@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-darwin-x64@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-freebsd-x64

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-freebsd-x64@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-freebsd-x64@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-linux-arm-gnueabihf

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-arm-gnueabihf@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-arm-gnueabihf@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-linux-arm64-gnu

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-arm64-gnu@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-arm64-gnu@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-linux-arm64-musl

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-arm64-musl@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-arm64-musl@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-linux-ppc64-gnu

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-ppc64-gnu@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-ppc64-gnu@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-linux-s390x-gnu

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-s390x-gnu@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-s390x-gnu@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-linux-x64-gnu

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-x64-gnu@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-x64-gnu@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-linux-x64-musl

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-x64-musl@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-linux-x64-musl@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-openharmony-arm64

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-openharmony-arm64@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-openharmony-arm64@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-wasm32-wasi

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-wasm32-wasi@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-wasm32-wasi@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-win32-arm64-msvc

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-win32-arm64-msvc@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-win32-arm64-msvc@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

@rolldown/binding-win32-x64-msvc

pnpm add https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-win32-x64-msvc@10254 -D
npm i https://pkg.pr.new/rolldown/rolldown/@rolldown/binding-win32-x64-msvc@10254 -D
yarn add https://pkg.pr.new/rolldown/rolldown/@rolldown/[email protected] -D

commit: 3600bc0

@sapphi-red

Copy link
Copy Markdown
Member

If applicable, would you add a test case that covers #6399 case?

@hyfdev
hyfdev force-pushed the codex/sourcemap-unmapped-boundaries branch from f3b2bcb to c81e977 Compare July 15, 2026 05:55
@hyfdev
hyfdev force-pushed the codex/issue-10070-root-fix branch from 584ebca to e0bd819 Compare July 15, 2026 05:55
@hyfdev
hyfdev force-pushed the codex/sourcemap-unmapped-boundaries branch from c81e977 to 3600bc0 Compare July 15, 2026 06:31
@hyfdev
hyfdev force-pushed the codex/issue-10070-root-fix branch from e0bd819 to 84f1aa1 Compare July 15, 2026 06:31

hyfdev commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

Merge activity

  • Jul 15, 6:56 AM UTC: The merge label 'graphite: merge-when-ready' was detected. This PR will be added to the Graphite merge queue once it meets the requirements.
  • Jul 15, 7:00 AM UTC: hyfdev added this pull request to the Graphite merge queue.
  • Jul 15, 7:07 AM UTC: The Graphite merge queue couldn't merge this PR because it had merge conflicts.
  • Jul 15, 8:38 AM UTC: The merge label 'graphite: merge-when-ready' was detected. This PR will be added to the Graphite merge queue once it meets the requirements.
  • Jul 15, 8:41 AM UTC: hyfdev added this pull request to the Graphite merge queue.

@graphite-app
graphite-app Bot changed the base branch from codex/issue-10070-root-fix to graphite-base/10254 July 15, 2026 06:59
graphite-app Bot pushed a commit that referenced this pull request Jul 15, 2026
refs #10070.

## The behavior to review

This PR makes one choice: when a coarse outer map points to a column before the first mapping on the same line of a more detailed inner map, use that first same-line mapping instead of dropping the generated position.

Rollup makes the same choice when tracing segments. The fallback never crosses a line.

## Concrete before and after

### User input

`main.js` is the source written by the user:

```js
export function app() {
  globalThis.side = 1;
  return 42;
}
```

### Generated output

Rolldown produces this chunk. Region comments and the `sourceMappingURL` line are omitted here, but the code shape is otherwise the fixture's real output:

```js
function app() {
	globalThis.side = 1;
	return 42;
}
export { app };
```

The generated JavaScript is identical before and after this PR. Only its source map changes.

### Before this PR

Asking the composed map where the two generated statements came from returns no original position:

```text
generated 3:1  globalThis.side = 1  ──X──>  null
generated 4:1  return 42             ──X──>  null
```

In a source-map visualizer, these generated statements have no colored counterpart in the Original pane. A debugger or stack-trace consumer cannot take these positions back to `main.js`.

### After this PR

The same generated positions resolve to the corresponding user-written statements:

```text
Generated output                              User input: main.js

3:1  globalThis.side = 1  ─────────────────>  2:2  globalThis.side = 1
4:1  return 42             ─────────────────>  3:2  return 42
```

Source-map consumer lines are one-based and columns are zero-based. These are the actual positions asserted by the integration fixture.

In a visualizer, each generated statement now shares a color with its corresponding statement in the Original pane. Selecting either side can identify the other side. Debuggers and stack traces can return to the correct original line; the column is the best same-line position available from the coarse map.

## Why the lookup changes

The map chain contains two different levels of detail:

```text
detailed map:  intermediate column 2 -> user source
coarse map:    final column 0        -> intermediate column 0
```

Before:

```text
final column 0
  -> intermediate column 0
  -> detailed map has no mapping at or before column 0
  -> drop the generated position
```

After:

```text
final column 0
  -> intermediate column 0
  -> detailed map's first mapping on this line is column 2
  -> use column 2 and preserve the generated position
```

Lookups between or after existing mappings still use the nearest mapping at or before the requested column. Missing and empty lines still fail. One-field explicitly unmapped segments are skipped in this PR, matching Rollup; #10254 separately preserves those boundaries.

#10074 remains necessary because it makes Rolldown-owned mutation maps more precise. This PR covers coarse external maps and other cases where the producer did not provide matching columns.

## Why the snapshots change

The snapshot visualizer writes mappings as:

```text
(original line:column) "original text" --> (generated line:column) "generated text"
```

Unlike the source-map consumer positions above, these snapshot coordinates are zero-based for both lines and columns. The three snapshots only add mappings; no existing mapping is removed or changed.

| Snapshot | Newly restored generated mapping | Previous first mapping on that generated line | Original position used |
| --- | --- | --- | --- |
| `misc/wrapped_esm` | `60:1 "("`, `60:2 "{"` | `60:3 "e} = "` | `foo.js 4:4` |
| `misc/wrapped_esm` | `61:1 "("`, `61:2 "{"` | `61:3 "h: "` | `foo.js 7:2` |
| `misc/wrapped_esm` | `73:1 "("`, `73:2 "{"` | `73:3 "destructuring} = "` | `foo.js 30:6` |
| `wrapped_esm_default_function` | `19:0 "init_foo("` | `19:9 ");"` | `bar.js 0:23` |
| `wrapped_esm_export_named_function` | `18:0 "init_foo("` | `18:9 ");"` | `bar.js 0:27` |

There are eight added rows in total: six in `misc/wrapped_esm`, one in each deconflict snapshot. Every addition follows the behavior under review:

```text
new generated column < previous first mapped column on that line
new original position = previous first mapping's original position
```

For example:

```diff
+(0:23) ";\n" --> (19:0) "init_foo("
 (0:23) ";\n" --> (19:9) ");\n"
```

The coarse map requested generated column 0, while the detailed map's first mapping was at column 9. The fallback associates column 0 with the same original position already used at column 9. It does not move or replace the existing mapping.

## Suggested review order

1. Review the lookup change and `source_id` guards in `crates/rolldown_sourcemap/src/lib.rs`.
2. Review the Rust test where a column-0 coarse token meets a column-2 detailed token.
3. Review the `renderChunk` fixture, which exercises the public plugin path and asserts the exact positions shown above.
4. Check the snapshot table against the eight added snapshot rows.

## User impact

- generated JavaScript, runtime behavior, and bundle size do not change
- users of source maps regain original locations for lines previously dropped during composition
- the change matters when a plugin or another transform provides a less column-detailed map than Rolldown's preceding map
- already resolvable mappings are unchanged

## Validation

- `cargo test -p rolldown_sourcemap`
- `just test-rust`
- `just test-node-rolldown-only fixtures-concurrent.test.ts -t plugin/render-chunk/coarse-sourcemap-composition`
- `cargo clippy -p rolldown_sourcemap --all-targets -- --deny warnings`
@graphite-app
graphite-app Bot changed the base branch from graphite-base/10254 to main July 15, 2026 07:05
@hyfdev
hyfdev force-pushed the codex/sourcemap-unmapped-boundaries branch from 3600bc0 to 2e29bfc Compare July 15, 2026 08:37
@hyfdev
hyfdev merged commit f49ebe4 into main Jul 15, 2026
53 of 54 checks passed
@hyfdev
hyfdev deleted the codex/sourcemap-unmapped-boundaries branch July 15, 2026 08:41
@rolldown-guard rolldown-guard Bot mentioned this pull request Jul 15, 2026
shulaoda added a commit that referenced this pull request Jul 15, 2026
## [1.2.0] - 2026-07-15

### 🚀 Features

- dev: skip shipping factories for newly imported top-level modules (#10223) by @h-a-n-a
- dev: per-client ship map for HMR patch sizing (#10208) by @h-a-n-a
- dev: client-side HMR (#10164) by @h-a-n-a
- dev: send a full-reload update to clients when a tsconfig changes (#10262) by @shulaoda
- treat `import.meta['url']` and `import.meta['ROLLUP_FILE_URL_*']` as side-effect free (#10267) by @sapphi-red
- rewrite `import.meta['url']` (#10251) by @sapphi-red
- add `FILE_NOT_FOUND` error (#10220) by @sapphi-red
- treat `import.meta.ROLLUP_FILE_URL_*` as side-effect free (#10217) by @sapphi-red

### 🐛 Bug Fixes

- sourcemap: preserve unmapped boundaries during composition (#10254) by @hyfdev
- `[format]` in `*FileNames` option for ESM format should be `es` instead of `esm` (#10214) by @sapphi-red
- sourcemap: preserve coarse mappings during composition (#10249) by @hyfdev
- rolldown_plugin_vite_import_glob: support tsconfig paths with `import.meta.glob` (#10167) by @sapphi-red
- dev: clear tsconfig caches for bare full builds (#10276) by @shulaoda
- dev: force a full rebuild when a tsconfig changes (#10261) by @shulaoda
- treat rooted drive-less module ids as absolute in preserveModules naming (#10235) by @IWANABETHATGUY
- watch: rebuild when tsconfig files change (#10258) by @shulaoda
- watch: drop tsconfig-merged transform options on each rebuild (#10257) by @shulaoda
- incorrect `EMPTY_IMPORT_META` warning for `import.meta.ROLLUP_FILE_URL_*` for CJS output (#10221) by @sapphi-red
- deconflict: rename CJS locals shadowing wrapped-ESM namespace objects (#9970) by @IWANABETHATGUY
- rolldown: drop the unused runtime module after entry-level external flattening (#10237) by @IWANABETHATGUY
- rolldown: re-propagate has_dynamic_exports to transitive star importers (#10239) by @IWANABETHATGUY
- tree-shaking: tree-shake destructured dynamic import namespace bindings (#10213) by @logaretm
- s390x: use json-escape-simd 3.1.1 for big-endian JSON escaping fix (#10211) by @satyamg1620

### 🚜 Refactor

- dev: move full-reload to client side (#10207) by @h-a-n-a
- readability follow-ups to the ReplaceWith migration (#10286) by @IWANABETHATGUY
- replace take_in-then-write-back with ReplaceWith and by-value moves (#10285) by @Boshen
- share the main resolver's cache with the transformer's tsconfig lookups (#10205) by @shulaoda
- rolldown: extract the ns star-external __reExport emission rule into LinkingMetadata (#10238) by @IWANABETHATGUY
- rolldown: unify link/generate diagnostics into a Diagnostics accumulator (#10234) by @IWANABETHATGUY
- sourcemap_filenames: drop dead sourcemap-filename plumbing (#10189) by @IWANABETHATGUY
- extract external import symbol merging into a method (#10224) by @IWANABETHATGUY
- rolldown: skip CJS namespace merging under strict execution order (#10203) by @hyfdev
- resolve the manual tsconfig per file instead of once at startup (#10200) by @shulaoda
- rolldown: route interop ESM init emission through a shared init-target view (#10202) by @hyfdev
- rolldown: collapse vestigial wrap-kind state and share chunk sort helper (#10201) by @hyfdev

### 📚 Documentation

- show plugin kinds in JSDoc and each hook's description (#10218) by @sapphi-red
- add an explanation about removing imports from external modules without any messages (#10215) by @sapphi-red

### ⚡ Performance

- sourcemap: owned merge in SourceJoiner::join (4005->5 allocs/chunk) (#10250) by @Boshen
- avoid redundant sourcemap string copies in collapse and minify paths (#10093) by @Boshen

### 🧪 Testing

- code-splitting: establish strict-order review baselines (#10287) by @hyfdev
- dev: add hot API test cases (#10181) by @h-a-n-a
- code-splitting: normalize strict execution order variants (#10277) by @hyfdev
- code-splitting: harden strict execution order coverage (#10252) by @hyfdev
- code-splitting: add strict execution order regressions (#10253) by @hyfdev

### ⚙️ Miscellaneous Tasks

- deps: update github actions (#10241) by @renovate[bot]
- deps: update oxc to 0.140.0 (#10274) by @shulaoda
- update Yunfei's GitHub username (#10275) by @hyfdev
- deps: update napi (#10260) by @renovate[bot]
- deps: update test262 submodule for tests (#10266) by @rolldown-guard[bot]
- deps: update dependency vite-plus to v0.2.4 (#10256) by @renovate[bot]
- deps: update napi (#10240) by @renovate[bot]
- deps: update oxc resolver to v11.24.2 (#10245) by @renovate[bot]
- deps: update rust crates (#10244) by @renovate[bot]
- disable Renovate updates for idna_adapter (#10248) by @shulaoda
- deps: update oxc resolver to v11.24.1 (#10232) by @renovate[bot]
- deps: update rust crate oxc_sourcemap to v8.1.1 (#10233) by @renovate[bot]
- deps: update dependency rolldown-plugin-dts to ^0.27.0 (#10206) by @renovate[bot]
- deps: upgrade sugar_path to v3 (#10230) by @hyfdev
- add `dist-*` to `.gitignore` in sourcemap-filenames/hash-final-content fixture (#10216) by @sapphi-red
- deps: update dependency rust to v1.97.0 (#10209) by @renovate[bot]

### ❤️ New Contributors

* @satyamg1620 made their first contribution in [#10211](#10211)

Co-authored-by: shulaoda <[email protected]>
graphite-app Bot pushed a commit that referenced this pull request Jul 21, 2026
…10368)

### Description

The `node-test-windows` job has been failing on every `main` run since 2026-07-15 (for example [this run](https://github.com/rolldown/rolldown/actions/runs/29795703407/job/88527096422)). The two fixtures added in #10249 and #10254 guard their `load` and `transform` hooks with `id.endsWith('/main.js')`. On Windows, module ids use backslashes, so the guard never matches and the hooks are silently skipped.

With the hooks skipped, `coarse-sourcemap-composition-issue-6399` bundles the on-disk comment-only `main.js` into an empty chunk whose `map` is `null`, so `new TraceMap(null)` throws `Cannot read properties of null (reading '_decodedMemo')`. In `explicit-unmapped-boundary`, the transform never injects `injected()`, so `code.indexOf('injected()')` returns -1 and the assertion fails.

This PR drops the leading slash so the checks become `id.endsWith('main.js')`, which is the pattern every other fixture in the repo already uses and works with both path separators. No production code is touched.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: the output sourcemap has less mappings than rollup when the plugin returns a line-only sourcemap

3 participants