diff --git a/cmake/tools/SetupWebKit.cmake b/cmake/tools/SetupWebKit.cmake index d3283cd2fd..d1af77335d 100644 --- a/cmake/tools/SetupWebKit.cmake +++ b/cmake/tools/SetupWebKit.cmake @@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use") option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading") if(NOT WEBKIT_VERSION) - set(WEBKIT_VERSION 754692aa9c30218d1e81444670f5e4649426b157) + set(WEBKIT_VERSION a4e17c67e3ba1dd35000a89161a591cbf09716ee) endif() string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX) diff --git a/src/bun.js/bindings/InspectorLifecycleAgent.cpp b/src/bun.js/bindings/InspectorLifecycleAgent.cpp index 090f9f59d7..a5eadfc1f0 100644 --- a/src/bun.js/bindings/InspectorLifecycleAgent.cpp +++ b/src/bun.js/bindings/InspectorLifecycleAgent.cpp @@ -1,5 +1,5 @@ #include "InspectorLifecycleAgent.h" - +#include "ZigGlobalObject.h" #include #include #include @@ -12,6 +12,12 @@ #include #include "ConsoleObject.h" #include +#include +#include +#include +#include +#include "BunProcess.h" +#include "headers.h" namespace Inspector { @@ -131,4 +137,77 @@ Protocol::ErrorStringOr InspectorLifecycleAgent::stopPreventingExit() return {}; } -} // namespace Inspector +using ModuleGraph = std::tuple> /* esm */, Ref> /* cjs */, String /* cwd */, String /* main */, Ref> /* argv */>; + +Protocol::ErrorStringOr InspectorLifecycleAgent::getModuleGraph() +{ + auto& vm = m_globalObject.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* global = defaultGlobalObject(&m_globalObject); + auto* esmMap = global->esmRegistryMap(); + auto* cjsMap = global->requireMap(); + + if (!esmMap || !cjsMap) { + return makeUnexpected(ErrorString("Module graph not available"_s)); + } + + Ref> esm = JSON::ArrayOf::create(); + { + auto iter1 = JSC::JSMapIterator::create(global, global->mapIteratorStructure(), esmMap, JSC::IterationKind::Keys); + RETURN_IF_EXCEPTION(scope, makeUnexpected(ErrorString("Failed to create iterator"_s))); + JSC::JSValue value; + while (iter1->next(global, value)) { + esm->addItem(value.toWTFString(global)); + RETURN_IF_EXCEPTION(scope, makeUnexpected(ErrorString("Failed to add item to esm array"_s))); + } + } + + Ref> cjs = JSON::ArrayOf::create(); + { + auto iter2 = JSC::JSMapIterator::create(global, global->mapIteratorStructure(), cjsMap, JSC::IterationKind::Keys); + RETURN_IF_EXCEPTION(scope, makeUnexpected(ErrorString("Failed to create iterator"_s))); + JSC::JSValue value; + while (iter2->next(global, value)) { + cjs->addItem(value.toWTFString(global)); + RETURN_IF_EXCEPTION(scope, makeUnexpected(ErrorString("Failed to add item to cjs array"_s))); + } + } + + auto* process = global->processObject(); + + Ref> argv = JSON::ArrayOf::create(); + { + + auto* array = jsCast(process->getArgv(global)); + RETURN_IF_EXCEPTION(scope, makeUnexpected(ErrorString("Failed to get argv"_s))); + for (size_t i = 0, length = array->length(); i < length; i++) { + auto value = array->getIndex(global, i); + RETURN_IF_EXCEPTION(scope, makeUnexpected(ErrorString("Failed to get value at index"_s))); + auto string = value.toWTFString(global); + RETURN_IF_EXCEPTION(scope, makeUnexpected(ErrorString("Failed to convert value to string"_s))); + argv->addItem(string); + } + } + + String main; + { + auto& builtinNames = Bun::builtinNames(vm); + auto value = global->bunObject()->get(global, builtinNames.mainPublicName()); + RETURN_IF_EXCEPTION(scope, makeUnexpected(ErrorString("Failed to get main"_s))); + main = value.toWTFString(global); + RETURN_IF_EXCEPTION(scope, makeUnexpected(ErrorString("Failed to convert value to string"_s))); + } + + String cwd; + { + auto cwdValue = JSC::JSValue::decode(Bun__Process__getCwd(&m_globalObject)); + RETURN_IF_EXCEPTION(scope, makeUnexpected(ErrorString("Failed to get cwd"_s))); + cwd = cwdValue.toWTFString(global); + RETURN_IF_EXCEPTION(scope, makeUnexpected(ErrorString("Failed to convert value to string"_s))); + } + + return ModuleGraph { WTFMove(esm), WTFMove(cjs), WTFMove(cwd), WTFMove(main), WTFMove(argv) }; +} + +} diff --git a/src/bun.js/bindings/InspectorLifecycleAgent.h b/src/bun.js/bindings/InspectorLifecycleAgent.h index 8f2d9ebc0a..28cfc79562 100644 --- a/src/bun.js/bindings/InspectorLifecycleAgent.h +++ b/src/bun.js/bindings/InspectorLifecycleAgent.h @@ -32,6 +32,8 @@ public: virtual Protocol::ErrorStringOr enable() final; virtual Protocol::ErrorStringOr disable() final; + virtual CommandResultOf> /* esm */, Ref> /* cjs */, String /* cwd */, String /* main */, Ref> /* argv */> getModuleGraph() final; + // Public API void reportReload(); void reportError(ZigException&); diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index ed83476f35..cf4345d36d 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -4377,6 +4377,22 @@ bool GlobalObject::hasNapiFinalizers() const void GlobalObject::setNodeWorkerEnvironmentData(JSMap* data) { m_nodeWorkerEnvironmentData.set(vm(), this, data); } +void GlobalObject::trackFFIFunction(JSC::JSFunction* function) +{ + this->m_ffiFunctions.append(JSC::Strong { vm(), function }); +} +bool GlobalObject::untrackFFIFunction(JSC::JSFunction* function) +{ + for (size_t i = 0; i < this->m_ffiFunctions.size(); ++i) { + if (this->m_ffiFunctions[i].get() == function) { + this->m_ffiFunctions[i].clear(); + this->m_ffiFunctions.removeAt(i); + return true; + } + } + return false; +} + extern "C" void Zig__GlobalObject__destructOnExit(Zig::GlobalObject* globalObject) { auto& vm = JSC::getVM(globalObject); diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 1713e377e2..1e376a94bb 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -643,21 +643,8 @@ public: String agentClusterID() const; static String defaultAgentClusterID(); - void trackFFIFunction(JSC::JSFunction* function) - { - this->m_ffiFunctions.append(JSC::Strong { vm(), function }); - } - bool untrackFFIFunction(JSC::JSFunction* function) - { - for (size_t i = 0; i < this->m_ffiFunctions.size(); ++i) { - if (this->m_ffiFunctions[i].get() == function) { - this->m_ffiFunctions[i].clear(); - this->m_ffiFunctions.remove(i); - return true; - } - } - return false; - } + void trackFFIFunction(JSC::JSFunction* function); + bool untrackFFIFunction(JSC::JSFunction* function); BunPlugin::OnLoad onLoadPlugins {}; BunPlugin::OnResolve onResolvePlugins {}; diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 29a74e28ba..32af189ab8 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -675,7 +675,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2, } auto removeFromStack = WTF::makeScopeExit([&] { if (addToStack) { - stack.remove(length); + stack.removeAt(length); while (gcBuffer.size() > originalGCBufferSize) gcBuffer.removeLast(); } diff --git a/src/bun.js/bindings/webcore/EventListenerMap.cpp b/src/bun.js/bindings/webcore/EventListenerMap.cpp index 4c8539aac4..be3493744f 100644 --- a/src/bun.js/bindings/webcore/EventListenerMap.cpp +++ b/src/bun.js/bindings/webcore/EventListenerMap.cpp @@ -135,7 +135,7 @@ static bool removeListenerFromVector(EventListenerVector& listeners, EventListen return false; listeners[indexOfRemovedListener]->markAsRemoved(); - listeners.remove(indexOfRemovedListener); + listeners.removeAt(indexOfRemovedListener); return true; } @@ -147,7 +147,7 @@ bool EventListenerMap::remove(const AtomString& eventType, EventListener& listen if (m_entries[i].first == eventType) { bool wasRemoved = removeListenerFromVector(m_entries[i].second, listener, useCapture); if (m_entries[i].second.isEmpty()) - m_entries.remove(i); + m_entries.removeAt(i); return wasRemoved; } } @@ -185,7 +185,7 @@ void EventListenerMap::removeFirstEventListenerCreatedFromMarkup(const AtomStrin if (m_entries[i].first == eventType) { removeFirstListenerCreatedFromMarkup(m_entries[i].second); if (m_entries[i].second.isEmpty()) - m_entries.remove(i); + m_entries.removeAt(i); return; } } diff --git a/src/bun.js/bindings/webcore/IdentifierEventListenerMap.cpp b/src/bun.js/bindings/webcore/IdentifierEventListenerMap.cpp index cbdfe6aa46..89ce0bba39 100644 --- a/src/bun.js/bindings/webcore/IdentifierEventListenerMap.cpp +++ b/src/bun.js/bindings/webcore/IdentifierEventListenerMap.cpp @@ -96,7 +96,7 @@ static bool removeListenerFromVector(SimpleEventListenerVector& listeners, Event return false; listeners[indexOfRemovedListener]->markAsRemoved(); - listeners.remove(indexOfRemovedListener); + listeners.removeAt(indexOfRemovedListener); return true; } @@ -108,7 +108,7 @@ bool IdentifierEventListenerMap::remove(const JSC::Identifier& eventType, EventL if (m_entries[i].first == eventType) { bool wasRemoved = removeListenerFromVector(m_entries[i].second, listener); if (m_entries[i].second.isEmpty()) - m_entries.remove(i); + m_entries.removeAt(i); return wasRemoved; } } @@ -122,7 +122,7 @@ bool IdentifierEventListenerMap::removeAll(const JSC::Identifier& eventType) for (unsigned i = 0; i < m_entries.size(); ++i) { if (m_entries[i].first == eventType) { - m_entries.remove(i); + m_entries.removeAt(i); return true; } } diff --git a/src/bun.js/bindings/webcore/MessagePortChannel.cpp b/src/bun.js/bindings/webcore/MessagePortChannel.cpp index 92f82c67c6..c231e812d7 100644 --- a/src/bun.js/bindings/webcore/MessagePortChannel.cpp +++ b/src/bun.js/bindings/webcore/MessagePortChannel.cpp @@ -170,7 +170,7 @@ std::optional MessagePortChannel::tryTakeMessageForPort return std::nullopt; auto message = m_pendingMessages[i].first(); - m_pendingMessages[i].remove(0); + m_pendingMessages[i].removeAt(0); return WTFMove(message); } diff --git a/src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp b/src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp index 636e8ba809..7e2fc56194 100644 --- a/src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp @@ -51,7 +51,7 @@ RefPtr CryptoKeyRSA::importJwk(CryptoAlgorithmIdentifier algorithm return nullptr; // Per RFC 7518 Section 6.3.1.1: https://tools.ietf.org/html/rfc7518#section-6.3.1.1 if (!modulus->isEmpty() && !modulus->at(0)) - modulus->remove(0); + modulus->removeAt(0); auto exponent = base64URLDecode(keyData.e); if (!exponent) return nullptr; diff --git a/test/cli/inspect/BunFrontendDevServer.test.ts b/test/cli/inspect/BunFrontendDevServer.test.ts index 1d99aeab8f..f9f38fb100 100644 --- a/test/cli/inspect/BunFrontendDevServer.test.ts +++ b/test/cli/inspect/BunFrontendDevServer.test.ts @@ -4,7 +4,7 @@ import { Subprocess, spawn } from "bun"; import { afterAll, beforeAll, describe, expect, test } from "bun:test"; import fs from "fs"; import { bunExe, bunEnv as env, isPosix, tmpdirSync } from "harness"; -import { join } from "node:path"; +import path, { join } from "node:path"; import { InspectorSession, connect } from "./junit-reporter"; import { SocketFramer } from "./socket-framer"; const bunEnv = { ...env, NODE_ENV: "development" }; @@ -18,6 +18,7 @@ class BunFrontendDevServerSession extends InspectorSession { this.send("Console.enable"); this.send("Runtime.enable"); this.send("BunFrontendDevServer.enable"); + this.send("LifecycleReporter.enable"); await this.sendAndWait("Inspector.initialized"); } @@ -341,6 +342,39 @@ describe.if(isPosix)("BunFrontendDevServer inspector protocol", () => { // Verify the duration is reasonable expect(bundleCompleteEvent.durationMs).toBeGreaterThan(-1); + + // Test for LifecycleReporter.getModuleGraph + type ModuleGraph = { + argv: string[]; + cjs: string[]; + esm: string[]; + main: string; + cwd: string; + }; + const moduleGraph = (await session.sendAndWait("LifecycleReporter.getModuleGraph")) as ModuleGraph; + const realCwd = path.resolve(tempdir).replaceAll("\\", "/"); + moduleGraph.argv = moduleGraph.argv.map(a => path.basename(a)); + moduleGraph.cjs = moduleGraph.cjs.map(a => a.replaceAll("\\", "/").replaceAll(realCwd, "")); + moduleGraph.esm = moduleGraph.esm.map(a => a.replaceAll("\\", "/").replaceAll(realCwd, "")); + moduleGraph.main = moduleGraph.main.replaceAll("\\", "/").replaceAll(realCwd, ""); + moduleGraph.cwd = moduleGraph.cwd.replaceAll("\\", "/").replaceAll(realCwd, ""); + expect(moduleGraph).toMatchInlineSnapshot(` + { + "argv": [ + "${path.basename(process.execPath)}", + "server.ts", + ], + "cjs": [], + "cwd": "", + "esm": [ + "bun:main", + "/server.ts", + "/index.html", + "/second.html", + ], + "main": "/server.ts", + } + `); }); test("should notify on bundleFailed events", async () => {