diff --git a/ReactCommon/hermes/inspector/chrome/Connection.cpp b/ReactCommon/hermes/inspector/chrome/Connection.cpp index ac7b36cc35a8cb..9eeb4acc31879e 100644 --- a/ReactCommon/hermes/inspector/chrome/Connection.cpp +++ b/ReactCommon/hermes/inspector/chrome/Connection.cpp @@ -40,6 +40,7 @@ namespace m = ::facebook::hermes::inspector::chrome::message; static const char *const kVirtualBreakpointPrefix = "virtualbreakpoint-"; static const char *const kBeforeScriptWithSourceMapExecution = "beforeScriptWithSourceMapExecution"; +static const char *const kUserEnteredScriptPrefix = "userScript"; /* * Connection::Impl @@ -104,6 +105,7 @@ class Connection::Impl : public inspector::InspectorObserver, void handle(const m::profiler::StartRequest &req) override; void handle(const m::profiler::StopRequest &req) override; void handle(const m::runtime::CallFunctionOnRequest &req) override; + void handle(const m::runtime::CompileScriptRequest &req) override; void handle(const m::runtime::EvaluateRequest &req) override; void handle(const m::runtime::GetHeapUsageRequest &req) override; void handle(const m::runtime::GetPropertiesRequest &req) override; @@ -160,6 +162,10 @@ class Connection::Impl : public inspector::InspectorObserver, std::mutex parsedScriptsMutex_; std::vector parsedScripts_; + // preparedScripts_ stores user-entered scripts that have been prepared for + // execution, and may be invoked by a later command. + std::vector> preparedScripts_; + // Some events are represented as a mode in Hermes but a breakpoint in CDP, // e.g. "beforeScriptExecution" and "beforeScriptWithSourceMapExecution". // Keep track of these separately. The caller should lock the @@ -1092,6 +1098,42 @@ void Connection::Impl::handle(const m::runtime::CallFunctionOnRequest &req) { .thenError(sendErrorToClient(req.id)); } +void Connection::Impl::handle(const m::runtime::CompileScriptRequest &req) { + auto resp = std::make_shared(); + resp->id = req.id; + + inspector_ + ->executeIfEnabled( + "Runtime.compileScriptRequest", + [this, req, resp](const debugger::ProgramState &state) { + if (req.executionContextId.hasValue() && + req.executionContextId.value() != kHermesExecutionContextId) { + throw std::invalid_argument("Invalid execution context"); + } + + auto source = std::make_shared(req.expression); + std::shared_ptr preparedScript; + try { + preparedScript = + getRuntime().prepareJavaScript(source, req.sourceURL); + } catch (const facebook::jsi::JSIException &err) { + resp->exceptionDetails = m::runtime::ExceptionDetails(); + resp->exceptionDetails->text = err.what(); + return; + } + + if (req.persistScript) { + auto scriptId = folly::to( + kUserEnteredScriptPrefix, preparedScripts_.size()); + preparedScripts_.push_back(std::move(preparedScript)); + resp->scriptId = scriptId; + } + }) + .via(executor_.get()) + .thenValue([this, resp](auto &&) { sendResponseToClient(*resp); }) + .thenError(sendErrorToClient(req.id)); +} + void Connection::Impl::handle(const m::runtime::EvaluateRequest &req) { auto remoteObjPtr = std::make_shared(); diff --git a/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp b/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp index e04f8f7c322c80..3ae62d24002f67 100644 --- a/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp +++ b/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp @@ -1,5 +1,5 @@ // Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. -// @generated SignedSource<> +// @generated SignedSource<<8397f2428e68a26e014f91fdb77c1eb3>> #include "MessageTypes.h" @@ -63,6 +63,7 @@ std::unique_ptr Request::fromJsonThrowOnError(const std::string &str) { {"Profiler.start", makeUnique}, {"Profiler.stop", makeUnique}, {"Runtime.callFunctionOn", makeUnique}, + {"Runtime.compileScript", makeUnique}, {"Runtime.evaluate", makeUnique}, {"Runtime.getHeapUsage", makeUnique}, {"Runtime.getProperties", makeUnique}, @@ -1112,6 +1113,39 @@ void runtime::CallFunctionOnRequest::accept(RequestHandler &handler) const { handler.handle(*this); } +runtime::CompileScriptRequest::CompileScriptRequest() + : Request("Runtime.compileScript") {} + +runtime::CompileScriptRequest::CompileScriptRequest(const dynamic &obj) + : Request("Runtime.compileScript") { + assign(id, obj, "id"); + assign(method, obj, "method"); + + dynamic params = obj.at("params"); + assign(expression, params, "expression"); + assign(sourceURL, params, "sourceURL"); + assign(persistScript, params, "persistScript"); + assign(executionContextId, params, "executionContextId"); +} + +dynamic runtime::CompileScriptRequest::toDynamic() const { + dynamic params = dynamic::object; + put(params, "expression", expression); + put(params, "sourceURL", sourceURL); + put(params, "persistScript", persistScript); + put(params, "executionContextId", executionContextId); + + dynamic obj = dynamic::object; + put(obj, "id", id); + put(obj, "method", method); + put(obj, "params", std::move(params)); + return obj; +} + +void runtime::CompileScriptRequest::accept(RequestHandler &handler) const { + handler.handle(*this); +} + runtime::EvaluateRequest::EvaluateRequest() : Request("Runtime.evaluate") {} runtime::EvaluateRequest::EvaluateRequest(const dynamic &obj) @@ -1456,6 +1490,25 @@ dynamic runtime::CallFunctionOnResponse::toDynamic() const { return obj; } +runtime::CompileScriptResponse::CompileScriptResponse(const dynamic &obj) { + assign(id, obj, "id"); + + dynamic res = obj.at("result"); + assign(scriptId, res, "scriptId"); + assign(exceptionDetails, res, "exceptionDetails"); +} + +dynamic runtime::CompileScriptResponse::toDynamic() const { + dynamic res = dynamic::object; + put(res, "scriptId", scriptId); + put(res, "exceptionDetails", exceptionDetails); + + dynamic obj = dynamic::object; + put(obj, "id", id); + put(obj, "result", std::move(res)); + return obj; +} + runtime::EvaluateResponse::EvaluateResponse(const dynamic &obj) { assign(id, obj, "id"); diff --git a/ReactCommon/hermes/inspector/chrome/MessageTypes.h b/ReactCommon/hermes/inspector/chrome/MessageTypes.h index 98b11b5f305257..fb5e10d32d1acb 100644 --- a/ReactCommon/hermes/inspector/chrome/MessageTypes.h +++ b/ReactCommon/hermes/inspector/chrome/MessageTypes.h @@ -1,5 +1,5 @@ // Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. -// @generated SignedSource<> +// @generated SignedSource<<2bada3d9c303c840ddcc292c7ba52604>> #pragma once @@ -52,6 +52,8 @@ struct CallArgument; struct CallFrame; struct CallFunctionOnRequest; struct CallFunctionOnResponse; +struct CompileScriptRequest; +struct CompileScriptResponse; struct ConsoleAPICalledNotification; struct EvaluateRequest; struct EvaluateResponse; @@ -141,6 +143,7 @@ struct RequestHandler { virtual void handle(const profiler::StartRequest &req) = 0; virtual void handle(const profiler::StopRequest &req) = 0; virtual void handle(const runtime::CallFunctionOnRequest &req) = 0; + virtual void handle(const runtime::CompileScriptRequest &req) = 0; virtual void handle(const runtime::EvaluateRequest &req) = 0; virtual void handle(const runtime::GetHeapUsageRequest &req) = 0; virtual void handle(const runtime::GetPropertiesRequest &req) = 0; @@ -180,6 +183,7 @@ struct NoopRequestHandler : public RequestHandler { void handle(const profiler::StartRequest &req) override {} void handle(const profiler::StopRequest &req) override {} void handle(const runtime::CallFunctionOnRequest &req) override {} + void handle(const runtime::CompileScriptRequest &req) override {} void handle(const runtime::EvaluateRequest &req) override {} void handle(const runtime::GetHeapUsageRequest &req) override {} void handle(const runtime::GetPropertiesRequest &req) override {} @@ -654,6 +658,19 @@ struct runtime::CallFunctionOnRequest : public Request { folly::Optional objectGroup; }; +struct runtime::CompileScriptRequest : public Request { + CompileScriptRequest(); + explicit CompileScriptRequest(const folly::dynamic &obj); + + folly::dynamic toDynamic() const override; + void accept(RequestHandler &handler) const override; + + std::string expression; + std::string sourceURL; + bool persistScript{}; + folly::Optional executionContextId; +}; + struct runtime::EvaluateRequest : public Request { EvaluateRequest(); explicit EvaluateRequest(const folly::dynamic &obj); @@ -801,6 +818,15 @@ struct runtime::CallFunctionOnResponse : public Response { folly::Optional exceptionDetails; }; +struct runtime::CompileScriptResponse : public Response { + CompileScriptResponse() = default; + explicit CompileScriptResponse(const folly::dynamic &obj); + folly::dynamic toDynamic() const override; + + folly::Optional scriptId; + folly::Optional exceptionDetails; +}; + struct runtime::EvaluateResponse : public Response { EvaluateResponse() = default; explicit EvaluateResponse(const folly::dynamic &obj); diff --git a/ReactCommon/hermes/inspector/tools/message_types.txt b/ReactCommon/hermes/inspector/tools/message_types.txt index 99c92cfca05028..dec6c3d4afe105 100644 --- a/ReactCommon/hermes/inspector/tools/message_types.txt +++ b/ReactCommon/hermes/inspector/tools/message_types.txt @@ -38,3 +38,4 @@ Runtime.getHeapUsage Runtime.getProperties Runtime.runIfWaitingForDebugger Runtime.globalLexicalScopeNames +Runtime.compileScript