Skip to content

Commit

Permalink
Implement Runtime.compileScript
Browse files Browse the repository at this point in the history
Summary: Implement `Runtime.compileScript`

Reviewed By: dannysu

Differential Revision: D53314067

fbshipit-source-id: bb3c87a08af92404c34b6901f529d11811f07f0c
  • Loading branch information
Matt Blagden authored and facebook-github-bot committed Feb 8, 2024
1 parent 337a0d7 commit 00a2f44
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 0 deletions.
3 changes: 3 additions & 0 deletions API/hermes/cdp/CDPAgent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ void CDPAgentImpl::DomainAgents::handleCommand(
} else if (command->method == "Runtime.globalLexicalScopeNames") {
runtimeAgent_->globalLexicalScopeNames(
static_cast<m::runtime::GlobalLexicalScopeNamesRequest &>(*command));
} else if (command->method == "Runtime.compileScript") {
runtimeAgent_->compileScript(
static_cast<m::runtime::CompileScriptRequest &>(*command));
} else {
messageCallback_(message::makeErrorResponse(
command->id,
Expand Down
31 changes: 31 additions & 0 deletions API/hermes/cdp/RuntimeDomainAgent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace facebook {
namespace hermes {
namespace cdp {

static const char *const kUserEnteredScriptIdPrefix = "userScript";

RuntimeDomainAgent::RuntimeDomainAgent(
int32_t executionContextID,
HermesRuntime &runtime,
Expand Down Expand Up @@ -98,6 +100,35 @@ void RuntimeDomainAgent::globalLexicalScopeNames(
sendResponseToClient(resp);
}

void RuntimeDomainAgent::compileScript(
const m::runtime::CompileScriptRequest &req) {
if (!checkRuntimeEnabled(req)) {
return;
}

m::runtime::CompileScriptResponse resp;
resp.id = req.id;

auto source = std::make_shared<jsi::StringBuffer>(req.expression);
std::shared_ptr<const jsi::PreparedJavaScript> preparedScript;
try {
preparedScript = runtime_.prepareJavaScript(source, req.sourceURL);
} catch (const facebook::jsi::JSIException &err) {
resp.exceptionDetails = m::runtime::ExceptionDetails();
resp.exceptionDetails->text = err.what();
sendResponseToClient(resp);
return;
}

if (req.persistScript) {
auto scriptId =
kUserEnteredScriptIdPrefix + std::to_string(preparedScripts_.size());
preparedScripts_.push_back(std::move(preparedScript));
resp.scriptId = scriptId;
}
sendResponseToClient(resp);
}

bool RuntimeDomainAgent::checkRuntimeEnabled(const m::Request &req) {
if (!enabled_) {
sendResponseToClient(m::makeErrorResponse(
Expand Down
6 changes: 6 additions & 0 deletions API/hermes/cdp/RuntimeDomainAgent.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class RuntimeDomainAgent : public DomainAgent {
/// Handles Runtime.globalLexicalScopeNames request
void globalLexicalScopeNames(
const m::runtime::GlobalLexicalScopeNamesRequest &req);
/// Handles Runtime.compileScript request
void compileScript(const m::runtime::CompileScriptRequest &req);

private:
bool checkRuntimeEnabled(const m::Request &req);
Expand All @@ -46,6 +48,10 @@ class RuntimeDomainAgent : public DomainAgent {
/// Whether Runtime.enable was received and wasn't disabled by receiving
/// Runtime.disable
bool enabled_;

// preparedScripts_ stores user-entered scripts that have been prepared for
// execution, and may be invoked by a later command.
std::vector<std::shared_ptr<const jsi::PreparedJavaScript>> preparedScripts_;
};

} // namespace cdp
Expand Down
2 changes: 2 additions & 0 deletions API/hermes/inspector/chrome/tests/ConnectionTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,7 @@ TEST_F(ConnectionTests, testRuntimeEvaluateReturnByValue) {
asyncRuntime.stop();
}

// Also implemented as CDPAgentTest::RuntimeCompileScript
TEST_F(ConnectionTests, testRuntimeCompileScript) {
int msgId = 1;

Expand All @@ -1681,6 +1682,7 @@ TEST_F(ConnectionTests, testRuntimeCompileScript) {
asyncRuntime.stop();
}

// Also implemented as CDPAgentTest::RuntimeCompileScriptParseError
TEST_F(ConnectionTests, testRuntimeCompileScriptParseError) {
int msgId = 1;

Expand Down
38 changes: 38 additions & 0 deletions unittests/API/CDPAgentTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1243,4 +1243,42 @@ TEST_F(CDPAgentTest, RuntimeGlobalLexicalScopeNames) {
stopFlag_.store(true);
}

TEST_F(CDPAgentTest, RuntimeCompileScript) {
int msgId = 1;

sendAndCheckResponse("Runtime.enable", msgId++);
ensureNotification(waitForMessage(), "Runtime.executionContextCreated");

// Compile a valid script
sendRequest("Runtime.compileScript", msgId, [](::hermes::JSONEmitter &json) {
json.emitKeyValue("persistScript", true);
json.emitKeyValue("sourceURL", "none");
json.emitKeyValue("expression", "1+1");
});

// Expect success, and a unique identifier for the script
auto resp = expectResponse(std::nullopt, msgId++);
EXPECT_EQ("userScript0", jsonScope_.getString(resp, {"result", "scriptId"}));
}

TEST_F(CDPAgentTest, RuntimeCompileScriptParseError) {
int msgId = 1;

sendAndCheckResponse("Runtime.enable", msgId++);
ensureNotification(waitForMessage(), "Runtime.executionContextCreated");

// Compile an invalid script
sendRequest("Runtime.compileScript", msgId, [](::hermes::JSONEmitter &json) {
json.emitKeyValue("persistScript", true);
json.emitKeyValue("sourceURL", "none");
json.emitKeyValue("expression", "/oops");
});

// Expect it to be rejected with details about the compilation failure
auto resp = expectResponse(std::nullopt, msgId++);
EXPECT_GT(
jsonScope_.getString(resp, {"result", "exceptionDetails", "text"}).size(),
0);
}

#endif // HERMES_ENABLE_DEBUGGER

0 comments on commit 00a2f44

Please sign in to comment.