From 77156374a49678b039a9dcbd43be23e7acea946b Mon Sep 17 00:00:00 2001 From: Jean-Philippe Sirois Date: Thu, 26 Feb 2026 19:43:56 +0400 Subject: [PATCH 1/4] feat(mikroorm): add project root detection via tsconfig.json Co-Authored-By: Claude Opus 4.6 --- .../sqlcommenter-mikroorm/src/path.ts | 34 +++++++++++++++++++ .../sqlcommenter-mikroorm/test/path.spec.ts | 28 +++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts create mode 100644 nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts diff --git a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts new file mode 100644 index 00000000..385594e9 --- /dev/null +++ b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts @@ -0,0 +1,34 @@ +import { existsSync } from "node:fs"; +import { dirname, join } from "node:path"; + +let cachedProjectRoot: string | undefined; + +/** + * Finds the project root by walking up from `process.cwd()` looking for `tsconfig.json`. + * + * In deployed environments, `process.cwd()` may not be the project root + * (e.g., `cd .amplify-hosting/compute/default/ && node app.js`). + * Walking up to find `tsconfig.json` — which is never copied to deployment directories — + * gives us the real project root. + * + * The result is cached since the project root doesn't change during a process's lifetime. + */ +export function findProjectRoot(): string { + if (cachedProjectRoot !== undefined) { + return cachedProjectRoot; + } + let projectRoot = process.cwd(); + for (let d = projectRoot; d !== dirname(d); d = dirname(d)) { + if (existsSync(join(d, "tsconfig.json"))) { + projectRoot = d; + break; + } + } + cachedProjectRoot = projectRoot; + return projectRoot; +} + +/** @internal Exposed for testing only */ +export function _resetProjectRootCache() { + cachedProjectRoot = undefined; +} diff --git a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts new file mode 100644 index 00000000..fb496202 --- /dev/null +++ b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts @@ -0,0 +1,28 @@ +import { test } from "node:test"; +import assert from "node:assert"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { + findProjectRoot, + _resetProjectRootCache, +} from "../src/path.js"; + +test("findProjectRoot", async (t) => { + t.afterEach(() => { + _resetProjectRootCache(); + }); + + await t.test("returns a directory containing tsconfig.json", () => { + const root = findProjectRoot(); + assert.ok( + existsSync(join(root, "tsconfig.json")), + `Expected ${root} to contain tsconfig.json`, + ); + }); + + await t.test("caches the result across calls", () => { + const first = findProjectRoot(); + const second = findProjectRoot(); + assert.strictEqual(first, second); + }); +}); From 6c162b4b1fbc8c9a7f000abacf8bb029b069617d Mon Sep 17 00:00:00 2001 From: Jean-Philippe Sirois Date: Thu, 26 Feb 2026 19:44:55 +0400 Subject: [PATCH 2/4] feat(mikroorm): normalize source-map-resolved file paths Co-Authored-By: Claude Opus 4.6 --- .../sqlcommenter-mikroorm/src/index.ts | 3 +- .../sqlcommenter-mikroorm/src/path.ts | 29 +++++++++++++ .../sqlcommenter-mikroorm/test/path.spec.ts | 42 +++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/index.ts b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/index.ts index 2ec36b78..953dc07e 100644 --- a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/index.ts +++ b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/index.ts @@ -1,6 +1,7 @@ import { alreadyHasTrailingComment, serializeTags, type Tag } from "./sqlcommenter.js"; import { als } from "./als.js"; import { pushW3CTraceContext } from "./tracing.js"; +import { resolveFilePath } from "./path.js"; const LIBRARY_NAME = "sqlcommenter-mikroorm"; @@ -42,7 +43,7 @@ export function traceCaller(): string | undefined { } const match = methodCaller.match(filepathRegex); if (match) { - return match[1]; + return resolveFilePath(match[1]); } } diff --git a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts index 385594e9..2a2c2460 100644 --- a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts +++ b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts @@ -28,6 +28,35 @@ export function findProjectRoot(): string { return projectRoot; } +/** + * Resolves a file path from a stack trace to a correct absolute path. + * + * When compiled JS is relocated (e.g., postbuild copies `dist/` to a deployment directory), + * source-map-resolved paths become incorrect because the relative `sources` entries in + * `.map` files resolve against the new location instead of the original project. + * + * This extracts the `src/`-relative portion and reconstructs the path using the real + * project root. + * + * @param raw - A stack trace entry like "/wrong/path/src/routes/admin.ts:12:15" + * @returns The resolved path like "/project/root/src/routes/admin.ts:12:15" + */ +export function resolveFilePath(raw: string): string { + // Split off :line:column suffix + const match = raw.match(/^(.*?):(\d+:\d+)$/); + if (!match) { + return raw; + } + const [, filePath, lineCol] = match; + const srcIdx = filePath.indexOf("src/"); + if (srcIdx < 0) { + return raw; + } + const projectRoot = findProjectRoot(); + const relativePath = filePath.substring(srcIdx); + return `${projectRoot}/${relativePath}:${lineCol}`; +} + /** @internal Exposed for testing only */ export function _resetProjectRootCache() { cachedProjectRoot = undefined; diff --git a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts index fb496202..2318584a 100644 --- a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts +++ b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts @@ -4,6 +4,7 @@ import { existsSync } from "node:fs"; import { join } from "node:path"; import { findProjectRoot, + resolveFilePath, _resetProjectRootCache, } from "../src/path.js"; @@ -26,3 +27,44 @@ test("findProjectRoot", async (t) => { assert.strictEqual(first, second); }); }); + +test("resolveFilePath", async (t) => { + t.afterEach(() => { + _resetProjectRootCache(); + }); + + await t.test("resolves path with src/ to project root", () => { + const projectRoot = findProjectRoot(); + const result = resolveFilePath( + "/wrong/deploy/dir/src/routes/admin.ts:12:15", + ); + assert.strictEqual(result, `${projectRoot}/src/routes/admin.ts:12:15`); + }); + + await t.test("leaves path without src/ unchanged", () => { + const result = resolveFilePath("/some/other/path/routes/admin.ts:5:10"); + assert.strictEqual(result, "/some/other/path/routes/admin.ts:5:10"); + }); + + await t.test("preserves line:column suffix", () => { + const projectRoot = findProjectRoot(); + const result = resolveFilePath("/bad/path/src/index.ts:99:3"); + assert.strictEqual(result, `${projectRoot}/src/index.ts:99:3`); + }); + + await t.test("uses first src/ occurrence", () => { + const projectRoot = findProjectRoot(); + const result = resolveFilePath( + "/deploy/src/nested/src/routes/admin.ts:1:1", + ); + assert.strictEqual( + result, + `${projectRoot}/src/nested/src/routes/admin.ts:1:1`, + ); + }); + + await t.test("returns raw string if no line:column suffix", () => { + const result = resolveFilePath("/some/path/src/file.ts"); + assert.strictEqual(result, "/some/path/src/file.ts"); + }); +}); From 474e4628ca03f92f9f94253d83e848c31f30f714 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Sirois Date: Thu, 26 Feb 2026 19:45:48 +0400 Subject: [PATCH 3/4] feat(mikroorm): add WSL path support for file tag Co-Authored-By: Claude Opus 4.6 --- .../sqlcommenter-mikroorm/src/path.ts | 19 +++++++- .../sqlcommenter-mikroorm/test/path.spec.ts | 48 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts index 2a2c2460..811866bd 100644 --- a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts +++ b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/src/path.ts @@ -54,7 +54,24 @@ export function resolveFilePath(raw: string): string { } const projectRoot = findProjectRoot(); const relativePath = filePath.substring(srcIdx); - return `${projectRoot}/${relativePath}:${lineCol}`; + const resolved = `${projectRoot}/${relativePath}`; + return `${applyWslPrefix(resolved)}:${lineCol}`; +} + +/** + * Prefixes an absolute path with the WSL network path when running inside WSL. + * + * Inside WSL, absolute paths like `/home/user/project/...` can't be resolved + * from Windows-side tooling (e.g., clickable links in dashboards or VS Code). + * The `WSL_DISTRO_NAME` env var is always set inside WSL, and the path format + * `//wsl.localhost//...` makes paths accessible from Windows. + */ +export function applyWslPrefix(filePath: string): string { + const distro = process.env.WSL_DISTRO_NAME; + if (distro) { + return `//wsl.localhost/${distro}${filePath}`; + } + return filePath; } /** @internal Exposed for testing only */ diff --git a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts index 2318584a..1e09cf4d 100644 --- a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts +++ b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/test/path.spec.ts @@ -5,6 +5,7 @@ import { join } from "node:path"; import { findProjectRoot, resolveFilePath, + applyWslPrefix, _resetProjectRootCache, } from "../src/path.js"; @@ -68,3 +69,50 @@ test("resolveFilePath", async (t) => { assert.strictEqual(result, "/some/path/src/file.ts"); }); }); + +test("applyWslPrefix", async (t) => { + const originalWslDistroName = process.env.WSL_DISTRO_NAME; + + t.afterEach(() => { + if (originalWslDistroName === undefined) { + delete process.env.WSL_DISTRO_NAME; + } else { + process.env.WSL_DISTRO_NAME = originalWslDistroName; + } + }); + + await t.test("prefixes path when WSL_DISTRO_NAME is set", () => { + process.env.WSL_DISTRO_NAME = "Ubuntu-22.04"; + const path = "/home/user/project/src/file.ts:1:1"; + const result = applyWslPrefix(path); + assert.strictEqual(result, "//wsl.localhost/Ubuntu-22.04/home/user/project/src/file.ts:1:1"); + }); + + await t.test("returns path unchanged when WSL_DISTRO_NAME is not set", () => { + delete process.env.WSL_DISTRO_NAME; + const path = "/home/user/project/src/file.ts:1:1"; + const result = applyWslPrefix(path); + assert.strictEqual(result, path); + }); +}); + +test("resolveFilePath with WSL", async (t) => { + const originalWslDistroName = process.env.WSL_DISTRO_NAME; + + t.afterEach(() => { + _resetProjectRootCache(); + if (originalWslDistroName === undefined) { + delete process.env.WSL_DISTRO_NAME; + } else { + process.env.WSL_DISTRO_NAME = originalWslDistroName; + } + }); + + await t.test("applies WSL prefix to resolved src/ paths", () => { + process.env.WSL_DISTRO_NAME = "Ubuntu-22.04"; + const projectRoot = findProjectRoot(); + const rawPath = "/wrong/deploy/dir/src/routes/admin.ts:12:15"; + const result = resolveFilePath(rawPath); + assert.strictEqual(result, `//wsl.localhost/Ubuntu-22.04${projectRoot}/src/routes/admin.ts:12:15`); + }); +}); From ca488ea5e8ded8430e966c4ba04722ff1ce90c54 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Sirois Date: Thu, 26 Feb 2026 19:51:19 +0400 Subject: [PATCH 4/4] chore(mikroorm): bump version to 0.1.0 Co-Authored-By: Claude Opus 4.6 --- .../packages/sqlcommenter-mikroorm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/package.json b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/package.json index 76cfbb69..c3534020 100644 --- a/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/package.json +++ b/nodejs/sqlcommenter-nodejs/packages/sqlcommenter-mikroorm/package.json @@ -1,6 +1,6 @@ { "name": "@query-doctor/sqlcommenter-mikroorm", - "version": "0.0.2", + "version": "0.1.0", "description": "SQLCommenter patch for MikroORM", "main": "dist/cjs/index.js", "type": "module",