WebContent: Restore ability to use Inspector accessors like "$0"

We implement these built-in accessors via a lexical environment override
on the inspected document's global scope. However, ClassicScript will
parse the script we provide as a JS program, in which any evaluated
bindings will be interpreted as global bindings. Our global binding
lookup in the bytecode interpreter does not search the lexical env for
the binding, thus scripts like "$0" fail to evaluate.

Instead, we can create an ECMAScriptFunctionObject to evaluate scripts
entered into the Inspector. These are not evaluated as JS programs, and
thus any evaluated bindings are interpreted as non-global bindings. The
lexical environment override we set will then be considered.
This commit is contained in:
Timothy Flynn 2024-10-29 13:43:58 -04:00
parent e41c668435
commit ae1c58fad1

View file

@ -9,18 +9,12 @@
#include <AK/MemoryStream.h>
#include <AK/StringBuilder.h>
#include <AK/TemporaryChange.h>
#include <LibJS/MarkupGenerator.h>
#include <LibJS/Print.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/GlobalEnvironment.h>
#include <LibJS/Runtime/ObjectEnvironment.h>
#include <LibJS/Runtime/Realm.h>
#include <LibJS/Runtime/VM.h>
#include <LibWeb/HTML/PolicyContainers.h>
#include <LibWeb/HTML/Scripting/ClassicScript.h>
#include <LibWeb/HTML/Scripting/Environments.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/WebDriver/ExecuteScript.h>
#include <WebContent/ConsoleGlobalEnvironmentExtensions.h>
#include <WebContent/PageClient.h>
#include <WebContent/WebContentConsoleClient.h>
@ -51,17 +45,21 @@ void WebContentConsoleClient::handle_input(ByteString const& js_source)
if (!m_console_global_environment_extensions)
return;
auto& settings = Web::HTML::relevant_settings_object(*m_console_global_environment_extensions);
auto script = Web::HTML::ClassicScript::create("(console)", js_source, settings, settings.api_base_url());
auto& realm = m_console->realm();
auto& window = verify_cast<Web::HTML::Window>(realm.global_object());
JS::NonnullGCPtr<JS::Environment> with_scope = JS::new_object_environment(*m_console_global_environment_extensions, true, &settings.realm().global_environment());
auto source_text = ByteString::formatted("return {}", js_source);
// FIXME: Add parse error printouts back once ClassicScript can report parse errors.
auto result = script->run(Web::HTML::ClassicScript::RethrowErrors::No, with_scope);
auto completion = Web::WebDriver::execute_a_function_body(window, source_text, {}, m_console_global_environment_extensions);
if (result.value().has_value()) {
m_console_global_environment_extensions->set_most_recent_result(result.value().value());
print_html(JS::MarkupGenerator::html_from_value(*result.value()).release_value_but_fixme_should_propagate_errors().to_byte_string());
if (completion.has_value()) {
m_console_global_environment_extensions->set_most_recent_result(completion.value());
print_html(JS::MarkupGenerator::html_from_value(completion.value()).release_value_but_fixme_should_propagate_errors().to_byte_string());
} else {
m_console_global_environment_extensions->set_most_recent_result(JS::js_undefined());
if (completion.error().value().has_value())
print_html(JS::MarkupGenerator::html_from_value(completion.error().value().value()).release_value_but_fixme_should_propagate_errors().to_byte_string());
}
}