1import * as Bundle from "@/Bundle/Bundle";
2import * as NodeServices from "@effect/platform-node/NodeServices";
3import { expect, layer } from "alchemy-test";
4import * as Effect from "effect/Effect";
5import * as FileSystem from "effect/FileSystem";
6import * as Path from "effect/Path";
7
8/**
9 * Rolldown's default `resolve.conditionNames` are import-kind specific
10 * (`import` for `import` statements, `require` for `require()` calls). An
11 * explicit list is applied as one set to BOTH kinds, so listing `"import"`
12 * makes every `require()` also match a package's `"import"` export — and
13 * `exports` maps resolve in the PACKAGE's key order. `pg-pool` lists
14 * `import` before `require`, so `pg`'s `require("pg-pool")` received the
15 * ESM namespace and died with `TypeError: The superclass is not a
16 * constructor`. {@link Bundle.BUN_CONDITION_NAMES} /
17 * {@link Bundle.NODE_CONDITION_NAMES} leave the kind to rolldown.
18 */
19layer(NodeServices.layer)("bundle conditionNames", (it) => {
20 /**
21 * A dual package shaped like `pg-pool`: `import` listed first, each
22 * entry carrying a distinct marker so the bundle shows which one a
23 * given import kind resolved.
24 */
25 const project = Effect.gen(function* () {
26 const fs = yield* FileSystem.FileSystem;
27 const path = yield* Path.Path;
28 const root = yield* fs.makeTempDirectory({ prefix: "alchemy-conditions-" });
29 const pkg = path.join(root, "node_modules", "dual-pkg");
30 yield* fs.makeDirectory(pkg, { recursive: true });
31 yield* fs.writeFileString(
32 path.join(pkg, "package.json"),
33 JSON.stringify({
34 name: "dual-pkg",
35 exports: { ".": { import: "./esm.mjs", require: "./cjs.cjs" } },
36 }),
37 );
38 yield* fs.writeFileString(
39 path.join(pkg, "esm.mjs"),
40 `export const kind = "DUAL_PKG_ESM_ENTRY";\n`,
41 );
42 yield* fs.writeFileString(
43 path.join(pkg, "cjs.cjs"),
44 `module.exports = { kind: "DUAL_PKG_CJS_ENTRY" };\n`,
45 );
46 // A CommonJS consumer (what `pg` is) requiring the dual package…
47 yield* fs.writeFileString(
48 path.join(root, "consumer.cjs"),
49 `module.exports = { viaRequire: require("dual-pkg").kind };\n`,
50 );
51 // …and an ESM entry importing it directly as well.
52 const entry = path.join(root, "entry.mjs");
53 yield* fs.writeFileString(
54 entry,
55 `import { kind as viaImport } from "dual-pkg";\nimport consumer from "./consumer.cjs";\nexport default { viaImport, viaRequire: consumer.viaRequire };\n`,
56 );
57 return { root, entry };
58 });
59
60 const bundleWith = (conditionNames: readonly string[]) =>
61 Effect.gen(function* () {
62 const fs = yield* FileSystem.FileSystem;
63 const { root, entry } = yield* project;
64 try {
65 const result = yield* Bundle.build(
66 {
67 cwd: root,
68 input: entry,
69 platform: "node",
70 resolve: { conditionNames: [...conditionNames] },
71 },
72 { format: "esm" },
73 );
74 return result.files
75 .filter((file) => typeof file.content === "string")
76 .map((file) => file.content as string)
77 .join("\n");
78 } finally {
79 yield* fs.remove(root, { recursive: true }).pipe(Effect.ignore);
80 }
81 });
82
83 it.effect(
84 "BUN_CONDITION_NAMES: require() resolves the CJS export, import the ESM one",
85 () =>
86 Effect.gen(function* () {
87 const code = yield* bundleWith(Bundle.BUN_CONDITION_NAMES);
88 expect(code).toContain("DUAL_PKG_CJS_ENTRY");
89 expect(code).toContain("DUAL_PKG_ESM_ENTRY");
90 }),
91 { tags: ["unit", "local"] },
92 );
93
94 it.effect(
95 "NODE_CONDITION_NAMES: require() resolves the CJS export, import the ESM one",
96 () =>
97 Effect.gen(function* () {
98 const code = yield* bundleWith(Bundle.NODE_CONDITION_NAMES);
99 expect(code).toContain("DUAL_PKG_CJS_ENTRY");
100 expect(code).toContain("DUAL_PKG_ESM_ENTRY");
101 }),
102 { tags: ["unit", "local"] },
103 );
104
105 // The control: the former list, with `"import"` baked in, hands the CJS
106 // consumer's require() the ESM entry — the `pg` crash.
107 it.effect(
108 "a list containing `import` mis-resolves require() to ESM",
109 () =>
110 Effect.gen(function* () {
111 const code = yield* bundleWith(["bun", "import", "module", "default"]);
112 expect(code).not.toContain("DUAL_PKG_CJS_ENTRY");
113 expect(code).toContain("DUAL_PKG_ESM_ENTRY");
114 }),
115 { tags: ["unit", "local"] },
116 );
117});