Skip to content

Commit 7daf4b8

Browse files
veksenclaude
andcommitted
feat(drizzle): normalize source-map-resolved file paths
When compiled JS is relocated (e.g., postbuild copies dist/ to a deployment directory), source map relative paths resolve to wrong absolute paths. The file tag would contain bogus paths like /.amplify-hosting/compute/src/routes/admin.ts instead of the real project path. This extracts the src/-relative portion from the stack trace path and reconstructs it using the real project root found via tsconfig.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 35dbda9 commit 7daf4b8

3 files changed

Lines changed: 80 additions & 2 deletions

File tree

nodejs/sqlcommenter-nodejs/packages/sqlcommenter-drizzle/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { alreadyHasComment, serializeTags } from "./sqlcommenter.js";
22
import { als } from "./als.js";
33
import { pushW3CTraceContext } from "./tracing.js";
4+
import { resolveFilePath } from "./path.js";
45

56
const LIBRARY_NAME = "sqlcommenter-drizzle";
67

@@ -54,7 +55,7 @@ export function traceCaller(): string | undefined {
5455
}
5556
const match = methodCaller.match(filepathRegex);
5657
if (match) {
57-
return match[1];
58+
return resolveFilePath(match[1]);
5859
}
5960
}
6061

nodejs/sqlcommenter-nodejs/packages/sqlcommenter-drizzle/src/path.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,35 @@ export function findProjectRoot(): string {
2828
return projectRoot;
2929
}
3030

31+
/**
32+
* Resolves a file path from a stack trace to a correct absolute path.
33+
*
34+
* When compiled JS is relocated (e.g., postbuild copies `dist/` to a deployment directory),
35+
* source-map-resolved paths become incorrect because the relative `sources` entries in
36+
* `.map` files resolve against the new location instead of the original project.
37+
*
38+
* This extracts the `src/`-relative portion and reconstructs the path using the real
39+
* project root.
40+
*
41+
* @param raw - A stack trace entry like "/wrong/path/src/routes/admin.ts:12:15"
42+
* @returns The resolved path like "/project/root/src/routes/admin.ts:12:15"
43+
*/
44+
export function resolveFilePath(raw: string): string {
45+
// Split off :line:column suffix
46+
const match = raw.match(/^(.*?):(\d+:\d+)$/);
47+
if (!match) {
48+
return raw;
49+
}
50+
const [, filePath, lineCol] = match;
51+
const srcIdx = filePath.indexOf("src/");
52+
if (srcIdx < 0) {
53+
return raw;
54+
}
55+
const projectRoot = findProjectRoot();
56+
const relativePath = filePath.substring(srcIdx);
57+
return `${projectRoot}/${relativePath}:${lineCol}`;
58+
}
59+
3160
/** @internal Exposed for testing only */
3261
export function _resetProjectRootCache() {
3362
cachedProjectRoot = undefined;

nodejs/sqlcommenter-nodejs/packages/sqlcommenter-drizzle/test/path.spec.ts

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { test } from "node:test";
22
import assert from "node:assert";
33
import { existsSync } from "node:fs";
44
import { join } from "node:path";
5-
import { findProjectRoot, _resetProjectRootCache } from "../src/path.js";
5+
import {
6+
findProjectRoot,
7+
resolveFilePath,
8+
_resetProjectRootCache,
9+
} from "../src/path.js";
610

711
test("findProjectRoot", async (t) => {
812
t.afterEach(() => {
@@ -23,3 +27,47 @@ test("findProjectRoot", async (t) => {
2327
assert.strictEqual(first, second);
2428
});
2529
});
30+
31+
test("resolveFilePath", async (t) => {
32+
t.afterEach(() => {
33+
_resetProjectRootCache();
34+
});
35+
36+
await t.test(
37+
"resolves path with src/ to project root",
38+
() => {
39+
const projectRoot = findProjectRoot();
40+
const result = resolveFilePath(
41+
"/wrong/deploy/dir/src/routes/admin.ts:12:15",
42+
);
43+
assert.strictEqual(result, `${projectRoot}/src/routes/admin.ts:12:15`);
44+
},
45+
);
46+
47+
await t.test("leaves path without src/ unchanged", () => {
48+
const result = resolveFilePath("/some/other/path/routes/admin.ts:5:10");
49+
assert.strictEqual(result, "/some/other/path/routes/admin.ts:5:10");
50+
});
51+
52+
await t.test("preserves line:column suffix", () => {
53+
const projectRoot = findProjectRoot();
54+
const result = resolveFilePath("/bad/path/src/index.ts:99:3");
55+
assert.strictEqual(result, `${projectRoot}/src/index.ts:99:3`);
56+
});
57+
58+
await t.test("uses first src/ occurrence", () => {
59+
const projectRoot = findProjectRoot();
60+
const result = resolveFilePath(
61+
"/deploy/src/nested/src/routes/admin.ts:1:1",
62+
);
63+
assert.strictEqual(
64+
result,
65+
`${projectRoot}/src/nested/src/routes/admin.ts:1:1`,
66+
);
67+
});
68+
69+
await t.test("returns raw string if no line:column suffix", () => {
70+
const result = resolveFilePath("/some/path/src/file.ts");
71+
assert.strictEqual(result, "/some/path/src/file.ts");
72+
});
73+
});

0 commit comments

Comments
 (0)