fix(cli): handle symlinks in isMain() for Node.js

The dnt polyfill's import-meta-ponyfill doesn't resolve symlinks when
comparing process.argv[1] with import.meta.url. When npm creates a
symlink for the `wmill` bin (e.g., /usr/bin/wmill -> .../main.js),
the paths don't match and isMain() incorrectly returns false, causing
the CLI to silently exit without running.

This fix resolves symlinks using fs.realpathSync() before comparison,
ensuring the CLI works correctly when invoked via npm-installed symlinks.

Tested with Node.js 20 and 25.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Ruben Fiszel
2026-01-28 18:16:17 +00:00
parent b1868779a9
commit 1149094cdc

View File

@@ -5,6 +5,13 @@ import {
esMain,
log,
} from "../deps.ts";
// Node.js-specific imports for symlink resolution in isMain()
// These are only used in Node.js, not Deno
// dnt-shim-ignore
import { realpathSync } from "node:fs";
// dnt-shim-ignore
import { fileURLToPath } from "node:url";
import flow from "./commands/flow/flow.ts";
import app from "./commands/app/app.ts";
import script from "./commands/script/script.ts";
@@ -239,8 +246,23 @@ function isMain() {
}
return isMain;
} else {
//@ts-ignore
return esMain.default(import.meta);
// For Node.js, we need to handle symlinks properly.
// The dnt polyfill doesn't resolve symlinks when comparing process.argv[1]
// with import.meta.url, so `wmill` symlink doesn't match the real file path.
// We resolve symlinks manually to get accurate comparison.
try {
const scriptPath = process.argv[1];
if (!scriptPath) return false;
const realScriptPath = realpathSync(scriptPath);
const modulePath = fileURLToPath(import.meta.url);
return realScriptPath === modulePath;
} catch {
// Fallback to esMain if something fails
//@ts-ignore
return esMain.default(import.meta);
}
}
}
if (isMain()) {