mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-09 17:49:40 +00:00
LibDevTools: Begin supporting the JavaScript console
This implements enough to execute JavaScript and reply with the result. We do not yet support autocomplete or eager evaluation.
This commit is contained in:
parent
37f07c176a
commit
6d33b70e61
Notes:
github-actions[bot]
2025-02-28 12:09:40 +00:00
Author: https://github.com/trflynn89
Commit: 6d33b70e61
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3686
8 changed files with 170 additions and 7 deletions
97
Libraries/LibDevTools/Actors/ConsoleActor.cpp
Normal file
97
Libraries/LibDevTools/Actors/ConsoleActor.cpp
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/Debug.h>
|
||||||
|
#include <AK/JsonArray.h>
|
||||||
|
#include <AK/JsonObject.h>
|
||||||
|
#include <AK/Time.h>
|
||||||
|
#include <LibDevTools/Actors/ConsoleActor.h>
|
||||||
|
#include <LibDevTools/Actors/TabActor.h>
|
||||||
|
#include <LibDevTools/DevToolsDelegate.h>
|
||||||
|
#include <LibDevTools/DevToolsServer.h>
|
||||||
|
|
||||||
|
namespace DevTools {
|
||||||
|
|
||||||
|
NonnullRefPtr<ConsoleActor> ConsoleActor::create(DevToolsServer& devtools, String name, WeakPtr<TabActor> tab)
|
||||||
|
{
|
||||||
|
return adopt_ref(*new ConsoleActor(devtools, move(name), move(tab)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleActor::ConsoleActor(DevToolsServer& devtools, String name, WeakPtr<TabActor> tab)
|
||||||
|
: Actor(devtools, move(name))
|
||||||
|
, m_tab(move(tab))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleActor::~ConsoleActor() = default;
|
||||||
|
|
||||||
|
void ConsoleActor::handle_message(StringView type, JsonObject const& message)
|
||||||
|
{
|
||||||
|
JsonObject response;
|
||||||
|
response.set("from"sv, name());
|
||||||
|
|
||||||
|
if (type == "autocomplete"sv) {
|
||||||
|
response.set("matches"sv, JsonArray {});
|
||||||
|
response.set("matchProp"sv, String {});
|
||||||
|
send_message(move(response));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == "evaluateJSAsync"sv) {
|
||||||
|
auto text = message.get_string("text"sv);
|
||||||
|
if (!text.has_value()) {
|
||||||
|
send_missing_parameter_error("text"sv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result_id = MUST(String::formatted("{}-{}", name(), m_execution_id++));
|
||||||
|
|
||||||
|
response.set("resultID"sv, result_id);
|
||||||
|
send_message(move(response));
|
||||||
|
|
||||||
|
// FIXME: We do not support eager evaluation of scripts. Just bail for now.
|
||||||
|
if (message.get_bool("eager"sv).value_or(false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto tab = m_tab.strong_ref()) {
|
||||||
|
auto block_token = block_responses();
|
||||||
|
|
||||||
|
devtools().delegate().evaluate_javascript(tab->description(), *text,
|
||||||
|
[result_id, input = *text, weak_self = make_weak_ptr<ConsoleActor>(), block_token = move(block_token)](ErrorOr<JsonValue> result) mutable {
|
||||||
|
if (result.is_error()) {
|
||||||
|
dbgln_if(DEVTOOLS_DEBUG, "Unable to inspect DOM node: {}", result.error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto self = weak_self.strong_ref())
|
||||||
|
self->received_console_result(move(result_id), move(input), result.release_value(), move(block_token));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_unrecognized_packet_type_error(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleActor::received_console_result(String result_id, String input, JsonValue result, BlockToken block_token)
|
||||||
|
{
|
||||||
|
JsonObject message;
|
||||||
|
message.set("from"sv, name());
|
||||||
|
message.set("type"sv, "evaluationResult"_string);
|
||||||
|
message.set("timestamp"sv, AK::UnixDateTime::now().milliseconds_since_epoch());
|
||||||
|
message.set("resultID"sv, move(result_id));
|
||||||
|
message.set("input"sv, move(input));
|
||||||
|
message.set("result"sv, move(result));
|
||||||
|
message.set("exception"sv, JsonValue {});
|
||||||
|
message.set("exceptionMessage"sv, JsonValue {});
|
||||||
|
message.set("helperResult"sv, JsonValue {});
|
||||||
|
|
||||||
|
send_message(move(message), move(block_token));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
Libraries/LibDevTools/Actors/ConsoleActor.h
Normal file
33
Libraries/LibDevTools/Actors/ConsoleActor.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/NonnullRefPtr.h>
|
||||||
|
#include <LibDevTools/Actor.h>
|
||||||
|
|
||||||
|
namespace DevTools {
|
||||||
|
|
||||||
|
class ConsoleActor final : public Actor {
|
||||||
|
public:
|
||||||
|
static constexpr auto base_name = "console"sv;
|
||||||
|
|
||||||
|
static NonnullRefPtr<ConsoleActor> create(DevToolsServer&, String name, WeakPtr<TabActor>);
|
||||||
|
virtual ~ConsoleActor() override;
|
||||||
|
|
||||||
|
virtual void handle_message(StringView type, JsonObject const&) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ConsoleActor(DevToolsServer&, String name, WeakPtr<TabActor>);
|
||||||
|
|
||||||
|
void received_console_result(String result_id, String input, JsonValue result, BlockToken);
|
||||||
|
|
||||||
|
WeakPtr<TabActor> m_tab;
|
||||||
|
|
||||||
|
u64 m_execution_id { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
#include <AK/JsonArray.h>
|
#include <AK/JsonArray.h>
|
||||||
#include <AK/JsonObject.h>
|
#include <AK/JsonObject.h>
|
||||||
#include <LibDevTools/Actors/CSSPropertiesActor.h>
|
#include <LibDevTools/Actors/CSSPropertiesActor.h>
|
||||||
|
#include <LibDevTools/Actors/ConsoleActor.h>
|
||||||
#include <LibDevTools/Actors/FrameActor.h>
|
#include <LibDevTools/Actors/FrameActor.h>
|
||||||
#include <LibDevTools/Actors/InspectorActor.h>
|
#include <LibDevTools/Actors/InspectorActor.h>
|
||||||
#include <LibDevTools/Actors/TabActor.h>
|
#include <LibDevTools/Actors/TabActor.h>
|
||||||
|
@ -14,15 +15,16 @@
|
||||||
|
|
||||||
namespace DevTools {
|
namespace DevTools {
|
||||||
|
|
||||||
NonnullRefPtr<FrameActor> FrameActor::create(DevToolsServer& devtools, String name, WeakPtr<TabActor> tab, WeakPtr<CSSPropertiesActor> css_properties, WeakPtr<InspectorActor> inspector, WeakPtr<ThreadActor> thread)
|
NonnullRefPtr<FrameActor> FrameActor::create(DevToolsServer& devtools, String name, WeakPtr<TabActor> tab, WeakPtr<CSSPropertiesActor> css_properties, WeakPtr<ConsoleActor> console, WeakPtr<InspectorActor> inspector, WeakPtr<ThreadActor> thread)
|
||||||
{
|
{
|
||||||
return adopt_ref(*new FrameActor(devtools, move(name), move(tab), move(css_properties), move(inspector), move(thread)));
|
return adopt_ref(*new FrameActor(devtools, move(name), move(tab), move(css_properties), move(console), move(inspector), move(thread)));
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameActor::FrameActor(DevToolsServer& devtools, String name, WeakPtr<TabActor> tab, WeakPtr<CSSPropertiesActor> css_properties, WeakPtr<InspectorActor> inspector, WeakPtr<ThreadActor> thread)
|
FrameActor::FrameActor(DevToolsServer& devtools, String name, WeakPtr<TabActor> tab, WeakPtr<CSSPropertiesActor> css_properties, WeakPtr<ConsoleActor> console, WeakPtr<InspectorActor> inspector, WeakPtr<ThreadActor> thread)
|
||||||
: Actor(devtools, move(name))
|
: Actor(devtools, move(name))
|
||||||
, m_tab(move(tab))
|
, m_tab(move(tab))
|
||||||
, m_css_properties(move(css_properties))
|
, m_css_properties(move(css_properties))
|
||||||
|
, m_console(move(console))
|
||||||
, m_inspector(move(inspector))
|
, m_inspector(move(inspector))
|
||||||
, m_thread(move(thread))
|
, m_thread(move(thread))
|
||||||
{
|
{
|
||||||
|
@ -95,6 +97,8 @@ JsonObject FrameActor::serialize_target() const
|
||||||
|
|
||||||
if (auto css_properties = m_css_properties.strong_ref())
|
if (auto css_properties = m_css_properties.strong_ref())
|
||||||
target.set("cssPropertiesActor"sv, css_properties->name());
|
target.set("cssPropertiesActor"sv, css_properties->name());
|
||||||
|
if (auto console = m_console.strong_ref())
|
||||||
|
target.set("consoleActor"sv, console->name());
|
||||||
if (auto inspector = m_inspector.strong_ref())
|
if (auto inspector = m_inspector.strong_ref())
|
||||||
target.set("inspectorActor"sv, inspector->name());
|
target.set("inspectorActor"sv, inspector->name());
|
||||||
if (auto thread = m_thread.strong_ref())
|
if (auto thread = m_thread.strong_ref())
|
||||||
|
|
|
@ -15,7 +15,7 @@ class FrameActor final : public Actor {
|
||||||
public:
|
public:
|
||||||
static constexpr auto base_name = "frame"sv;
|
static constexpr auto base_name = "frame"sv;
|
||||||
|
|
||||||
static NonnullRefPtr<FrameActor> create(DevToolsServer&, String name, WeakPtr<TabActor>, WeakPtr<CSSPropertiesActor>, WeakPtr<InspectorActor>, WeakPtr<ThreadActor>);
|
static NonnullRefPtr<FrameActor> create(DevToolsServer&, String name, WeakPtr<TabActor>, WeakPtr<CSSPropertiesActor>, WeakPtr<ConsoleActor>, WeakPtr<InspectorActor>, WeakPtr<ThreadActor>);
|
||||||
virtual ~FrameActor() override;
|
virtual ~FrameActor() override;
|
||||||
|
|
||||||
virtual void handle_message(StringView type, JsonObject const&) override;
|
virtual void handle_message(StringView type, JsonObject const&) override;
|
||||||
|
@ -24,11 +24,12 @@ public:
|
||||||
JsonObject serialize_target() const;
|
JsonObject serialize_target() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FrameActor(DevToolsServer&, String name, WeakPtr<TabActor>, WeakPtr<CSSPropertiesActor>, WeakPtr<InspectorActor>, WeakPtr<ThreadActor>);
|
FrameActor(DevToolsServer&, String name, WeakPtr<TabActor>, WeakPtr<CSSPropertiesActor>, WeakPtr<ConsoleActor>, WeakPtr<InspectorActor>, WeakPtr<ThreadActor>);
|
||||||
|
|
||||||
WeakPtr<TabActor> m_tab;
|
WeakPtr<TabActor> m_tab;
|
||||||
|
|
||||||
WeakPtr<CSSPropertiesActor> m_css_properties;
|
WeakPtr<CSSPropertiesActor> m_css_properties;
|
||||||
|
WeakPtr<ConsoleActor> m_console;
|
||||||
WeakPtr<InspectorActor> m_inspector;
|
WeakPtr<InspectorActor> m_inspector;
|
||||||
WeakPtr<ThreadActor> m_thread;
|
WeakPtr<ThreadActor> m_thread;
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/Debug.h>
|
||||||
#include <AK/JsonObject.h>
|
#include <AK/JsonObject.h>
|
||||||
#include <LibCore/EventLoop.h>
|
#include <LibCore/EventLoop.h>
|
||||||
#include <LibDevTools/Actors/CSSPropertiesActor.h>
|
#include <LibDevTools/Actors/CSSPropertiesActor.h>
|
||||||
|
#include <LibDevTools/Actors/ConsoleActor.h>
|
||||||
#include <LibDevTools/Actors/FrameActor.h>
|
#include <LibDevTools/Actors/FrameActor.h>
|
||||||
#include <LibDevTools/Actors/InspectorActor.h>
|
#include <LibDevTools/Actors/InspectorActor.h>
|
||||||
#include <LibDevTools/Actors/TabActor.h>
|
#include <LibDevTools/Actors/TabActor.h>
|
||||||
|
@ -66,6 +68,26 @@ void WatcherActor::handle_message(StringView type, JsonObject const& message)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == "watchResources"sv) {
|
||||||
|
auto resource_types = message.get_array("resourceTypes"sv);
|
||||||
|
if (!resource_types.has_value()) {
|
||||||
|
send_missing_parameter_error("resourceTypes"sv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (DEVTOOLS_DEBUG) {
|
||||||
|
for (auto const& resource_type : resource_types->values()) {
|
||||||
|
if (!resource_type.is_string())
|
||||||
|
continue;
|
||||||
|
if (resource_type.as_string() != "console-message"sv)
|
||||||
|
dbgln("Unrecognized `watchResources` resource type: '{}'", resource_type.as_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send_message(move(response));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == "watchTargets"sv) {
|
if (type == "watchTargets"sv) {
|
||||||
auto target_type = message.get_string("targetType"sv);
|
auto target_type = message.get_string("targetType"sv);
|
||||||
if (!target_type.has_value()) {
|
if (!target_type.has_value()) {
|
||||||
|
@ -75,10 +97,11 @@ void WatcherActor::handle_message(StringView type, JsonObject const& message)
|
||||||
|
|
||||||
if (target_type == "frame"sv) {
|
if (target_type == "frame"sv) {
|
||||||
auto& css_properties = devtools().register_actor<CSSPropertiesActor>();
|
auto& css_properties = devtools().register_actor<CSSPropertiesActor>();
|
||||||
|
auto& console = devtools().register_actor<ConsoleActor>(m_tab);
|
||||||
auto& inspector = devtools().register_actor<InspectorActor>(m_tab);
|
auto& inspector = devtools().register_actor<InspectorActor>(m_tab);
|
||||||
auto& thread = devtools().register_actor<ThreadActor>();
|
auto& thread = devtools().register_actor<ThreadActor>();
|
||||||
|
|
||||||
auto& target = devtools().register_actor<FrameActor>(m_tab, css_properties, inspector, thread);
|
auto& target = devtools().register_actor<FrameActor>(m_tab, css_properties, console, inspector, thread);
|
||||||
m_target = target;
|
m_target = target;
|
||||||
|
|
||||||
response.set("type"sv, "target-available-form"sv);
|
response.set("type"sv, "target-available-form"sv);
|
||||||
|
@ -102,7 +125,7 @@ JsonObject WatcherActor::serialize_description() const
|
||||||
{
|
{
|
||||||
JsonObject resources;
|
JsonObject resources;
|
||||||
resources.set("Cache"sv, false);
|
resources.set("Cache"sv, false);
|
||||||
resources.set("console-message"sv, false);
|
resources.set("console-message"sv, true);
|
||||||
resources.set("cookies"sv, false);
|
resources.set("cookies"sv, false);
|
||||||
resources.set("css-change"sv, false);
|
resources.set("css-change"sv, false);
|
||||||
resources.set("css-message"sv, false);
|
resources.set("css-message"sv, false);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
Actor.cpp
|
Actor.cpp
|
||||||
|
Actors/ConsoleActor.cpp
|
||||||
Actors/CSSPropertiesActor.cpp
|
Actors/CSSPropertiesActor.cpp
|
||||||
Actors/DeviceActor.cpp
|
Actors/DeviceActor.cpp
|
||||||
Actors/FrameActor.cpp
|
Actors/FrameActor.cpp
|
||||||
|
|
|
@ -35,6 +35,9 @@ public:
|
||||||
|
|
||||||
virtual void highlight_dom_node(TabDescription const&, Web::UniqueNodeID, Optional<Web::CSS::Selector::PseudoElement::Type>) const { }
|
virtual void highlight_dom_node(TabDescription const&, Web::UniqueNodeID, Optional<Web::CSS::Selector::PseudoElement::Type>) const { }
|
||||||
virtual void clear_highlighted_dom_node(TabDescription const&) const { }
|
virtual void clear_highlighted_dom_node(TabDescription const&) const { }
|
||||||
|
|
||||||
|
using OnScriptEvaluationComplete = Function<void(ErrorOr<JsonValue>)>;
|
||||||
|
virtual void evaluate_javascript(TabDescription const&, String, OnScriptEvaluationComplete) const { }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace DevTools {
|
||||||
|
|
||||||
class Actor;
|
class Actor;
|
||||||
class Connection;
|
class Connection;
|
||||||
|
class ConsoleActor;
|
||||||
class CSSPropertiesActor;
|
class CSSPropertiesActor;
|
||||||
class DeviceActor;
|
class DeviceActor;
|
||||||
class DevToolsDelegate;
|
class DevToolsDelegate;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue