Skip to content

Commit cf55e45

Browse files
committed
fix(response) orphaned .wasm.map diagnostic misclassification
- Count `.wasm.map` files directly in `addWasmDiscoveryCounts` instead of only when a companion `.wasm` exists - Widen the diagnostic walk to include `.map` so orphan wasm maps leave the JS `mapFiles` tally - Add a `buildEmptyDiscoveryError` branch for wasm maps without modules, explaining the missing `.wasm` requirement - Cover orphan and JS-map tally behavior in `wasm.test.ts`
1 parent baaefee commit cf55e45

3 files changed

Lines changed: 72 additions & 6 deletions

File tree

‎packages/cli/src/lib/sourcemap/inject.ts‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,17 @@ export function buildEmptyDiscoveryError(
827827
"directory"
828828
);
829829
}
830+
// Wasm maps with no module beside them: the debug ID comes from the
831+
// module's `build_id`, so the map alone is not uploadable.
832+
if (jsFiles === 0 && mapFiles === 0 && wasmMaps > 0 && wasmFiles === 0) {
833+
return new ValidationError(
834+
`Found ${wasmMaps} .wasm.map file(s) in '${dir}' but no .wasm ` +
835+
"modules. A wasm sourcemap is matched to its module's build_id, so " +
836+
"the .wasm file must sit beside it — point the command at your " +
837+
"build output. Pass --allow-empty to suppress.",
838+
"directory"
839+
);
840+
}
830841
if (jsFiles === 0 && mapFiles === 0) {
831842
return new ValidationError(
832843
`Directory '${dir}' contains no JS or sourcemap files. ` +

‎packages/cli/src/lib/sourcemap/wasm.ts‎

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ const log = logger.withTag("sourcemap.wasm");
4040
*/
4141
const WASM_EXTENSIONS: ReadonlySet<string> = new Set([".wasm"]);
4242

43+
/**
44+
* Extensions scanned when counting artifacts for the zero-pairs diagnostic.
45+
* Covers `.map` so an orphaned `app.wasm.map` — a map whose module is not in
46+
* the directory — is attributed to wasm instead of being left in the JS tally.
47+
*/
48+
const WASM_DIAGNOSTIC_EXTENSIONS: ReadonlySet<string> = new Set([
49+
".wasm",
50+
".map",
51+
]);
52+
4353
/** A WebAssembly module and the sourcemap sitting next to it. */
4454
export type WasmPair = {
4555
/** Absolute path to the `.wasm` module. */
@@ -178,7 +188,9 @@ export async function discoverWasmPairs(
178188
* Only called on the zero-pairs error path, so a second walk costs nothing
179189
* that matters. `.wasm.map` files are moved out of the JS `mapFiles` tally —
180190
* the JS walk counts every `.map` — so the JS branches of
181-
* `buildEmptyDiscoveryError` keep describing JS alone.
191+
* `buildEmptyDiscoveryError` keep describing JS alone. Maps are counted
192+
* independently of modules, so a map left behind by a missing module is still
193+
* recognised as wasm.
182194
*
183195
* @param dir - Directory to scan
184196
* @param js - The diagnostic from `diagnoseEmptyDiscovery`
@@ -191,10 +203,17 @@ export async function addWasmDiscoveryCounts(
191203
const absDir = resolvePath(dir);
192204
let wasmFiles = 0;
193205
let wasmMaps = 0;
194-
for await (const wasmPath of walkWasmModules(absDir)) {
195-
wasmFiles += 1;
196-
if (await hasCompanionMap(`${wasmPath}.map`)) {
206+
for await (const path of walkWasmModules(
207+
absDir,
208+
undefined,
209+
WASM_DIAGNOSTIC_EXTENSIONS
210+
)) {
211+
// The widened extension set also yields JS `.map` files; those stay in the
212+
// JS tally.
213+
if (path.endsWith(".wasm.map")) {
197214
wasmMaps += 1;
215+
} else if (path.endsWith(".wasm")) {
216+
wasmFiles += 1;
198217
}
199218
}
200219
return {
@@ -211,14 +230,18 @@ export async function addWasmDiscoveryCounts(
211230
* Uses the same traversal settings as JS discovery — build outputs are usually
212231
* gitignored, `dist`/`build` must not be pruned, and a wasm module easily
213232
* exceeds any size cap.
233+
*
234+
* @param extensions - Widened only by the diagnostic walk, which also needs
235+
* `.map` files; callers must then filter the extra extensions themselves.
214236
*/
215237
async function* walkWasmModules(
216238
absDir: string,
217-
ignoreMatcher?: ReturnType<typeof ignore>
239+
ignoreMatcher?: ReturnType<typeof ignore>,
240+
extensions: ReadonlySet<string> = WASM_EXTENSIONS
218241
): AsyncGenerator<string> {
219242
for await (const entry of walkFiles({
220243
cwd: absDir,
221-
extensions: WASM_EXTENSIONS,
244+
extensions,
222245
alwaysSkipDirs: SOURCEMAP_SKIP_DIRS,
223246
hidden: false,
224247
respectGitignore: false,

‎packages/cli/test/lib/sourcemap/wasm.test.ts‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { tmpdir } from "node:os";
1111
import { join } from "node:path";
1212
import ignore from "ignore";
1313
import { beforeEach, describe, expect, test } from "vitest";
14+
import { buildEmptyDiscoveryError } from "../../../src/lib/sourcemap/inject.js";
1415
import {
1516
addWasmDiscoveryCounts,
1617
discoverWasmPairs,
@@ -255,4 +256,35 @@ describe("addWasmDiscoveryCounts", () => {
255256
expect(diag.wasmFiles).toBe(1);
256257
expect(diag.wasmMaps).toBe(0);
257258
});
259+
260+
test("attributes a map with no module to wasm, not JS", async () => {
261+
await writeMap("app.wasm.map");
262+
263+
const diag = await addWasmDiscoveryCounts(dir, {
264+
jsFiles: 0,
265+
mapFiles: 1,
266+
});
267+
268+
expect(diag).toEqual({
269+
jsFiles: 0,
270+
mapFiles: 0,
271+
wasmFiles: 0,
272+
wasmMaps: 1,
273+
});
274+
expect(buildEmptyDiscoveryError(dir, diag).message).toContain(
275+
"1 .wasm.map file(s)"
276+
);
277+
});
278+
279+
test("leaves JS maps in the JS tally", async () => {
280+
await writeMap("app.js.map");
281+
282+
const diag = await addWasmDiscoveryCounts(dir, {
283+
jsFiles: 0,
284+
mapFiles: 1,
285+
});
286+
287+
expect(diag.mapFiles).toBe(1);
288+
expect(diag.wasmMaps).toBe(0);
289+
});
258290
});

0 commit comments

Comments
 (0)