mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-07 16:49:54 +00:00
LibWeb: Implement the LegacyUnforgeable attribute
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
This fixes the frame-ancestors WPT tests from crashing when an iframe is blocked from loading. This is because it would get an undefined location.href from the cross-origin iframe, which causes a crash as it expects it to be there.
This commit is contained in:
parent
7853b757c2
commit
c7d25301d3
Notes:
github-actions[bot]
2025-03-28 00:10:01 +00:00
Author: https://github.com/Lubrsi
Commit: c7d25301d3
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3973
Reviewed-by: https://github.com/tcl3 ✅
15 changed files with 511 additions and 76 deletions
|
@ -504,7 +504,7 @@ void Parser::parse_stringifier(HashMap<ByteString, ByteString>& extended_attribu
|
||||||
interface.has_stringifier = true;
|
interface.has_stringifier = true;
|
||||||
if (lexer.next_is("attribute"sv) || lexer.next_is("inherit"sv) || lexer.next_is("readonly"sv)) {
|
if (lexer.next_is("attribute"sv) || lexer.next_is("inherit"sv) || lexer.next_is("readonly"sv)) {
|
||||||
parse_attribute(extended_attributes, interface);
|
parse_attribute(extended_attributes, interface);
|
||||||
interface.stringifier_attribute = interface.attributes.last().name;
|
interface.stringifier_attribute = interface.attributes.last();
|
||||||
} else {
|
} else {
|
||||||
assert_specific(';');
|
assert_specific(';');
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,7 +280,7 @@ public:
|
||||||
Vector<Function> functions;
|
Vector<Function> functions;
|
||||||
Vector<Function> static_functions;
|
Vector<Function> static_functions;
|
||||||
bool has_stringifier { false };
|
bool has_stringifier { false };
|
||||||
Optional<ByteString> stringifier_attribute;
|
Optional<Attribute> stringifier_attribute;
|
||||||
bool has_unscopable_member { false };
|
bool has_unscopable_member { false };
|
||||||
|
|
||||||
Optional<NonnullRefPtr<Type const>> value_iterator_type;
|
Optional<NonnullRefPtr<Type const>> value_iterator_type;
|
||||||
|
|
|
@ -483,6 +483,7 @@ void Document::initialize(JS::Realm& realm)
|
||||||
{
|
{
|
||||||
Base::initialize(realm);
|
Base::initialize(realm);
|
||||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(Document);
|
WEB_SET_PROTOTYPE_FOR_INTERFACE(Document);
|
||||||
|
Bindings::DocumentPrototype::define_unforgeable_attributes(realm, *this);
|
||||||
|
|
||||||
m_selection = realm.create<Selection::Selection>(realm, *this);
|
m_selection = realm.create<Selection::Selection>(realm, *this);
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ void Event::initialize(JS::Realm& realm)
|
||||||
{
|
{
|
||||||
Base::initialize(realm);
|
Base::initialize(realm);
|
||||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(Event);
|
WEB_SET_PROTOTYPE_FOR_INTERFACE(Event);
|
||||||
|
Bindings::EventPrototype::define_unforgeable_attributes(realm, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Event::visit_edges(Visitor& visitor)
|
void Event::visit_edges(Visitor& visitor)
|
||||||
|
|
|
@ -43,6 +43,7 @@ void Location::initialize(JS::Realm& realm)
|
||||||
{
|
{
|
||||||
Base::initialize(realm);
|
Base::initialize(realm);
|
||||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(Location);
|
WEB_SET_PROTOTYPE_FOR_INTERFACE(Location);
|
||||||
|
Bindings::LocationPrototype::define_unforgeable_attributes(realm, *this);
|
||||||
|
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
|
|
||||||
|
|
|
@ -731,6 +731,7 @@ WebIDL::ExceptionOr<void> Window::initialize_web_interfaces(Badge<WindowEnvironm
|
||||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(Window);
|
WEB_SET_PROTOTYPE_FOR_INTERFACE(Window);
|
||||||
|
|
||||||
Bindings::WindowGlobalMixin::initialize(realm, *this);
|
Bindings::WindowGlobalMixin::initialize(realm, *this);
|
||||||
|
Bindings::WindowGlobalMixin::define_unforgeable_attributes(realm, *this);
|
||||||
WindowOrWorkerGlobalScopeMixin::initialize(realm);
|
WindowOrWorkerGlobalScopeMixin::initialize(realm);
|
||||||
|
|
||||||
if (s_internals_object_exposed)
|
if (s_internals_object_exposed)
|
||||||
|
|
|
@ -3338,8 +3338,12 @@ void @named_properties_class@::visit_edges(Visitor& visitor)
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webidl.spec.whatwg.org/#interface-prototype-object
|
enum class GenerateUnforgeables {
|
||||||
static void generate_prototype_or_global_mixin_definitions(IDL::Interface const& interface, StringBuilder& builder)
|
No,
|
||||||
|
Yes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void generate_prototype_or_global_mixin_initialization(IDL::Interface const& interface, StringBuilder& builder, GenerateUnforgeables generate_unforgeables)
|
||||||
{
|
{
|
||||||
SourceGenerator generator { builder };
|
SourceGenerator generator { builder };
|
||||||
|
|
||||||
|
@ -3357,15 +3361,27 @@ static void generate_prototype_or_global_mixin_definitions(IDL::Interface const&
|
||||||
generator.set("iterator_name", ByteString::formatted("{}Iterator", interface.name));
|
generator.set("iterator_name", ByteString::formatted("{}Iterator", interface.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_global_interface) {
|
bool define_on_existing_object = is_global_interface || generate_unforgeables == GenerateUnforgeables::Yes;
|
||||||
generator.set("named_properties_class", ByteString::formatted("{}Properties", interface.name));
|
|
||||||
// Doing this with macros is not super nice, but simplifies codegen a lot.
|
|
||||||
generator.append(R"~~~(
|
|
||||||
#define define_direct_property (object.define_direct_property)
|
|
||||||
#define define_native_accessor (object.define_native_accessor)
|
|
||||||
#define define_native_function (object.define_native_function)
|
|
||||||
#define set_prototype (object.set_prototype)
|
|
||||||
|
|
||||||
|
if (define_on_existing_object) {
|
||||||
|
generator.set("define_direct_property", "object.define_direct_property");
|
||||||
|
generator.set("define_native_accessor", "object.define_native_accessor");
|
||||||
|
generator.set("define_native_function", "object.define_native_function");
|
||||||
|
generator.set("set_prototype", "object.set_prototype");
|
||||||
|
} else {
|
||||||
|
generator.set("define_direct_property", "define_direct_property");
|
||||||
|
generator.set("define_native_accessor", "define_native_accessor");
|
||||||
|
generator.set("define_native_function", "define_native_function");
|
||||||
|
generator.set("set_prototype", "set_prototype");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generate_unforgeables == GenerateUnforgeables::Yes) {
|
||||||
|
generator.append(R"~~~(
|
||||||
|
void @class_name@::define_unforgeable_attributes(JS::Realm& realm, [[maybe_unused]] JS::Object& object)
|
||||||
|
{
|
||||||
|
)~~~");
|
||||||
|
} else if (is_global_interface) {
|
||||||
|
generator.append(R"~~~(
|
||||||
void @class_name@::initialize(JS::Realm& realm, JS::Object& object)
|
void @class_name@::initialize(JS::Realm& realm, JS::Object& object)
|
||||||
{
|
{
|
||||||
)~~~");
|
)~~~");
|
||||||
|
@ -3376,38 +3392,49 @@ void @class_name@::initialize(JS::Realm& realm)
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Currently almost everything gets default_attributes but it should be configurable per attribute.
|
|
||||||
// See the spec links for details
|
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
|
|
||||||
[[maybe_unused]] auto& vm = realm.vm();
|
[[maybe_unused]] auto& vm = realm.vm();
|
||||||
|
|
||||||
|
)~~~");
|
||||||
|
|
||||||
|
// FIXME: Currently almost everything gets default_attributes but it should be configurable per attribute.
|
||||||
|
// See the spec links for details
|
||||||
|
if (generate_unforgeables == GenerateUnforgeables::No) {
|
||||||
|
generator.append(R"~~~(
|
||||||
[[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable | JS::Attribute::Writable;
|
[[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable | JS::Attribute::Writable;
|
||||||
|
|
||||||
)~~~");
|
|
||||||
|
|
||||||
if (interface.name == "DOMException"sv) {
|
|
||||||
generator.append(R"~~~(
|
|
||||||
|
|
||||||
set_prototype(realm.intrinsics().error_prototype());
|
|
||||||
)~~~");
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (interface.prototype_base_class == "ObjectPrototype") {
|
|
||||||
generator.append(R"~~~(
|
|
||||||
|
|
||||||
set_prototype(realm.intrinsics().object_prototype());
|
|
||||||
|
|
||||||
)~~~");
|
|
||||||
} else if (is_global_interface) {
|
|
||||||
generator.append(R"~~~(
|
|
||||||
set_prototype(&ensure_web_prototype<@prototype_name@>(realm, "@name@"_fly_string));
|
|
||||||
)~~~");
|
)~~~");
|
||||||
} else {
|
} else {
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
|
[[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable;
|
||||||
|
)~~~");
|
||||||
|
}
|
||||||
|
|
||||||
set_prototype(&ensure_web_prototype<@prototype_base_class@>(realm, "@parent_name@"_fly_string));
|
if (generate_unforgeables == GenerateUnforgeables::No) {
|
||||||
|
if (interface.name == "DOMException"sv) {
|
||||||
|
generator.append(R"~~~(
|
||||||
|
|
||||||
|
@set_prototype@(realm.intrinsics().error_prototype());
|
||||||
|
)~~~");
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (interface.prototype_base_class == "ObjectPrototype") {
|
||||||
|
generator.append(R"~~~(
|
||||||
|
|
||||||
|
@set_prototype@(realm.intrinsics().object_prototype());
|
||||||
|
|
||||||
)~~~");
|
)~~~");
|
||||||
|
} else if (is_global_interface) {
|
||||||
|
generator.append(R"~~~(
|
||||||
|
@set_prototype@(&ensure_web_prototype<@prototype_name@>(realm, "@name@"_fly_string));
|
||||||
|
)~~~");
|
||||||
|
} else {
|
||||||
|
generator.append(R"~~~(
|
||||||
|
|
||||||
|
@set_prototype@(&ensure_web_prototype<@prototype_base_class@>(realm, "@parent_name@"_fly_string));
|
||||||
|
|
||||||
|
)~~~");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interface.has_unscopable_member) {
|
if (interface.has_unscopable_member) {
|
||||||
|
@ -3418,11 +3445,15 @@ void @class_name@::initialize(JS::Realm& realm)
|
||||||
|
|
||||||
// https://webidl.spec.whatwg.org/#es-attributes
|
// https://webidl.spec.whatwg.org/#es-attributes
|
||||||
for (auto& attribute : interface.attributes) {
|
for (auto& attribute : interface.attributes) {
|
||||||
|
bool has_unforgeable_attribute = attribute.extended_attributes.contains("LegacyUnforgeable"sv);
|
||||||
|
if ((generate_unforgeables == GenerateUnforgeables::Yes && !has_unforgeable_attribute) || (generate_unforgeables == GenerateUnforgeables::No && has_unforgeable_attribute))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (attribute.extended_attributes.contains("FIXME")) {
|
if (attribute.extended_attributes.contains("FIXME")) {
|
||||||
auto fixme_attribute_generator = generator.fork();
|
auto fixme_attribute_generator = generator.fork();
|
||||||
fixme_attribute_generator.set("attribute.name", attribute.name);
|
fixme_attribute_generator.set("attribute.name", attribute.name);
|
||||||
fixme_attribute_generator.append(R"~~~(
|
fixme_attribute_generator.append(R"~~~(
|
||||||
define_direct_property("@attribute.name@"_fly_string, JS::js_undefined(), default_attributes | JS::Attribute::Unimplemented);
|
@define_direct_property@("@attribute.name@"_fly_string, JS::js_undefined(), default_attributes | JS::Attribute::Unimplemented);
|
||||||
)~~~");
|
)~~~");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -3443,36 +3474,47 @@ void @class_name@::initialize(JS::Realm& realm)
|
||||||
}
|
}
|
||||||
|
|
||||||
attribute_generator.append(R"~~~(
|
attribute_generator.append(R"~~~(
|
||||||
define_native_accessor(realm, "@attribute.name@"_fly_string, @attribute.getter_callback@, @attribute.setter_callback@, default_attributes);
|
@define_native_accessor@(realm, "@attribute.name@"_fly_string, @attribute.getter_callback@, @attribute.setter_callback@, default_attributes);
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& function : interface.functions) {
|
for (auto& function : interface.functions) {
|
||||||
|
bool has_unforgeable_attribute = function.extended_attributes.contains("LegacyUnforgeable"sv);
|
||||||
|
if ((generate_unforgeables == GenerateUnforgeables::Yes && !has_unforgeable_attribute) || (generate_unforgeables == GenerateUnforgeables::No && has_unforgeable_attribute))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (function.extended_attributes.contains("FIXME")) {
|
if (function.extended_attributes.contains("FIXME")) {
|
||||||
auto fixme_function_generator = generator.fork();
|
auto fixme_function_generator = generator.fork();
|
||||||
fixme_function_generator.set("function.name", function.name);
|
fixme_function_generator.set("function.name", function.name);
|
||||||
fixme_function_generator.append(R"~~~(
|
fixme_function_generator.append(R"~~~(
|
||||||
define_direct_property("@function.name@"_fly_string, JS::js_undefined(), default_attributes | JS::Attribute::Unimplemented);
|
@define_direct_property@("@function.name@"_fly_string, JS::js_undefined(), default_attributes | JS::Attribute::Unimplemented);
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webidl.spec.whatwg.org/#es-constants
|
// https://webidl.spec.whatwg.org/#es-constants
|
||||||
for (auto& constant : interface.constants) {
|
if (generate_unforgeables == GenerateUnforgeables::No) {
|
||||||
// FIXME: Do constants need to be added to the unscopable list?
|
for (auto& constant : interface.constants) {
|
||||||
|
// FIXME: Do constants need to be added to the unscopable list?
|
||||||
|
|
||||||
auto constant_generator = generator.fork();
|
auto constant_generator = generator.fork();
|
||||||
constant_generator.set("constant.name", constant.name);
|
constant_generator.set("constant.name", constant.name);
|
||||||
|
|
||||||
generate_wrap_statement(constant_generator, constant.value, constant.type, interface, ByteString::formatted("auto constant_{}_value =", constant.name));
|
generate_wrap_statement(constant_generator, constant.value, constant.type, interface, ByteString::formatted("auto constant_{}_value =", constant.name));
|
||||||
|
|
||||||
constant_generator.append(R"~~~(
|
constant_generator.append(R"~~~(
|
||||||
define_direct_property("@constant.name@"_fly_string, constant_@constant.name@_value, JS::Attribute::Enumerable);
|
@define_direct_property@("@constant.name@"_fly_string, constant_@constant.name@_value, JS::Attribute::Enumerable);
|
||||||
)~~~");
|
)~~~");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webidl.spec.whatwg.org/#es-operations
|
// https://webidl.spec.whatwg.org/#es-operations
|
||||||
for (auto const& overload_set : interface.overload_sets) {
|
for (auto const& overload_set : interface.overload_sets) {
|
||||||
|
// NOTE: This assumes that every function in the overload set has the same attribute set.
|
||||||
|
bool has_unforgeable_attribute = any_of(overload_set.value, [](auto const& function) { return function.extended_attributes.contains("LegacyUnforgeable"); });
|
||||||
|
if ((generate_unforgeables == GenerateUnforgeables::Yes && !has_unforgeable_attribute) || (generate_unforgeables == GenerateUnforgeables::No && has_unforgeable_attribute))
|
||||||
|
continue;
|
||||||
|
|
||||||
auto function_generator = generator.fork();
|
auto function_generator = generator.fork();
|
||||||
function_generator.set("function.name", overload_set.key);
|
function_generator.set("function.name", overload_set.key);
|
||||||
function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
|
function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
|
||||||
|
@ -3486,95 +3528,103 @@ void @class_name@::initialize(JS::Realm& realm)
|
||||||
}
|
}
|
||||||
|
|
||||||
function_generator.append(R"~~~(
|
function_generator.append(R"~~~(
|
||||||
define_native_function(realm, "@function.name@"_fly_string, @function.name:snakecase@, @function.length@, default_attributes);
|
@define_native_function@(realm, "@function.name@"_fly_string, @function.name:snakecase@, @function.length@, default_attributes);
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interface.has_stringifier) {
|
bool should_generate_stringifier = true;
|
||||||
// FIXME: Do stringifiers need to be added to the unscopable list?
|
if (interface.stringifier_attribute.has_value()) {
|
||||||
|
bool has_unforgeable_attribute = interface.stringifier_attribute.value().extended_attributes.contains("LegacyUnforgeable"sv);
|
||||||
|
if ((generate_unforgeables == GenerateUnforgeables::Yes && !has_unforgeable_attribute) || (generate_unforgeables == GenerateUnforgeables::No && has_unforgeable_attribute))
|
||||||
|
should_generate_stringifier = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interface.has_stringifier && should_generate_stringifier) {
|
||||||
|
// FIXME: Do stringifiers need to be added to the unscopable list?
|
||||||
auto stringifier_generator = generator.fork();
|
auto stringifier_generator = generator.fork();
|
||||||
stringifier_generator.append(R"~~~(
|
stringifier_generator.append(R"~~~(
|
||||||
define_native_function(realm, "toString"_fly_string, to_string, 0, default_attributes);
|
@define_native_function@(realm, "toString"_fly_string, to_string, 0, default_attributes);
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webidl.spec.whatwg.org/#define-the-iteration-methods
|
// https://webidl.spec.whatwg.org/#define-the-iteration-methods
|
||||||
// This applies to this if block and the following if block.
|
// This applies to this if block and the following if block.
|
||||||
if (interface.indexed_property_getter.has_value()) {
|
if (interface.indexed_property_getter.has_value() && generate_unforgeables == GenerateUnforgeables::No) {
|
||||||
auto iterator_generator = generator.fork();
|
auto iterator_generator = generator.fork();
|
||||||
iterator_generator.append(R"~~~(
|
iterator_generator.append(R"~~~(
|
||||||
define_direct_property(vm.well_known_symbol_iterator(), realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.values), JS::Attribute::Configurable | JS::Attribute::Writable);
|
@define_direct_property@(vm.well_known_symbol_iterator(), realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.values), JS::Attribute::Configurable | JS::Attribute::Writable);
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
if (interface.value_iterator_type.has_value()) {
|
if (interface.value_iterator_type.has_value()) {
|
||||||
iterator_generator.append(R"~~~(
|
iterator_generator.append(R"~~~(
|
||||||
define_direct_property(vm.names.entries, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.entries), default_attributes);
|
@define_direct_property@(vm.names.entries, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.entries), default_attributes);
|
||||||
define_direct_property(vm.names.keys, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.keys), default_attributes);
|
@define_direct_property@(vm.names.keys, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.keys), default_attributes);
|
||||||
define_direct_property(vm.names.values, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.values), default_attributes);
|
@define_direct_property@(vm.names.values, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.values), default_attributes);
|
||||||
define_direct_property(vm.names.forEach, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.forEach), default_attributes);
|
@define_direct_property@(vm.names.forEach, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.forEach), default_attributes);
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interface.pair_iterator_types.has_value()) {
|
if (interface.pair_iterator_types.has_value() && generate_unforgeables == GenerateUnforgeables::No) {
|
||||||
// FIXME: Do pair iterators need to be added to the unscopable list?
|
// FIXME: Do pair iterators need to be added to the unscopable list?
|
||||||
|
|
||||||
auto iterator_generator = generator.fork();
|
auto iterator_generator = generator.fork();
|
||||||
iterator_generator.append(R"~~~(
|
iterator_generator.append(R"~~~(
|
||||||
define_native_function(realm, vm.names.entries, entries, 0, default_attributes);
|
@define_native_function@(realm, vm.names.entries, entries, 0, default_attributes);
|
||||||
define_native_function(realm, vm.names.forEach, for_each, 1, default_attributes);
|
@define_native_function@(realm, vm.names.forEach, for_each, 1, default_attributes);
|
||||||
define_native_function(realm, vm.names.keys, keys, 0, default_attributes);
|
@define_native_function@(realm, vm.names.keys, keys, 0, default_attributes);
|
||||||
define_native_function(realm, vm.names.values, values, 0, default_attributes);
|
@define_native_function@(realm, vm.names.values, values, 0, default_attributes);
|
||||||
|
|
||||||
define_direct_property(vm.well_known_symbol_iterator(), get_without_side_effects(vm.names.entries), JS::Attribute::Configurable | JS::Attribute::Writable);
|
@define_direct_property@(vm.well_known_symbol_iterator(), get_without_side_effects(vm.names.entries), JS::Attribute::Configurable | JS::Attribute::Writable);
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webidl.spec.whatwg.org/#js-setlike
|
// https://webidl.spec.whatwg.org/#js-setlike
|
||||||
if (interface.set_entry_type.has_value()) {
|
if (interface.set_entry_type.has_value() && generate_unforgeables == GenerateUnforgeables::No) {
|
||||||
|
|
||||||
auto setlike_generator = generator.fork();
|
auto setlike_generator = generator.fork();
|
||||||
|
|
||||||
setlike_generator.append(R"~~~(
|
setlike_generator.append(R"~~~(
|
||||||
define_native_accessor(realm, vm.names.size, get_size, nullptr, JS::Attribute::Enumerable | JS::Attribute::Configurable);
|
@define_native_accessor@(realm, vm.names.size, get_size, nullptr, JS::Attribute::Enumerable | JS::Attribute::Configurable);
|
||||||
define_native_function(realm, vm.names.entries, entries, 0, default_attributes);
|
@define_native_function@(realm, vm.names.entries, entries, 0, default_attributes);
|
||||||
// NOTE: Keys intentionally returns values for setlike
|
// NOTE: Keys intentionally returns values for setlike
|
||||||
define_native_function(realm, vm.names.keys, values, 0, default_attributes);
|
@define_native_function@(realm, vm.names.keys, values, 0, default_attributes);
|
||||||
define_native_function(realm, vm.names.values, values, 0, default_attributes);
|
@define_native_function@(realm, vm.names.values, values, 0, default_attributes);
|
||||||
define_direct_property(vm.well_known_symbol_iterator(), get_without_side_effects(vm.names.values), JS::Attribute::Configurable | JS::Attribute::Writable);
|
@define_direct_property@(vm.well_known_symbol_iterator(), get_without_side_effects(vm.names.values), JS::Attribute::Configurable | JS::Attribute::Writable);
|
||||||
define_native_function(realm, vm.names.forEach, for_each, 1, default_attributes);
|
@define_native_function@(realm, vm.names.forEach, for_each, 1, default_attributes);
|
||||||
define_native_function(realm, vm.names.has, has, 1, default_attributes);
|
@define_native_function@(realm, vm.names.has, has, 1, default_attributes);
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
if (!interface.overload_sets.contains("add"sv) && !interface.is_set_readonly) {
|
if (!interface.overload_sets.contains("add"sv) && !interface.is_set_readonly) {
|
||||||
setlike_generator.append(R"~~~(
|
setlike_generator.append(R"~~~(
|
||||||
define_native_function(realm, vm.names.add, add, 1, default_attributes);
|
@define_native_function@(realm, vm.names.add, add, 1, default_attributes);
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
if (!interface.overload_sets.contains("delete"sv) && !interface.is_set_readonly) {
|
if (!interface.overload_sets.contains("delete"sv) && !interface.is_set_readonly) {
|
||||||
setlike_generator.append(R"~~~(
|
setlike_generator.append(R"~~~(
|
||||||
define_native_function(realm, vm.names.delete_, delete_, 1, default_attributes);
|
@define_native_function@(realm, vm.names.delete_, delete_, 1, default_attributes);
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
if (!interface.overload_sets.contains("clear"sv) && !interface.is_set_readonly) {
|
if (!interface.overload_sets.contains("clear"sv) && !interface.is_set_readonly) {
|
||||||
setlike_generator.append(R"~~~(
|
setlike_generator.append(R"~~~(
|
||||||
define_native_function(realm, vm.names.clear, clear, 0, default_attributes);
|
@define_native_function@(realm, vm.names.clear, clear, 0, default_attributes);
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interface.has_unscopable_member) {
|
if (interface.has_unscopable_member) {
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
define_direct_property(vm.well_known_symbol_unscopables(), unscopable_object, JS::Attribute::Configurable);
|
@define_direct_property@(vm.well_known_symbol_unscopables(), unscopable_object, JS::Attribute::Configurable);
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.append(R"~~~(
|
if (generate_unforgeables == GenerateUnforgeables::No) {
|
||||||
define_direct_property(vm.well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm, "@namespaced_name@"_string), JS::Attribute::Configurable);
|
generator.append(R"~~~(
|
||||||
|
@define_direct_property@(vm.well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm, "@namespaced_name@"_string), JS::Attribute::Configurable);
|
||||||
)~~~");
|
)~~~");
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_global_interface) {
|
if (!define_on_existing_object) {
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
Base::initialize(realm);
|
Base::initialize(realm);
|
||||||
)~~~");
|
)~~~");
|
||||||
|
@ -3583,6 +3633,26 @@ void @class_name@::initialize(JS::Realm& realm)
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
}
|
}
|
||||||
)~~~");
|
)~~~");
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://webidl.spec.whatwg.org/#interface-prototype-object
|
||||||
|
static void generate_prototype_or_global_mixin_definitions(IDL::Interface const& interface, StringBuilder& builder)
|
||||||
|
{
|
||||||
|
SourceGenerator generator { builder };
|
||||||
|
|
||||||
|
auto is_global_interface = interface.extended_attributes.contains("Global");
|
||||||
|
auto class_name = is_global_interface ? interface.global_mixin_class : interface.prototype_class;
|
||||||
|
generator.set("name", interface.name);
|
||||||
|
generator.set("namespaced_name", interface.namespaced_name);
|
||||||
|
generator.set("class_name", class_name);
|
||||||
|
generator.set("fully_qualified_name", interface.fully_qualified_name);
|
||||||
|
generator.set("parent_name", interface.parent_name);
|
||||||
|
generator.set("prototype_base_class", interface.prototype_base_class);
|
||||||
|
generator.set("prototype_name", interface.prototype_class); // Used for Global Mixin
|
||||||
|
|
||||||
|
if (interface.pair_iterator_types.has_value()) {
|
||||||
|
generator.set("iterator_name", ByteString::formatted("{}Iterator", interface.name));
|
||||||
|
}
|
||||||
|
|
||||||
if (!interface.attributes.is_empty() || !interface.functions.is_empty() || interface.has_stringifier) {
|
if (!interface.attributes.is_empty() || !interface.functions.is_empty() || interface.has_stringifier) {
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
|
@ -4214,7 +4284,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
|
||||||
auto stringifier_generator = generator.fork();
|
auto stringifier_generator = generator.fork();
|
||||||
stringifier_generator.set("class_name", class_name);
|
stringifier_generator.set("class_name", class_name);
|
||||||
if (interface.stringifier_attribute.has_value())
|
if (interface.stringifier_attribute.has_value())
|
||||||
stringifier_generator.set("attribute.cpp_getter_name", interface.stringifier_attribute->to_snakecase());
|
stringifier_generator.set("attribute.cpp_getter_name", interface.stringifier_attribute.value().name.to_snakecase());
|
||||||
|
|
||||||
stringifier_generator.append(R"~~~(
|
stringifier_generator.append(R"~~~(
|
||||||
JS_DEFINE_NATIVE_FUNCTION(@class_name@::to_string)
|
JS_DEFINE_NATIVE_FUNCTION(@class_name@::to_string)
|
||||||
|
@ -4955,6 +5025,8 @@ class @prototype_class@ : public JS::Object {
|
||||||
JS_OBJECT(@prototype_class@, JS::Object);
|
JS_OBJECT(@prototype_class@, JS::Object);
|
||||||
GC_DECLARE_ALLOCATOR(@prototype_class@);
|
GC_DECLARE_ALLOCATOR(@prototype_class@);
|
||||||
public:
|
public:
|
||||||
|
static void define_unforgeable_attributes(JS::Realm&, JS::Object&);
|
||||||
|
|
||||||
explicit @prototype_class@(JS::Realm&);
|
explicit @prototype_class@(JS::Realm&);
|
||||||
virtual void initialize(JS::Realm&) override;
|
virtual void initialize(JS::Realm&) override;
|
||||||
virtual ~@prototype_class@() override;
|
virtual ~@prototype_class@() override;
|
||||||
|
@ -5124,6 +5196,8 @@ void @prototype_class@::initialize(JS::Realm& realm)
|
||||||
if (interface.supports_named_properties())
|
if (interface.supports_named_properties())
|
||||||
generate_named_properties_object_definitions(interface, builder);
|
generate_named_properties_object_definitions(interface, builder);
|
||||||
} else {
|
} else {
|
||||||
|
generate_prototype_or_global_mixin_initialization(interface, builder, GenerateUnforgeables::No);
|
||||||
|
generate_prototype_or_global_mixin_initialization(interface, builder, GenerateUnforgeables::Yes);
|
||||||
generate_prototype_or_global_mixin_definitions(interface, builder);
|
generate_prototype_or_global_mixin_definitions(interface, builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5250,6 +5324,7 @@ namespace Web::Bindings {
|
||||||
class @class_name@ {
|
class @class_name@ {
|
||||||
public:
|
public:
|
||||||
void initialize(JS::Realm&, JS::Object&);
|
void initialize(JS::Realm&, JS::Object&);
|
||||||
|
void define_unforgeable_attributes(JS::Realm&, JS::Object&);
|
||||||
@class_name@();
|
@class_name@();
|
||||||
virtual ~@class_name@();
|
virtual ~@class_name@();
|
||||||
|
|
||||||
|
@ -5313,6 +5388,8 @@ namespace Web::Bindings {
|
||||||
@class_name@::~@class_name@() = default;
|
@class_name@::~@class_name@() = default;
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
|
generate_prototype_or_global_mixin_initialization(interface, builder, GenerateUnforgeables::No);
|
||||||
|
generate_prototype_or_global_mixin_initialization(interface, builder, GenerateUnforgeables::Yes);
|
||||||
generate_prototype_or_global_mixin_definitions(interface, builder);
|
generate_prototype_or_global_mixin_definitions(interface, builder);
|
||||||
|
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
location exists on document itself: true
|
||||||
|
location does not exist on LocationPrototype: true
|
||||||
|
location descriptor is not undefined: true
|
||||||
|
location enumerable: true
|
||||||
|
location configurable: false
|
||||||
|
location writable: undefined
|
||||||
|
location exists on document itself: true
|
||||||
|
location does not exist on LocationPrototype: true
|
||||||
|
location descriptor is not undefined: true
|
||||||
|
location enumerable: true
|
||||||
|
location configurable: false
|
||||||
|
location writable: undefined
|
||||||
|
location exists on document itself: true
|
||||||
|
location does not exist on LocationPrototype: true
|
||||||
|
location descriptor is not undefined: true
|
||||||
|
location enumerable: true
|
||||||
|
location configurable: false
|
||||||
|
location writable: undefined
|
||||||
|
location exists on document itself: true
|
||||||
|
location does not exist on LocationPrototype: true
|
||||||
|
location descriptor is not undefined: true
|
||||||
|
location enumerable: true
|
||||||
|
location configurable: false
|
||||||
|
location writable: undefined
|
||||||
|
location exists on document itself: true
|
||||||
|
location does not exist on LocationPrototype: true
|
||||||
|
location descriptor is not undefined: true
|
||||||
|
location enumerable: true
|
||||||
|
location configurable: false
|
||||||
|
location writable: undefined
|
||||||
|
location exists on document itself: true
|
||||||
|
location does not exist on LocationPrototype: true
|
||||||
|
location descriptor is not undefined: true
|
||||||
|
location enumerable: true
|
||||||
|
location configurable: false
|
||||||
|
location writable: undefined
|
|
@ -0,0 +1,18 @@
|
||||||
|
isTrusted exists on Event instance itself: true
|
||||||
|
isTrusted does not exist on LocationPrototype: true
|
||||||
|
isTrusted descriptor is not undefined: true
|
||||||
|
isTrusted enumerable: true
|
||||||
|
isTrusted configurable: false
|
||||||
|
isTrusted writable: undefined
|
||||||
|
isTrusted exists on UIEvent instance itself: true
|
||||||
|
isTrusted does not exist on LocationPrototype: true
|
||||||
|
isTrusted descriptor is not undefined: true
|
||||||
|
isTrusted enumerable: true
|
||||||
|
isTrusted configurable: false
|
||||||
|
isTrusted writable: undefined
|
||||||
|
isTrusted exists on CustomEvent instance itself: true
|
||||||
|
isTrusted does not exist on LocationPrototype: true
|
||||||
|
isTrusted descriptor is not undefined: true
|
||||||
|
isTrusted enumerable: true
|
||||||
|
isTrusted configurable: false
|
||||||
|
isTrusted writable: undefined
|
|
@ -0,0 +1,156 @@
|
||||||
|
href exists on location itself: true
|
||||||
|
href does not exist on LocationPrototype: true
|
||||||
|
href descriptor is not undefined: true
|
||||||
|
href enumerable: true
|
||||||
|
href configurable: true
|
||||||
|
href writable: undefined
|
||||||
|
origin exists on location itself: true
|
||||||
|
origin does not exist on LocationPrototype: true
|
||||||
|
origin descriptor is not undefined: true
|
||||||
|
origin enumerable: true
|
||||||
|
origin configurable: true
|
||||||
|
origin writable: undefined
|
||||||
|
protocol exists on location itself: true
|
||||||
|
protocol does not exist on LocationPrototype: true
|
||||||
|
protocol descriptor is not undefined: true
|
||||||
|
protocol enumerable: true
|
||||||
|
protocol configurable: true
|
||||||
|
protocol writable: undefined
|
||||||
|
host exists on location itself: true
|
||||||
|
host does not exist on LocationPrototype: true
|
||||||
|
host descriptor is not undefined: true
|
||||||
|
host enumerable: true
|
||||||
|
host configurable: true
|
||||||
|
host writable: undefined
|
||||||
|
hostname exists on location itself: true
|
||||||
|
hostname does not exist on LocationPrototype: true
|
||||||
|
hostname descriptor is not undefined: true
|
||||||
|
hostname enumerable: true
|
||||||
|
hostname configurable: true
|
||||||
|
hostname writable: undefined
|
||||||
|
port exists on location itself: true
|
||||||
|
port does not exist on LocationPrototype: true
|
||||||
|
port descriptor is not undefined: true
|
||||||
|
port enumerable: true
|
||||||
|
port configurable: true
|
||||||
|
port writable: undefined
|
||||||
|
pathname exists on location itself: true
|
||||||
|
pathname does not exist on LocationPrototype: true
|
||||||
|
pathname descriptor is not undefined: true
|
||||||
|
pathname enumerable: true
|
||||||
|
pathname configurable: true
|
||||||
|
pathname writable: undefined
|
||||||
|
search exists on location itself: true
|
||||||
|
search does not exist on LocationPrototype: true
|
||||||
|
search descriptor is not undefined: true
|
||||||
|
search enumerable: true
|
||||||
|
search configurable: true
|
||||||
|
search writable: undefined
|
||||||
|
hash exists on location itself: true
|
||||||
|
hash does not exist on LocationPrototype: true
|
||||||
|
hash descriptor is not undefined: true
|
||||||
|
hash enumerable: true
|
||||||
|
hash configurable: true
|
||||||
|
hash writable: undefined
|
||||||
|
assign exists on location itself: true
|
||||||
|
assign does not exist on LocationPrototype: true
|
||||||
|
assign descriptor is not undefined: true
|
||||||
|
assign enumerable: true
|
||||||
|
assign configurable: true
|
||||||
|
assign writable: false
|
||||||
|
replace exists on location itself: true
|
||||||
|
replace does not exist on LocationPrototype: true
|
||||||
|
replace descriptor is not undefined: true
|
||||||
|
replace enumerable: true
|
||||||
|
replace configurable: true
|
||||||
|
replace writable: false
|
||||||
|
reload exists on location itself: true
|
||||||
|
reload does not exist on LocationPrototype: true
|
||||||
|
reload descriptor is not undefined: true
|
||||||
|
reload enumerable: true
|
||||||
|
reload configurable: true
|
||||||
|
reload writable: false
|
||||||
|
toString exists on location itself: true
|
||||||
|
toString does not exist on LocationPrototype: true
|
||||||
|
toString descriptor is not undefined: true
|
||||||
|
toString enumerable: true
|
||||||
|
toString configurable: true
|
||||||
|
toString writable: false
|
||||||
|
href exists on document.location itself: true
|
||||||
|
href does not exist on LocationPrototype: true
|
||||||
|
href descriptor is not undefined: true
|
||||||
|
href enumerable: true
|
||||||
|
href configurable: true
|
||||||
|
href writable: undefined
|
||||||
|
origin exists on document.location itself: true
|
||||||
|
origin does not exist on LocationPrototype: true
|
||||||
|
origin descriptor is not undefined: true
|
||||||
|
origin enumerable: true
|
||||||
|
origin configurable: true
|
||||||
|
origin writable: undefined
|
||||||
|
protocol exists on document.location itself: true
|
||||||
|
protocol does not exist on LocationPrototype: true
|
||||||
|
protocol descriptor is not undefined: true
|
||||||
|
protocol enumerable: true
|
||||||
|
protocol configurable: true
|
||||||
|
protocol writable: undefined
|
||||||
|
host exists on document.location itself: true
|
||||||
|
host does not exist on LocationPrototype: true
|
||||||
|
host descriptor is not undefined: true
|
||||||
|
host enumerable: true
|
||||||
|
host configurable: true
|
||||||
|
host writable: undefined
|
||||||
|
hostname exists on document.location itself: true
|
||||||
|
hostname does not exist on LocationPrototype: true
|
||||||
|
hostname descriptor is not undefined: true
|
||||||
|
hostname enumerable: true
|
||||||
|
hostname configurable: true
|
||||||
|
hostname writable: undefined
|
||||||
|
port exists on document.location itself: true
|
||||||
|
port does not exist on LocationPrototype: true
|
||||||
|
port descriptor is not undefined: true
|
||||||
|
port enumerable: true
|
||||||
|
port configurable: true
|
||||||
|
port writable: undefined
|
||||||
|
pathname exists on document.location itself: true
|
||||||
|
pathname does not exist on LocationPrototype: true
|
||||||
|
pathname descriptor is not undefined: true
|
||||||
|
pathname enumerable: true
|
||||||
|
pathname configurable: true
|
||||||
|
pathname writable: undefined
|
||||||
|
search exists on document.location itself: true
|
||||||
|
search does not exist on LocationPrototype: true
|
||||||
|
search descriptor is not undefined: true
|
||||||
|
search enumerable: true
|
||||||
|
search configurable: true
|
||||||
|
search writable: undefined
|
||||||
|
hash exists on document.location itself: true
|
||||||
|
hash does not exist on LocationPrototype: true
|
||||||
|
hash descriptor is not undefined: true
|
||||||
|
hash enumerable: true
|
||||||
|
hash configurable: true
|
||||||
|
hash writable: undefined
|
||||||
|
assign exists on document.location itself: true
|
||||||
|
assign does not exist on LocationPrototype: true
|
||||||
|
assign descriptor is not undefined: true
|
||||||
|
assign enumerable: true
|
||||||
|
assign configurable: true
|
||||||
|
assign writable: false
|
||||||
|
replace exists on document.location itself: true
|
||||||
|
replace does not exist on LocationPrototype: true
|
||||||
|
replace descriptor is not undefined: true
|
||||||
|
replace enumerable: true
|
||||||
|
replace configurable: true
|
||||||
|
replace writable: false
|
||||||
|
reload exists on document.location itself: true
|
||||||
|
reload does not exist on LocationPrototype: true
|
||||||
|
reload descriptor is not undefined: true
|
||||||
|
reload enumerable: true
|
||||||
|
reload configurable: true
|
||||||
|
reload writable: false
|
||||||
|
toString exists on document.location itself: true
|
||||||
|
toString does not exist on LocationPrototype: true
|
||||||
|
toString descriptor is not undefined: true
|
||||||
|
toString enumerable: true
|
||||||
|
toString configurable: true
|
||||||
|
toString writable: false
|
|
@ -0,0 +1,24 @@
|
||||||
|
window exists on window itself: true
|
||||||
|
window does not exist on LocationPrototype: true
|
||||||
|
window descriptor is not undefined: true
|
||||||
|
window enumerable: true
|
||||||
|
window configurable: false
|
||||||
|
window writable: undefined
|
||||||
|
document exists on window itself: true
|
||||||
|
document does not exist on LocationPrototype: true
|
||||||
|
document descriptor is not undefined: true
|
||||||
|
document enumerable: true
|
||||||
|
document configurable: false
|
||||||
|
document writable: undefined
|
||||||
|
location exists on window itself: true
|
||||||
|
location does not exist on LocationPrototype: true
|
||||||
|
location descriptor is not undefined: true
|
||||||
|
location enumerable: true
|
||||||
|
location configurable: false
|
||||||
|
location writable: undefined
|
||||||
|
top exists on window itself: true
|
||||||
|
top does not exist on LocationPrototype: true
|
||||||
|
top descriptor is not undefined: true
|
||||||
|
top enumerable: true
|
||||||
|
top configurable: false
|
||||||
|
top writable: undefined
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
const unforgeableProperties = [
|
||||||
|
"location",
|
||||||
|
];
|
||||||
|
|
||||||
|
const documents = [
|
||||||
|
document,
|
||||||
|
new Document(),
|
||||||
|
document.implementation.createDocument("http://www.w3.org/1999/xhtml", null, null),
|
||||||
|
document.implementation.createDocument("http://www.w3.org/2000/svg", null, null),
|
||||||
|
document.implementation.createDocument(null, null, null),
|
||||||
|
document.implementation.createHTMLDocument(),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const document of documents) {
|
||||||
|
const documentPrototype = Object.getPrototypeOf(document);
|
||||||
|
|
||||||
|
for (const property of unforgeableProperties) {
|
||||||
|
println(`${property} exists on document itself: ${Object.hasOwn(document, property)}`);
|
||||||
|
println(`${property} does not exist on LocationPrototype: ${!Object.hasOwn(documentPrototype, property)}`);
|
||||||
|
|
||||||
|
const propertyDescriptor = Object.getOwnPropertyDescriptor(document, property);
|
||||||
|
println(`${property} descriptor is not undefined: ${propertyDescriptor !== undefined}`);
|
||||||
|
println(`${property} enumerable: ${propertyDescriptor.enumerable}`);
|
||||||
|
println(`${property} configurable: ${propertyDescriptor.configurable}`);
|
||||||
|
println(`${property} writable: ${propertyDescriptor.writable}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
const unforgeableProperties = [
|
||||||
|
"isTrusted",
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const eventType of [Event, UIEvent, CustomEvent]) {
|
||||||
|
const event = new eventType("test");
|
||||||
|
const eventPrototype = Object.getPrototypeOf(event);
|
||||||
|
|
||||||
|
for (const property of unforgeableProperties) {
|
||||||
|
println(`${property} exists on ${eventType.name} instance itself: ${Object.hasOwn(event, property)}`);
|
||||||
|
println(`${property} does not exist on LocationPrototype: ${!Object.hasOwn(eventPrototype, property)}`);
|
||||||
|
|
||||||
|
const propertyDescriptor = Object.getOwnPropertyDescriptor(event, property);
|
||||||
|
println(`${property} descriptor is not undefined: ${propertyDescriptor !== undefined}`);
|
||||||
|
println(`${property} enumerable: ${propertyDescriptor.enumerable}`);
|
||||||
|
println(`${property} configurable: ${propertyDescriptor.configurable}`);
|
||||||
|
println(`${property} writable: ${propertyDescriptor.writable}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
for (const { location, name } of [{ location: window.location, name: "location" }, { location: document.location, name: "document.location" }]) {
|
||||||
|
const unforgeableProperties = [
|
||||||
|
"href",
|
||||||
|
"origin",
|
||||||
|
"protocol",
|
||||||
|
"host",
|
||||||
|
"hostname",
|
||||||
|
"port",
|
||||||
|
"pathname",
|
||||||
|
"search",
|
||||||
|
"hash",
|
||||||
|
"assign",
|
||||||
|
"replace",
|
||||||
|
"reload",
|
||||||
|
// FIXME: "ancestorOrigins",
|
||||||
|
"toString",
|
||||||
|
];
|
||||||
|
|
||||||
|
const locationPrototype = Object.getPrototypeOf(location);
|
||||||
|
|
||||||
|
for (const property of unforgeableProperties) {
|
||||||
|
println(`${property} exists on ${name} itself: ${Object.hasOwn(location, property)}`);
|
||||||
|
println(`${property} does not exist on LocationPrototype: ${!Object.hasOwn(locationPrototype, property)}`);
|
||||||
|
|
||||||
|
const propertyDescriptor = Object.getOwnPropertyDescriptor(location, property);
|
||||||
|
println(`${property} descriptor is not undefined: ${propertyDescriptor !== undefined}`);
|
||||||
|
println(`${property} enumerable: ${propertyDescriptor.enumerable}`);
|
||||||
|
println(`${property} configurable: ${propertyDescriptor.configurable}`);
|
||||||
|
println(`${property} writable: ${propertyDescriptor.writable}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
const unforgeableProperties = [
|
||||||
|
"window",
|
||||||
|
"document",
|
||||||
|
"location",
|
||||||
|
"top",
|
||||||
|
];
|
||||||
|
|
||||||
|
const windowPrototype = Object.getPrototypeOf(window);
|
||||||
|
|
||||||
|
for (const property of unforgeableProperties) {
|
||||||
|
println(`${property} exists on window itself: ${Object.hasOwn(window, property)}`);
|
||||||
|
println(`${property} does not exist on LocationPrototype: ${!Object.hasOwn(windowPrototype, property)}`);
|
||||||
|
|
||||||
|
const propertyDescriptor = Object.getOwnPropertyDescriptor(window, property);
|
||||||
|
println(`${property} descriptor is not undefined: ${propertyDescriptor !== undefined}`);
|
||||||
|
println(`${property} enumerable: ${propertyDescriptor.enumerable}`);
|
||||||
|
println(`${property} configurable: ${propertyDescriptor.configurable}`);
|
||||||
|
println(`${property} writable: ${propertyDescriptor.writable}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue