aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bun.js/bindings/CommonJSModuleRecord.cpp21
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp16
-rw-r--r--src/js_ast.zig4
-rw-r--r--src/js_parser.zig46
-rw-r--r--src/js_printer.zig34
-rw-r--r--test/cli/run/require-cache-fixture.cjs14
-rw-r--r--test/cli/run/require-cache.test.js2
7 files changed, 91 insertions, 46 deletions
diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp
index e3bf3a0db..a32d722d9 100644
--- a/src/bun.js/bindings/CommonJSModuleRecord.cpp
+++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp
@@ -218,7 +218,7 @@ static Structure* internalCreateCommonJSModuleStructure(
structure = structure->addPropertyTransition(
vm,
structure,
- JSC::Identifier::fromString(vm, "fileName"_s),
+ JSC::Identifier::fromString(vm, "filename"_s),
0,
offset);
@@ -310,10 +310,15 @@ JSC::SourceCode createCommonJSModule(
? JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), source.commonJSExportsLen)
: JSC::constructEmptyObject(globalObject, globalObject->objectPrototype());
- if (!globalObject->requireMap()->has(globalObject, requireMapKey)) {
- globalObject->requireMap()->set(globalObject, requireMapKey, exportsObject);
+ auto index = sourceURL.reverseFind('/', sourceURL.length());
+ JSString* dirname = jsEmptyString(vm);
+ JSString* filename = requireMapKey;
+ if (index != WTF::notFound) {
+ dirname = JSC::jsSubstring(globalObject, requireMapKey, 0, index);
}
+ globalObject->requireMap()->set(globalObject, requireMapKey, exportsObject);
+
JSC::SourceCode inputSource(
JSC::StringSourceProvider::create(sourceCodeString,
JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(sourceURL)),
@@ -344,6 +349,16 @@ JSC::SourceCode createCommonJSModule(
scopeExtensionObject->putDirectOffset(
vm,
2,
+ dirname);
+
+ scopeExtensionObject->putDirectOffset(
+ vm,
+ 3,
+ filename);
+
+ scopeExtensionObject->putDirectOffset(
+ vm,
+ 4,
requireFunction);
auto* executable = JSC::DirectEvalExecutable::create(
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 2a6be49b2..0a453a9c8 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -2619,7 +2619,7 @@ void GlobalObject::finishCreation(VM& vm)
JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype(
globalObject,
globalObject->objectPrototype(),
- 3);
+ 5);
JSC::PropertyOffset offset;
auto& vm = globalObject->vm();
@@ -2640,6 +2640,20 @@ void GlobalObject::finishCreation(VM& vm)
structure = structure->addPropertyTransition(
vm,
structure,
+ JSC::Identifier::fromString(vm, "__dirname"_s),
+ 0,
+ offset);
+
+ structure = structure->addPropertyTransition(
+ vm,
+ structure,
+ JSC::Identifier::fromString(vm, "__filename"_s),
+ 0,
+ offset);
+
+ structure = structure->addPropertyTransition(
+ vm,
+ structure,
JSC::Identifier::fromString(vm, "require"_s),
JSC::PropertyAttribute::Function | JSC::PropertyAttribute::Builtin | 0,
offset);
diff --git a/src/js_ast.zig b/src/js_ast.zig
index c3585ef38..707e83fa0 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -4141,6 +4141,7 @@ pub const Expr = struct {
e_class,
e_require_string,
e_require_call_target,
+ e_require_resolve_call_target,
e_commonjs_export_identifier,
@@ -4796,6 +4797,7 @@ pub const Expr = struct {
e_require_string: E.RequireString,
e_require_resolve_string: E.RequireResolveString,
e_require_call_target: void,
+ e_require_resolve_call_target: void,
e_missing: E.Missing,
e_this: E.This,
@@ -7612,6 +7614,7 @@ pub const Macro = struct {
e_require_resolve_string: E.RequireResolveString,
e_require_string: E.RequireString,
e_require_call_target: void,
+ e_require_resolve_call_target: void,
g_property: *G.Property,
@@ -7660,6 +7663,7 @@ pub const Macro = struct {
e_if,
e_require_resolve_string,
e_require_call_target,
+ e_require_resolve_call_target,
e_import,
e_this,
e_class,
diff --git a/src/js_parser.zig b/src/js_parser.zig
index 0d15ffd9e..5f46507d7 100644
--- a/src/js_parser.zig
+++ b/src/js_parser.zig
@@ -16483,14 +16483,12 @@ fn NewParser_(
// require.resolve(FOO) => import.meta.resolveSync(FOO, pathsObject)
return p.newExpr(
E.Call{
- .target = p.newExpr(
- E.Dot{
- .target = p.newExpr(E.ImportMeta{}, e_.target.loc),
- .name = "resolveSync",
- .name_loc = e_.target.data.e_dot.name_loc,
+ .target = Expr{
+ .data = .{
+ .e_require_resolve_call_target = {},
},
- e_.target.loc,
- ),
+ .loc = e_.target.loc,
+ },
.args = e_.args,
.close_paren_loc = e_.close_paren_loc,
},
@@ -21088,15 +21086,23 @@ fn NewParser_(
//
// })(module, exports, require);
.bun_js => {
- var args = allocator.alloc(Arg, 3) catch unreachable;
- args[0] = Arg{
- .binding = p.b(B.Identifier{ .ref = p.module_ref }, logger.Loc.Empty),
- };
- args[1] = Arg{
- .binding = p.b(B.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty),
- };
- args[2] = Arg{
- .binding = p.b(B.Identifier{ .ref = p.require_ref }, logger.Loc.Empty),
+ var args = allocator.alloc(Arg, 5) catch unreachable;
+ args[0..5].* = .{
+ Arg{
+ .binding = p.b(B.Identifier{ .ref = p.module_ref }, logger.Loc.Empty),
+ },
+ Arg{
+ .binding = p.b(B.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty),
+ },
+ Arg{
+ .binding = p.b(B.Identifier{ .ref = p.require_ref }, logger.Loc.Empty),
+ },
+ Arg{
+ .binding = p.b(B.Identifier{ .ref = p.dirname_ref }, logger.Loc.Empty),
+ },
+ Arg{
+ .binding = p.b(B.Identifier{ .ref = p.filename_ref }, logger.Loc.Empty),
+ },
};
var total_stmts_count: usize = 0;
for (parts) |part| {
@@ -21124,15 +21130,17 @@ fn NewParser_(
},
logger.Loc.Empty,
);
- var call_args = allocator.alloc(Expr, 4) catch unreachable;
+ var call_args = allocator.alloc(Expr, 6) catch unreachable;
//
- // (function(module, exports, require) {}).call(exports, module, exports, require)
- call_args[0..4].* = .{
+ // (function(module, exports, require, __dirname, __filename) {}).call(exports, module, exports, require, __dirname, __filename)
+ call_args[0..6].* = .{
p.newExpr(E.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty),
p.newExpr(E.Identifier{ .ref = p.module_ref }, logger.Loc.Empty),
p.newExpr(E.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty),
p.newExpr(E.Identifier{ .ref = p.require_ref }, logger.Loc.Empty),
+ p.newExpr(E.Identifier{ .ref = p.dirname_ref }, logger.Loc.Empty),
+ p.newExpr(E.Identifier{ .ref = p.filename_ref }, logger.Loc.Empty),
};
const call = p.newExpr(
diff --git a/src/js_printer.zig b/src/js_printer.zig
index 8a540edf9..6cce8bb6e 100644
--- a/src/js_printer.zig
+++ b/src/js_printer.zig
@@ -2124,26 +2124,6 @@ fn NewPrinter(
const is_unbound_eval = !e.is_direct_eval and p.isUnboundEvalIdentifier(e.target);
- if (is_unbound_eval) {
- if (e.args.len == 1 and e.args.ptr[0].data == .e_string and is_bun_platform) {
- // prisma:
- //
- // eval("__dirname")
- //
- // We don't have a __dirname variable defined in our ESM <> CJS compat mode
- // (Perhaps we should change that for cases like this?)
- //
- //
- if (e.args.ptr[0].data.e_string.eqlComptime("__dirname")) {
- p.print("import.meta.dir");
- return;
- } else if (e.args.ptr[0].data.e_string.eqlComptime("__filename")) {
- p.print("import.meta.file");
- return;
- }
- }
- }
-
if (wrap) {
p.print("(");
}
@@ -2155,9 +2135,10 @@ fn NewPrinter(
p.stmt_start = p.writer.written;
}
}
- // We don't ever want to accidentally generate a direct eval expression here
+ // We only want to generate an unbound eval() in CommonJS
p.call_target = e.target.data;
- if (is_unbound_eval) {
+
+ if (is_unbound_eval and p.options.module_type != .cjs) {
p.print("(0, ");
p.printExpr(e.target, .postfix, ExprFlag.None());
p.print(")");
@@ -2196,6 +2177,15 @@ fn NewPrinter(
p.print("import.meta.require");
}
},
+ .e_require_resolve_call_target => {
+ p.addSourceMapping(expr.loc);
+
+ if (p.options.module_type == .cjs or !is_bun_platform) {
+ p.print("require.resolve");
+ } else {
+ p.print("import.meta.resolveSync");
+ }
+ },
.e_require_string => |e| {
if (rewrite_esm_to_cjs and p.importRecord(e.import_record_index).is_legacy_bundled) {
p.printIndent();
diff --git a/test/cli/run/require-cache-fixture.cjs b/test/cli/run/require-cache-fixture.cjs
index 012f60589..b04e751ac 100644
--- a/test/cli/run/require-cache-fixture.cjs
+++ b/test/cli/run/require-cache-fixture.cjs
@@ -1,6 +1,18 @@
-// So it could be run in Node.js
+// This fixture is intended to be able to run in both Node.js and Bun
const Bun = (globalThis.Bun ??= { gc() {} });
+const { resolve } = require("path");
+
+if (__filename !== resolve(module.filename)) {
+ console.error(__filename, module.id);
+ throw new Error("__filename !== module.id");
+}
+
+if (__dirname !== resolve(module.filename, "../")) {
+ console.error(__filename, module.id);
+ throw new Error("__dirname !== module.filename");
+}
+
const foo = require("./require-cache-fixture-b.cjs");
exports.foo = foo;
diff --git a/test/cli/run/require-cache.test.js b/test/cli/run/require-cache.test.js
index 2f22ec139..e20470f9d 100644
--- a/test/cli/run/require-cache.test.js
+++ b/test/cli/run/require-cache.test.js
@@ -2,10 +2,12 @@ import { test, expect } from "bun:test";
import { bunEnv, bunExe } from "harness";
import { join } from "path";
+// This also tests __dirname and __filename
test("require.cache", () => {
const { stdout, exitCode } = Bun.spawnSync({
cmd: [bunExe(), "run", join(import.meta.dir, "require-cache-fixture.cjs")],
env: bunEnv,
+ stderr: "inherit",
});
expect(stdout.toString().trim().endsWith("--pass--")).toBe(true);