diff --git a/src/bun.js/ConsoleObject.zig b/src/bun.js/ConsoleObject.zig index 15903af626fd8..0d96332e1fbca 100644 --- a/src/bun.js/ConsoleObject.zig +++ b/src/bun.js/ConsoleObject.zig @@ -85,7 +85,7 @@ pub fn messageWithTypeAndLevel( //message_level: u32, level: MessageLevel, global: *JSGlobalObject, - vals: [*]JSValue, + vals: [*]const JSValue, len: usize, ) callconv(.C) void { if (comptime is_bindgen) { diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp index 57f4201dfe2e2..795a0b0465e79 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.cpp +++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp @@ -92,6 +92,9 @@ static bool canPerformFastEnumeration(Structure* s) return true; } +extern "C" bool Bun__VM__specifierIsEvalEntryPoint(void*, EncodedJSValue); +extern "C" void Bun__VM__setEntryPointEvalResult(void*, EncodedJSValue); + static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObject, JSCommonJSModule* moduleObject, JSString* dirname, JSValue filename, WTF::NakedPtr& exception) { JSSourceCode* code = moduleObject->sourceCode.get(); @@ -119,6 +122,30 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj moduleObject->hasEvaluated = true; + if (Bun__VM__specifierIsEvalEntryPoint(globalObject->bunVM(), JSValue::encode(filename))) { + + // Using same approach as node, `arguments` in the entry point isn't defined + // https://github.com/nodejs/node/blob/592c6907bfe1922f36240e9df076be1864c3d1bd/lib/internal/process/execution.js#L92 + globalObject->putDirect(vm, Identifier::fromLatin1(vm, "exports"_s), moduleObject->exportsObject(), 0); + globalObject->putDirect(vm, Identifier::fromLatin1(vm, "require"_s), requireFunction, 0); + globalObject->putDirect(vm, Identifier::fromLatin1(vm, "module"_s), moduleObject, 0); + globalObject->putDirect(vm, Identifier::fromLatin1(vm, "__filename"_s), filename, 0); + globalObject->putDirect(vm, Identifier::fromLatin1(vm, "__dirname"_s), dirname, 0); + + JSValue result = JSC::evaluate(globalObject, code->sourceCode(), jsUndefined(), exception); + + if (UNLIKELY(exception.get() || result.isEmpty())) { + moduleObject->sourceCode.clear(); + return false; + } + + Bun__VM__setEntryPointEvalResult(globalObject->bunVM(), JSValue::encode(result)); + + moduleObject->sourceCode.clear(); + + return true; + } + // This will return 0 if there was a syntax error or an allocation failure JSValue fnValue = JSC::evaluate(globalObject, code->sourceCode(), jsUndefined(), exception); diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index b8910c0c6cc06..a8792fb47a67f 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -742,7 +742,7 @@ static void resetOnEachMicrotaskTick(JSC::VM& vm, Zig::GlobalObject* globalObjec } } -extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(void* console_client, int32_t executionContextId, bool miniMode, void* worker_ptr) +extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(void* console_client, int32_t executionContextId, bool miniMode, bool evalMode, void* worker_ptr) { auto heapSize = miniMode ? JSC::HeapType::Small : JSC::HeapType::Large; @@ -779,6 +779,13 @@ extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(void* console_client, globalObject->m_processEnvObject.set(vm, globalObject, env); } } + } else if (evalMode) { + globalObject = Zig::EvalGlobalObject::create( + vm, + Zig::EvalGlobalObject::createStructure(vm, JSC::JSGlobalObject::create(vm, JSC::JSGlobalObject::createStructure(vm, JSC::jsNull())), + JSC::jsNull()), + &Zig::EvalGlobalObject::s_globalObjectMethodTable); + } else { globalObject = Zig::GlobalObject::create( vm, @@ -993,15 +1000,38 @@ const JSC::GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &reportUncaughtExceptionAtEventLoop, ¤tScriptExecutionOwner, &scriptExecutionStatus, + nullptr, // reportViolationForUnsafeEval nullptr, // defaultLanguage nullptr, // compileStreaming nullptr, // instantiateStreaming + &Zig::deriveShadowRealmGlobalObject +}; + +const JSC::GlobalObjectMethodTable EvalGlobalObject::s_globalObjectMethodTable = { + &supportsRichSourceInfo, + &shouldInterruptScript, + &javaScriptRuntimeFlags, + // &queueMicrotaskToEventLoop, // queueTaskToEventLoop nullptr, + nullptr, // &shouldInterruptScriptBeforeTimeout, + &moduleLoaderImportModule, // moduleLoaderImportModule + &moduleLoaderResolve, // moduleLoaderResolve + &moduleLoaderFetch, // moduleLoaderFetch + &moduleLoaderCreateImportMetaProperties, // moduleLoaderCreateImportMetaProperties + &moduleLoaderEvaluate, // moduleLoaderEvaluate + &promiseRejectionTracker, // promiseRejectionTracker + &reportUncaughtExceptionAtEventLoop, + ¤tScriptExecutionOwner, + &scriptExecutionStatus, + nullptr, // reportViolationForUnsafeEval + nullptr, // defaultLanguage + nullptr, // compileStreaming + nullptr, // instantiateStreaming &Zig::deriveShadowRealmGlobalObject }; -GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure) - : JSC::JSGlobalObject(vm, structure, &s_globalObjectMethodTable) +GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable) + : JSC::JSGlobalObject(vm, structure, methodTable) , m_bunVM(Bun__getVM()) , m_constructors(makeUnique()) , m_world(WebCore::DOMWrapperWorld::create(vm, WebCore::DOMWrapperWorld::Type::Normal)) @@ -1017,8 +1047,8 @@ GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure) globalEventScope.relaxAdoptionRequirement(); } -GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, WebCore::ScriptExecutionContextIdentifier contextId) - : JSC::JSGlobalObject(vm, structure, &s_globalObjectMethodTable) +GlobalObject::GlobalObject(JSC::VM& vm, JSC::Structure* structure, WebCore::ScriptExecutionContextIdentifier contextId, const JSC::GlobalObjectMethodTable* methodTable) + : JSC::JSGlobalObject(vm, structure, methodTable) , m_bunVM(Bun__getVM()) , m_constructors(makeUnique()) , m_world(WebCore::DOMWrapperWorld::create(vm, WebCore::DOMWrapperWorld::Type::Normal)) @@ -4478,21 +4508,47 @@ JSC::JSObject* GlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObje return Zig::ImportMetaObject::create(globalObject, keyString); } -JSC::JSValue GlobalObject::moduleLoaderEvaluate(JSGlobalObject* globalObject, +extern "C" void Bun__VM__setEvalResultIfEntryPoint(void*, EncodedJSValue, EncodedJSValue); + +JSC::JSValue GlobalObject::moduleLoaderEvaluate(JSGlobalObject* lexicalGlobalObject, JSModuleLoader* moduleLoader, JSValue key, JSValue moduleRecordValue, JSValue scriptFetcher, JSValue sentValue, JSValue resumeMode) { + Zig::GlobalObject* globalObject = jsCast(lexicalGlobalObject); + if (UNLIKELY(scriptFetcher && scriptFetcher.isObject())) { return scriptFetcher; } - JSC::JSValue result = moduleLoader->evaluateNonVirtual(globalObject, key, moduleRecordValue, + JSC::JSValue result = moduleLoader->evaluateNonVirtual(lexicalGlobalObject, key, moduleRecordValue, scriptFetcher, sentValue, resumeMode); return result; } +JSC::JSValue EvalGlobalObject::moduleLoaderEvaluate(JSGlobalObject* lexicalGlobalObject, + JSModuleLoader* moduleLoader, JSValue key, + JSValue moduleRecordValue, JSValue scriptFetcher, + JSValue sentValue, JSValue resumeMode) +{ + Zig::GlobalObject* globalObject = jsCast(lexicalGlobalObject); + + if (UNLIKELY(scriptFetcher && scriptFetcher.isObject())) { + Bun__VM__setEvalResultIfEntryPoint(globalObject->bunVM(), JSValue::encode(key), JSValue::encode(scriptFetcher)); + return scriptFetcher; + } + + JSC::JSValue result = moduleLoader->evaluateNonVirtual(lexicalGlobalObject, key, moduleRecordValue, + scriptFetcher, sentValue, resumeMode); + + // need to check each module evaluated to cover cases like these (23 should be the result): + // `import "./foo"; 23; import "./bar"` + Bun__VM__setEvalResultIfEntryPoint(globalObject->bunVM(), JSValue::encode(key), JSValue::encode(result)); + + return result; +} + GlobalObject::PromiseFunctions GlobalObject::promiseHandlerID(EncodedJSValue (*handler)(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1)) { if (handler == Bun__HTTPRequestContext__onReject) { diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index e8db205154566..8ee821f4e351d 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -92,6 +92,9 @@ class GlobalObject : public JSC::JSGlobalObject { // Make binding code generation easier. GlobalObject* globalObject() { return this; } + GlobalObject(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable*); + GlobalObject(JSC::VM& vm, JSC::Structure* structure, uint32_t, const JSC::GlobalObjectMethodTable*); + DOMGuardedObjectSet& guardedObjects() WTF_REQUIRES_LOCK(m_gcLock) { return m_guardedObjects; } const DOMGuardedObjectSet& guardedObjects() const WTF_IGNORES_THREAD_SAFETY_ANALYSIS @@ -107,14 +110,28 @@ class GlobalObject : public JSC::JSGlobalObject { static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure) { - GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) GlobalObject(vm, structure); + GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) GlobalObject(vm, structure, &s_globalObjectMethodTable); ptr->finishCreation(vm); return ptr; } static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure, uint32_t scriptExecutionContextId) { - GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) GlobalObject(vm, structure, scriptExecutionContextId); + GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) GlobalObject(vm, structure, scriptExecutionContextId, &s_globalObjectMethodTable); + ptr->finishCreation(vm); + return ptr; + } + + static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable) + { + GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) GlobalObject(vm, structure, methodTable); + ptr->finishCreation(vm); + return ptr; + } + + static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure, uint32_t scriptExecutionContextId, const JSC::GlobalObjectMethodTable* methodTable) + { + GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) GlobalObject(vm, structure, scriptExecutionContextId, methodTable); ptr->finishCreation(vm); return ptr; } @@ -169,6 +186,7 @@ class GlobalObject : public JSC::JSGlobalObject { static JSC::JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue); static JSC::JSObject* moduleLoaderCreateImportMetaProperties(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSModuleRecord*, JSC::JSValue); static JSC::JSValue moduleLoaderEvaluate(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue); + static ScriptExecutionStatus scriptExecutionStatus(JSGlobalObject*, JSObject*); static void promiseRejectionTracker(JSGlobalObject*, JSC::JSPromise*, JSC::JSPromiseRejectionOperation); void setConsole(void* console); @@ -452,8 +470,6 @@ class GlobalObject : public JSC::JSGlobalObject { void finishCreation(JSC::VM&); friend void WebCore::JSBuiltinInternalFunctions::initialize(Zig::GlobalObject&); WebCore::JSBuiltinInternalFunctions m_builtinInternalFunctions; - GlobalObject(JSC::VM& vm, JSC::Structure* structure); - GlobalObject(JSC::VM& vm, JSC::Structure* structure, uint32_t); std::unique_ptr m_constructors; uint8_t m_worldIsNormal; JSDOMStructureMap m_structures WTF_GUARDED_BY_LOCK(m_gcLock); @@ -556,6 +572,17 @@ class GlobalObject : public JSC::JSGlobalObject { WTF::Vector> m_ffiFunctions; }; +class EvalGlobalObject : public GlobalObject { +public: + static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable; + static JSC::JSValue moduleLoaderEvaluate(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue); + + EvalGlobalObject(JSC::VM& vm, JSC::Structure* structure) + : GlobalObject(vm, structure, &s_globalObjectMethodTable) + { + } +}; + } // namespace Zig // TODO: move this diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 96355e8ee14cd..08cf843aeed10 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -14,6 +14,7 @@ const is_bindgen: bool = std.meta.globalOption("bindgen", bool) orelse false; const ArrayBuffer = @import("../base.zig").ArrayBuffer; const JSC = @import("root").bun.JSC; const Shimmer = JSC.Shimmer; +const ConsoleObject = JSC.ConsoleObject; const FFI = @import("./FFI.zig"); const NullableAllocator = @import("../../nullable_allocator.zig").NullableAllocator; const MutableString = bun.MutableString; @@ -4074,6 +4075,22 @@ pub const JSValue = enum(JSValueReprInt) { }); } + pub fn print( + this: JSValue, + globalObject: *JSGlobalObject, + message_type: ConsoleObject.MessageType, + message_level: ConsoleObject.MessageLevel, + ) void { + JSC.ConsoleObject.messageWithTypeAndLevel( + undefined, + message_type, + message_level, + globalObject, + &[_]JSC.JSValue{this}, + 1, + ); + } + /// Create a JSValue string from a zig format-print (fmt + args) pub fn printString(globalThis: *JSGlobalObject, comptime stack_buffer_size: usize, comptime fmt: []const u8, args: anytype) !JSValue { var stack_fallback = std.heap.stackFallback(stack_buffer_size, globalThis.allocator()); diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig index 4b5d4fedc2075..ee3a563a7f70f 100644 --- a/src/bun.js/bindings/exports.zig +++ b/src/bun.js/bindings/exports.zig @@ -45,9 +45,10 @@ pub const ZigGlobalObject = extern struct { console: *anyopaque, context_id: i32, mini_mode: bool, + eval_mode: bool, worker_ptr: ?*anyopaque, ) *JSGlobalObject { - const global = shim.cppFn("create", .{ console, context_id, mini_mode, worker_ptr }); + const global = shim.cppFn("create", .{ console, context_id, mini_mode, eval_mode, worker_ptr }); Backtrace.reloadHandlers() catch unreachable; return global; } diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h index 4d448b015ab1d..bf8cf1abbce98 100644 --- a/src/bun.js/bindings/headers.h +++ b/src/bun.js/bindings/headers.h @@ -567,7 +567,7 @@ ZIG_DECL JSC__JSValue Reader__intptr__slowpath(JSC__JSGlobalObject* arg0, JSC__J #pragma mark - Zig::GlobalObject -CPP_DECL JSC__JSGlobalObject* Zig__GlobalObject__create(void* arg0, int32_t arg1, bool arg2, void* arg3); +CPP_DECL JSC__JSGlobalObject* Zig__GlobalObject__create(void* arg0, int32_t arg1, bool arg2, bool arg3, void* arg4); CPP_DECL void* Zig__GlobalObject__getModuleRegistryMap(JSC__JSGlobalObject* arg0); CPP_DECL bool Zig__GlobalObject__resetModuleRegistryMap(JSC__JSGlobalObject* arg0, void* arg1); diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig index 4c202bb28d8aa..7724cf485867f 100644 --- a/src/bun.js/bindings/headers.zig +++ b/src/bun.js/bindings/headers.zig @@ -358,7 +358,7 @@ pub extern fn Reader__f64__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JS pub extern fn Reader__i64__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; pub extern fn Reader__u64__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; pub extern fn Reader__intptr__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; -pub extern fn Zig__GlobalObject__create(arg0: ?*anyopaque, arg1: i32, arg2: bool, arg3: ?*anyopaque) *bindings.JSGlobalObject; +pub extern fn Zig__GlobalObject__create(arg0: ?*anyopaque, arg1: i32, arg2: bool, arg3: bool, arg4: ?*anyopaque) *bindings.JSGlobalObject; pub extern fn Zig__GlobalObject__getModuleRegistryMap(arg0: *bindings.JSGlobalObject) ?*anyopaque; pub extern fn Zig__GlobalObject__resetModuleRegistryMap(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) bool; pub extern fn Bun__Path__create(arg0: *bindings.JSGlobalObject, arg1: bool) JSC__JSValue; diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index dedd026a4ffde..3761c4763cd71 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -576,6 +576,8 @@ pub const VirtualMachine = struct { rare_data: ?*JSC.RareData = null, is_us_loop_entered: bool = false, pending_internal_promise: *JSC.JSInternalPromise = undefined, + entry_point_result: JSC.Strong = .{}, + auto_install_dependencies: bool = false, onUnhandledRejection: *const OnUnhandledRejection = defaultOnUnhandledRejection, @@ -901,8 +903,33 @@ pub const VirtualMachine = struct { return .running; } + pub fn specifierIsEvalEntryPoint(this: *VirtualMachine, specifier: JSValue) callconv(.C) bool { + if (this.module_loader.eval_source) |eval_source| { + var specifier_str = specifier.toBunString(this.global); + defer specifier_str.deref(); + return specifier_str.eqlUTF8(eval_source.path.text); + } + + return false; + } + + pub fn setEvalResultIfEntryPoint(this: *VirtualMachine, specifier: JSValue, result: JSValue) callconv(.C) void { + if (!this.entry_point_result.has() and this.specifierIsEvalEntryPoint(specifier)) { + this.entry_point_result.set(this.global, result); + } + } + + pub fn setEntryPointEvalResult(this: *VirtualMachine, value: JSValue) callconv(.C) void { + if (!this.entry_point_result.has()) { + this.entry_point_result.set(this.global, value); + } + } + comptime { @export(scriptExecutionStatus, .{ .name = "Bun__VM__scriptExecutionStatus" }); + @export(setEvalResultIfEntryPoint, .{ .name = "Bun__VM__setEvalResultIfEntryPoint" }); + @export(setEntryPointEvalResult, .{ .name = "Bun__VM__setEntryPointEvalResult" }); + @export(specifierIsEvalEntryPoint, .{ .name = "Bun__VM__specifierIsEvalEntryPoint" }); } pub fn onExit(this: *VirtualMachine) void { @@ -1226,6 +1253,7 @@ pub const VirtualMachine = struct { vm.console, -1, false, + false, null, ); vm.regular_event_loop.global = vm.global; @@ -1251,6 +1279,10 @@ pub const VirtualMachine = struct { env_loader: ?*DotEnv.Loader = null, store_fd: bool = false, smol: bool = false, + + // --print needs the result from evaluating the main module + eval: bool = false, + graph: ?*bun.StandaloneModuleGraph = null, debugger: bun.CLI.Command.Debugger = .{ .unspecified = {} }, }; @@ -1336,6 +1368,7 @@ pub const VirtualMachine = struct { vm.console, -1, opts.smol, + opts.eval, null, ); vm.regular_event_loop.global = vm.global; @@ -1483,6 +1516,7 @@ pub const VirtualMachine = struct { vm.console, @as(i32, @intCast(worker.execution_context_id)), worker.mini, + opts.eval, worker.cpp_worker, ); vm.regular_event_loop.global = vm.global; @@ -1602,13 +1636,13 @@ pub const VirtualMachine = struct { break :brk options.Loader.file; }; - if (jsc_vm.module_loader.eval_script) |eval_script| { + if (jsc_vm.module_loader.eval_source) |eval_source| { if (strings.endsWithComptime(specifier, bun.pathLiteral("/[eval]"))) { - virtual_source = eval_script; + virtual_source = eval_source; loader = .tsx; } if (strings.endsWithComptime(specifier, bun.pathLiteral("/[stdin]"))) { - virtual_source = eval_script; + virtual_source = eval_source; loader = .tsx; } } @@ -1686,7 +1720,7 @@ pub const VirtualMachine = struct { ret.result = null; ret.path = result.path; return; - } else if (jsc_vm.module_loader.eval_script != null and + } else if (jsc_vm.module_loader.eval_source != null and (strings.endsWithComptime(specifier, bun.pathLiteral("/[eval]")) or strings.endsWithComptime(specifier, bun.pathLiteral("/[stdin]")))) { diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index ec3fea4cab4f4..71f2f0ef2e9a3 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -432,6 +432,11 @@ pub const RuntimeTranspilerStore = struct { var should_close_input_file_fd = fd == null; var input_file_fd: StoredFileDescriptorType = .zero; + + const is_main = vm.main.len == path.text.len and + vm.main_hash == hash and + strings.eqlLong(vm.main, path.text, false); + var parse_options = Bundler.ParseOptions{ .allocator = allocator, .path = path, @@ -446,12 +451,13 @@ pub const RuntimeTranspilerStore = struct { .virtual_source = null, .dont_bundle_twice = true, .allow_commonjs = true, - .inject_jest_globals = bundler.options.rewrite_jest_for_tests and - vm.main.len == path.text.len and - vm.main_hash == hash and - strings.eqlLong(vm.main, path.text, false), - .set_breakpoint_on_first_line = vm.debugger != null and vm.debugger.?.set_breakpoint_on_first_line and strings.eqlLong(vm.main, path.text, true) and setBreakPointOnFirstLine(), + .inject_jest_globals = bundler.options.rewrite_jest_for_tests and is_main, + .set_breakpoint_on_first_line = vm.debugger != null and + vm.debugger.?.set_breakpoint_on_first_line and + is_main and + setBreakPointOnFirstLine(), .runtime_transpiler_cache = if (!JSC.RuntimeTranspilerCache.is_disabled) &cache else null, + .remove_cjs_module_wrapper = is_main and vm.module_loader.eval_source != null, }; defer { @@ -654,7 +660,7 @@ pub const RuntimeTranspilerStore = struct { pub const ModuleLoader = struct { transpile_source_code_arena: ?*bun.ArenaAllocator = null, - eval_script: ?*logger.Source = null, + eval_source: ?*logger.Source = null, const debug = Output.scoped(.ModuleLoader, true); @@ -1558,9 +1564,12 @@ pub const ModuleLoader = struct { .dont_bundle_twice = true, .allow_commonjs = true, .inject_jest_globals = jsc_vm.bundler.options.rewrite_jest_for_tests and is_main, - .set_breakpoint_on_first_line = is_main and jsc_vm.debugger != null and jsc_vm.debugger.?.set_breakpoint_on_first_line and setBreakPointOnFirstLine(), - + .set_breakpoint_on_first_line = is_main and + jsc_vm.debugger != null and + jsc_vm.debugger.?.set_breakpoint_on_first_line and + setBreakPointOnFirstLine(), .runtime_transpiler_cache = if (!disable_transpilying and !JSC.RuntimeTranspilerCache.is_disabled) &cache else null, + .remove_cjs_module_wrapper = is_main and jsc_vm.module_loader.eval_source != null, }; defer { if (should_close_input_file_fd and input_file_fd != bun.invalid_fd) { @@ -2140,13 +2149,13 @@ pub const ModuleLoader = struct { // The concurrent one only handles javascript-like loaders right now. var loader: ?options.Loader = jsc_vm.bundler.options.loaders.get(path.name.ext); - if (jsc_vm.module_loader.eval_script) |eval_script| { + if (jsc_vm.module_loader.eval_source) |eval_source| { if (strings.endsWithComptime(specifier, bun.pathLiteral("/[eval]"))) { - virtual_source = eval_script; + virtual_source = eval_source; loader = .tsx; } if (strings.endsWithComptime(specifier, bun.pathLiteral("/[stdin]"))) { - virtual_source = eval_script; + virtual_source = eval_source; loader = .tsx; } } diff --git a/src/bun_js.zig b/src/bun_js.zig index b96de87489706..bd00e117bf7e9 100644 --- a/src/bun_js.zig +++ b/src/bun_js.zig @@ -167,6 +167,7 @@ pub const Run = struct { .args = ctx.args, .store_fd = ctx.debug.hot_reload != .none, .smol = ctx.runtime_options.smol, + .eval = ctx.runtime_options.eval.eval_and_print, .debugger = ctx.runtime_options.debugger, }, ), @@ -182,12 +183,14 @@ pub const Run = struct { vm.arena = &run.arena; vm.allocator = arena.allocator(); - if (ctx.runtime_options.eval_script.len > 0) { - vm.module_loader.eval_script = ptr: { - const v = try bun.default_allocator.create(logger.Source); - v.* = logger.Source.initPathString(entry_path, ctx.runtime_options.eval_script); - break :ptr v; - }; + if (ctx.runtime_options.eval.script.len > 0) { + const script_source = try bun.default_allocator.create(logger.Source); + script_source.* = logger.Source.initPathString(entry_path, ctx.runtime_options.eval.script); + vm.module_loader.eval_source = script_source; + + if (ctx.runtime_options.eval.eval_and_print) { + b.options.dead_code_elimination = false; + } } b.options.install = ctx.install; @@ -266,7 +269,7 @@ pub const Run = struct { vm.hot_reload = this.ctx.debug.hot_reload; vm.onUnhandledRejection = &onUnhandledRejectionBeforeClose; - if (this.ctx.runtime_options.eval_script.len > 0) { + if (this.ctx.runtime_options.eval.script.len > 0) { Bun__ExposeNodeModuleGlobals(vm.global); } @@ -389,6 +392,11 @@ pub const Run = struct { vm.onExit(); + if (this.ctx.runtime_options.eval.eval_and_print) { + const result = vm.entry_point_result.trySwap() orelse .undefined; + result.print(vm.global, .Log, .Log); + } + if (!JSC.is_bindgen) JSC.napi.fixDeadCodeElimination(); Global.exit(exit_code); } diff --git a/src/bundler.zig b/src/bundler.zig index 8ddeaf7941ff3..cdbde565764f2 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -1278,6 +1278,7 @@ pub const Bundler = struct { inject_jest_globals: bool = false, set_breakpoint_on_first_line: bool = false, emit_decorator_metadata: bool = false, + remove_cjs_module_wrapper: bool = false, dont_bundle_twice: bool = false, allow_commonjs: bool = false, @@ -1429,6 +1430,7 @@ pub const Bundler = struct { opts.features.minify_syntax = bundler.options.minify_syntax; opts.features.minify_identifiers = bundler.options.minify_identifiers; opts.features.dead_code_elimination = bundler.options.dead_code_elimination; + opts.features.remove_cjs_module_wrapper = this_parse.remove_cjs_module_wrapper; if (bundler.macro_context == null) { bundler.macro_context = js_ast.Macro.MacroContext.init(bundler); diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index 986aa9871858c..c052ce37c194f 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -4513,7 +4513,6 @@ const LinkerContext = struct { stmt.loc, ), expr, - this.allocator, ); try this.graph.generateSymbolImportAndUse(source_index, 0, module_ref, 1, Index.init(source_index)); }, @@ -7521,7 +7520,6 @@ const LinkerContext = struct { }, Logger.Loc.Empty, ), - temp_allocator, ), ) catch unreachable; }, @@ -8725,7 +8723,6 @@ const LinkerContext = struct { value = value.joinWithComma( binding.assign( other, - temp_allocator, ), temp_allocator, ); diff --git a/src/cli.zig b/src/cli.zig index 0699666d57da4..6e6d3355f97a5 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -174,6 +174,7 @@ pub const Arguments = struct { clap.parseParam("--install Configure auto-install behavior. One of \"auto\" (default, auto-installs when no node_modules), \"fallback\" (missing packages only), \"force\" (always).") catch unreachable, clap.parseParam("-i Auto-install dependencies during execution. Equivalent to --install=fallback.") catch unreachable, clap.parseParam("-e, --eval Evaluate argument as a script") catch unreachable, + clap.parseParam("--print Evaluate argument as a script and print the result") catch unreachable, clap.parseParam("--prefer-offline Skip staleness checks for packages in the Bun runtime and resolve from disk") catch unreachable, clap.parseParam("--prefer-latest Use the latest matching versions of packages in the Bun runtime, always checking npm") catch unreachable, clap.parseParam("-p, --port Set the default port for Bun.serve") catch unreachable, @@ -537,7 +538,13 @@ pub const Arguments = struct { } if (args.option("--port")) |port_str| { - opts.port = std.fmt.parseInt(u16, port_str, 10) catch return error.InvalidPort; + if (comptime cmd == .RunAsNodeCommand) { + // TODO: prevent `node --port