Conversation
|
Updated 7:05 AM PT - Aug 14th, 2026
❌ @robobun, your commit 1e6cc67 has some failures in 🧪 To try this PR locally: bunx bun-pr 38454That installs a local version of the PR into your bun-38454 --bun |
|
Status: ready for review at fab0ef1 (rebased on current main); three LGTM bot reviews, no open threads. CI: every lane that has run is green on both builds of this PR (95875 for the previous head, 96288 for this one: 177 of 179 jobs passed, 0 failed). The two remaining jobs in each build are the Reproduced by making the checks real and running the existing users: |
|
Warning Review limit reached
Next review available in: 34 seconds Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
There was a problem hiding this comment.
LGTM — test-harness-only fix that turns a no-op expect(boolean) into a real assertion, with a self-checking regression test. The inline nit about the adjacent sourcesContent loop is pre-existing and non-blocking.
Extended reasoning...
Overview
This PR touches only test infrastructure: test/bundler/expectBundled.ts (the snapshotSourceMap.mappings checker and its helper parseSourceMapStrGenerated) and a new test/bundler/itBundled-snapshotSourceMap.test.ts. No src/ changes. The old check ended in expect(pos.line === dest.line) with no matcher, so the source-map's actual generated position was never asserted; the fix formats generatedPositionFor's answer as line:col:text (or "unmapped") and .toBe()s it against the snapshot entry, with a labelled failure message.
Security risks
None. Changes are confined to the test harness and a new test file; no runtime, network, filesystem-outside-tempdir, or user-facing code paths are touched.
Level of scrutiny
Low-to-moderate. It's a small, mechanical harness correction whose blast radius is the three existing snapshotSourceMap users. The author verified bundler_npm.test.ts (the only mappings user) still passes with 6 more real assertions, and bundler_edgecase.test.ts -t SourceMap (the mappingsExactMatch users, unaffected) still passes. The simplified parseSourceMapStrGenerated keeps the same split.length != 3 guard, so no previously-accepted entry format is now rejected.
Other factors
- The new test is well-constructed per repo rules: spawns a child
bun teston itself with an env flag to register must-fail cases, drains stdout/stderr/exited concurrently, spreadsbunEnvand clearsBUN_BUNDLER_TEST_FILTER, asserts each failure's exact label/Expected/Received plus0 pass / 3 fail, andskipIf(isWindows)with a comment naming #34552. The debug-build timeout is commented. - Checked that
generated_lines[pos.line - 1] ?? ""and the bounded.slice()handle out-of-range positions without throwing, so the assertion always produces a diffable string rather than a TypeError. - The one finding is a nit: a sibling dead loop (
i < parsed.sources) four lines above, pre-existing since #11344. Fixing it also requires correctingsourceContent→sourcesContentand the path base, then revalidating ReactSSR — reasonable as a follow-up, not a blocker for this strict improvement.
There was a problem hiding this comment.
LGTM — thanks for also fixing the sourcesContent loop and adding the StaleSourcesContent case to prove it runs.
What was reviewed:
- The
mappingsassertion rewrite:generatedPositionForresult is now formatted asline:col:textand.toBe'd against the entry, with"unmapped"for null — covers the position, the text, and the previously-silent unmapped case in one comparison. - The
sourcesContentloop repair (bound, field name,path.dirnamebase) matches what I flagged; theruntimeFilesoverwrite inStaleSourcesContentis a neat way to make it observably fail. - Existing
snapshotSourceMapusers (npm/ReactSSR, twobundler_edgecasemappingsExactMatchcases) — the now-live loop reads the same on-disk files the bundler read, so verbatim match is expected; CI on 1e6cc67 covers it. parseSourceMapStrGenerated: thesplit.length != 3guard was already there, so returningsplit[2]is equivalent to the oldmatch.join(":").
Extended reasoning...
Overview
Test-harness-only change under test/bundler/. Two files: expectBundled.ts (repairs two vacuous assertions in the snapshotSourceMap block — the mappings position check and the sourcesContent loop) and a new itBundled-snapshotSourceMap.test.ts that self-verifies the harness by spawning a child that must fail four ways (wrong line, wrong text, unmapped position, stale sourcesContent). No production code (src/) is touched.
Prior feedback addressed
My earlier inline comment flagged the sibling for (let i = 0; i < parsed.sources; i++) loop as another never-runs assertion of the same class. Commit 1e6cc677 fixes all three defects I named (.length bound, sourcesContent field name, path.dirname base for resolving the source path) and adds a labelled expect plus a StaleSourcesContent rejected case that proves the loop now executes and can fail. That fully closes the feedback.
Security risks
None. Test infrastructure only; no runtime, network, auth, or crypto surface.
Level of scrutiny
Low-to-medium. The change strictly tightens a test harness — worst case it turns a previously-passing test red, which CI catches immediately and which would be a real finding about source-map fidelity rather than a defect in this PR. I checked the three pre-existing snapshotSourceMap users: npm/ReactSSR and the two bundler_edgecase mappingsExactMatch cases all set files, so the now-live sourcesContent comparison runs for them too; since it compares the map's embedded content against the exact on-disk file the bundler read, a mismatch would indicate an actual bundler bug.
Other factors
parseSourceMapStrGeneratedsimplification is behaviour-preserving: the pre-existingsplit.length != 3guard means...matchwas always[split[2]], somatch.join(":")≡split[2].- The spawn test drains stdout/stderr/exited concurrently, spreads
bunEnv, deletesBUN_BUNDLER_TEST_FILTERso an ambient filter can't hide the child's cases, asserts(fail)for each name plus0 pass/4 fail, and assertsexitCodelast — all per harness conventions. - The Windows
skipIfis justified with a concrete cause (thetest/bundler/stack-path check vs backslash paths) and a tracked PR (#34552) that removes the need for it. - The
isDebug ? 60_000 : undefinedper-test timeout is scoped to the one spawn test, not a file-wide default.
…ings The mappings checker ended with expect(pos.line === dest.line) and expect(pos.column === dest.column), which assert nothing, so the only thing a mappings entry verified was that its expected text exists at the expected position in the generated file. What the source map actually maps the source position to was never compared. Compare what the map says, formatted as the same "line:col:text" string the snapshot uses, against the entry. A source position the map does not cover at all now fails too, instead of passing silently. The six entries in bundler_npm.test.ts hold under the real assertion.
Same class of dead check four lines above the mappings loop: the bound compared i against the sources array itself, so the body never ran, and had it run it read sourceContent instead of sourcesContent and resolved sources against the .map file instead of its directory. All three snapshotSourceMap users round-trip their sources verbatim with the loop live. The harness test gets a case that rewrites a source after bundling and checks the mismatch is reported.
… reject cases in-process fmtLoc read every field except generatedLine from the mapping being visited instead of from its argument, and generatedLine is what the two mappings were looked up by, so the two strings were always equal and the "Duplicate mapping" check (same commit as the other two) could not fire. No existing external source map trips it once it works. The harness test now calls the exported expectBundled() directly and checks each rejected case's error in-process instead of spawning a child bun test and grepping its reporter output: each case takes a fraction of a second, pins its own message, and no longer needs a timeout. It gains a case that rewrites the emitted map to put two source positions on one generated position.
1e6cc67 to
fab0ef1
Compare
There was a problem hiding this comment.
LGTM — test-harness-only fix that turns three vacuous snapshotSourceMap checks into real assertions.
What was reviewed:
- Verified the new
mappingspath formatsgeneratedPositionFor's answer asline:col:textandtoBe's it against the entry, and that the now-livesourcesContentloop resolves against the map's directory and reads the correct field — the earlier note on this is addressed. - Checked the
fmtLocclosure fix (was readingm.*instead ofloc.*) and that theDuplicateMappingcase's,AACAappendix produces two segments at one generated column to exercise it. - Confirmed
parseSourceMapStrGenerated'ssplit.length != 3guard was already present, so tightening from...matchtotextdrops no accepted inputs; only callers are in this file. - The rejects suite now calls the newly-exported
expectBundledin-process (superseding the spawn approach the PR body still describes) and asserts on the caught error message;ignoreFilterkeeps an ambientBUN_BUNDLER_TEST_FILTERfrom turning them into no-ops.
Extended reasoning...
Overview
Two files under test/bundler/. In expectBundled.ts: (1) the snapshotSourceMap.mappings check replaces expect(pos.line === dest.line) no-ops with a single labelled expect(actual).toBe(generated_str) that compares the map's actual generated position and the text at that position; (2) the sourcesContent loop's bound is fixed from i < parsed.sources (array) to .length, the field name from sourceContent to sourcesContent, and the path base from the .map file to its directory; (3) the duplicate-mapping formatter's closure bug (m.* instead of loc.*) is fixed so the two sides actually differ; (4) expectBundled is exported and parseSourceMapStrGenerated is simplified to a validator that returns the text part. A new itBundled-snapshotSourceMap.test.ts has one passing bundle plus five in-process reject cases (wrong line, wrong text, unmapped, stale sourcesContent via runtimeFiles, duplicate mapping via onAfterBundle) that assert on the caught error message.
Security risks
None. Test-harness code only; no production/runtime code touched, no external input handled.
Level of scrutiny
Low-to-medium. This is test infrastructure with three existing consumers (bundler_npm.test.ts ReactSSR and two bundler_edgecase.test.ts cases), all of which the PR body reports still pass with more expect() calls. The main risk — that making the assertions real breaks an existing user — was checked by the author and is easy to verify in CI. I traced that the two bundler_edgecase users only set mappingsExactMatch (unchanged path) plus files, so the newly-live loop adds three sourcesContent reads there; the npm/ReactSSR user exercises both fixed paths.
Other factors
- My prior inline comment about the sibling
sourcesContentloop was fully addressed and is marked resolved. - The
split.length != 3guard inparseSourceMapStrGeneratedalready existed, so switching from...match/join(':')to a plaintextdestructure cannot reject anything previously accepted. - The reject cases hard-code exact generated positions (e.g.
8:24 -> 3:24); the file-top comment documents the expected 8-line output so a future bundler-output change produces a readable diff rather than a mystery failure. - The PR description still describes a spawn-based child-process test; commit fab0ef1 moved to in-process
expectBundledcalls (hence the new export). Description staleness only, code is coherent. - Windows: the reject block is
skipIf(isWindows)becauseexpectBundled'stest/bundler/stack check never matches backslash paths (tracked in #34552); the passingitBundledcase is silently dropped there for the same pre-existing reason, which the test comments.
Problem
Three checks in the external source map validation block of
test/bundler/expectBundled.ts(theSourceMapConsumer.withcallback, all three added together in #11344) cannot fail:snapshotSourceMap[...].mappingsends withexpect(pos.line === dest.line); expect(pos.column === dest.column);(lines 1691-1692 on main).expect(boolean)with no matcher asserts nothing, sopos, the position the map actually produces for the entry, is never compared with anything. What an entry did verify is that its expected text exists at its expectedline:colof the generated file, which only reads the generated file: a map that sends every token to the wrong place passes as long as the hard-coded position contains the quoted text, and a source position the map does not cover at all (generatedPositionForreturningnull) passes too.sourcesContentloop (lines 1669-1674) has the boundi < parsed.sources, a number compared with an array, so it never iterates. Had it iterated it would have readparsed.sourceContent(the field issourcesContent) and resolved each source against the.mapfile path instead of the map's directory.snapshotSourceMapusers. ItsfmtLocreads every field exceptgeneratedLinefrom the mapping being visited (m) instead of from its argument, andgeneratedLineis part of the key the two mappings were matched on, so the two strings are always equal and theDuplicate mapping in source-mapthrow is unreachable.bundler_npm.test.ts(npm/ReactSSR) is the onlymappingsuser; it and two tests inbundler_edgecase.test.tssetsnapshotSourceMap; every external-map test with an outdir goes through the duplicate check.mappingsExactMatchis unaffected. The remaining dead check in this file, the never-populatedtestsRanduplicate-id set, is a different check and is fixed in test/bundler: make the itBundled duplicate-id check work and fix the 26 ids it finds #38471, which does not overlap with this diff.Fix
mappings: format what the map says for the entry's source position in the snapshot's ownline:col:textshape (text sliced from the generated file at that position,"unmapped"when the map has no position for it) andtoBeit against the entry. One string comparison covers position and text: equal strings mean the map's position is the expected one and the generated file has the expected text there, which is what the old text check established once the position agrees, so nothing that passed for the right reason changes.parseSourceMapStrGeneratednow only validates the entry's format and returns its text. The assertion is labelled with the map file and entry, so a failure readsExpected: "8:0:console"/Received: "7:0:console"and the received value can be pasted back into the test; this also replaces the old text-mismatch path, which asserted and then threw a secondNot matchederror.sourcesContent: iteratesources.length, readsourcesContent, resolve against the map's directory, label the assertion with the map file and source.fmtLocformats its argument. Nothing else changes, so a map is rejected exactly when one generated position carries two different source positions, which is what the check's comment says it is for.expectBundledis exported again (it was exported until bundler tests, testing plugins #2740;expectBundled.mdstill documents calling it directly) so the test below can call it without registering anything.bundler_npm.test.tsgoes from 179563 to 179575expect()calls (6 mappings entries, 6 sources) and passes;bundler_edgecase.test.ts(whole file),bundler_comments.test.ts,esbuild/loader.test.tsandesbuild/default.test.ts -t SourceMappass with the duplicate check live, so no current output has a duplicate generated position. The odd-lookingnpm/ReactSSRentries are fine:atandorin"1:5623:at"/"23:4082:or++"are the minified names, and'<html>' -> "100:19062:void"is the last of the three generated ranges that position maps to, which is whatgeneratedPositionForreturns for a multiply-mapped position, as before this change.test/bundler/itBundled-snapshotSourceMap.test.ts. OneitBundledcase with correctmappingson a two-file bundle (this also runs the livesourcesContentloop on both sources), plus five cases that callexpectBundled()directly and pin how the rejection starts: a position whose text is present but whose line the map disagrees with, a text mismatch, an unmapped position, a source rewritten after bundling viaruntimeFilessosourcesContentno longer matches disk, and a map rewritten inonAfterBundleto put two source positions on one generated position. Each case takes 0.2 to 0.6 s on a debug build. Against main'sexpectBundled.ts(plus theexport), four of the five are accepted (Received: "<expectBundled() passed>") and the text mismatch fails only on the old unlabelled message; with this change all six pass.test/, so a fail-before check that only stashessrc/cannot observe it; the before/after above was run by swapping in main'sexpectBundled.tsunder the debug build.expectBundled()cases aredescribe.skipIf(isWindows)because itstest/bundler/stack check never matches backslash paths there, which is also why theitBundledcase is silently not registered on Windows today (test/bundler: stop silently dropping every itBundled test on Windows #34552 fixes the check; the skip can go when it lands). Verified on Windows with the earlier spawn-based revision of this file that the harness registers nothing there, and that with test/bundler: stop silently dropping every itBundled test on Windows #34552's one-line fix applied the positive case passes un-skipped.Background
snapshotSourceMapis anitBundledoption for source maps too large to snapshot whole.filespins the map'ssources(and, through the loop fixed here, theirsourcesContent);mappingsis a list of[source position, generated position]samples, where the source side is"file:line:'token'"and the generated side is"line:col:text". Independently of that option, every external map produced by a test is decoded and checked for a generated position mapped to two different source positions.SourceMapConsumer.generatedPositionFor(thesource-mappackage) answers "where did this source position end up in the output"; it returns{ line: null, column: null }when the map has nothing at or before that position in that source.itBundled(id, opts)registers a test whose body isexpectBundled(id, opts);expectBundleditself only bundles and runs the checks, returning a promise that rejects on the first failed check.runtimeFilesare written, andonAfterBundleruns, after bundling and before these checks, which is how the test makes a source file or the map disagree with the bundle."AACA"is one VLQ segment: generated column +0, same source, source line +1, source column +0. Appended to the last mapped line it duplicates that line's last generated position with a different source line.expect(value, message)is bun:test's labelled form: the label replaces the matcher headline in the error message and Expected/Received are still appended (colored when attached to a terminal, hence theBun.stripANSIin the test).Error messages the test pins (debug build)
Earlier revisions of this PR
mappingsassertion; the test spawned a childbun testwith the must-fail cases and grepped its reporter output, which took about 4 s on a debug build and needed a debug-only timeout.sourcesContentloop after review pointed out it is the same kind of dead check in the same block.expectBundled()calls, which removed the child process, the env-var switch, the timeout and the dependence on reporter output.