1// @effect-diagnostics nodeBuiltinImport:off - entrypoint detection is a Node filesystem boundary.
2import * as NodeFS from "node:fs";
3import * as NodeOS from "node:os";
4import * as NodePath from "node:path";
5import * as NodeURL from "node:url";
6
7import { describe, expect, it } from "vite-plus/test";
8
9import { isEntrypoint } from "./entrypoint.ts";
10import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
11
12const makeTempDir = () => NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-entrypoint-test-"));
13
14describe("isEntrypoint", () => {
15 it("uses the runtime answer when Node provides one", () => {
16 // Node 22.18+ and 24.2+ populate `import.meta.main`; nothing else is consulted.
17 expect(
18 isEntrypoint({
19 moduleUrl: "file:///somewhere/bin.mjs",
20 entryPath: "/elsewhere/other.mjs",
21 runtimeMain: true,
22 }),
23 ).toBe(true);
24 expect(
25 isEntrypoint({
26 moduleUrl: "file:///somewhere/bin.mjs",
27 entryPath: "/somewhere/bin.mjs",
28 runtimeMain: false,
29 }),
30 ).toBe(false);
31 });
32
33 it("matches the entrypoint path when the runtime has no import.meta.main", () => {
34 // Node 22.16, 22.17 and 23.11 are inside `engines.node` but leave it undefined.
35 const dir = makeTempDir();
36 const entry = NodePath.join(dir, "bin.mjs");
37 NodeFS.writeFileSync(entry, "");
38
39 expect(
40 isEntrypoint({
41 moduleUrl: NodeURL.pathToFileURL(entry).href,
42 entryPath: entry,
43 runtimeMain: undefined,
44 }),
45 ).toBe(true);
46 });
47
48 it.skipIf(!symlinksSupported)(
49 "matches through a symlinked entrypoint, as npm and npx install it",
50 () => {
51 const dir = makeTempDir();
52 const real = NodePath.join(dir, "bin.mjs");
53 const link = NodePath.join(dir, "t3");
54 NodeFS.writeFileSync(real, "");
55 NodeFS.symlinkSync(real, link);
56
57 // Node resolves the module URL to the real path, and on macOS the temp
58 // directory itself sits behind a symlink (`/var` -> `/private/var`).
59 expect(
60 isEntrypoint({
61 moduleUrl: NodeURL.pathToFileURL(NodeFS.realpathSync(real)).href,
62 entryPath: link,
63 runtimeMain: undefined,
64 }),
65 ).toBe(true);
66 },
67 );
68
69 it("stays false for an imported module that is not the entrypoint", () => {
70 // This is what keeps `bin.test.ts` from launching the CLI on import.
71 const dir = makeTempDir();
72 const entry = NodePath.join(dir, "bin.mjs");
73 const imported = NodePath.join(dir, "cli.mjs");
74 NodeFS.writeFileSync(entry, "");
75 NodeFS.writeFileSync(imported, "");
76
77 expect(
78 isEntrypoint({
79 moduleUrl: NodeURL.pathToFileURL(imported).href,
80 entryPath: entry,
81 runtimeMain: undefined,
82 }),
83 ).toBe(false);
84 });
85
86 it("stays false when there is no entrypoint argument", () => {
87 expect(
88 isEntrypoint({
89 moduleUrl: "file:///somewhere/bin.mjs",
90 entryPath: undefined,
91 runtimeMain: undefined,
92 }),
93 ).toBe(false);
94 });
95});