#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/TypeCasts.h>
#include <AK/Variant.h>
#include <AK/Vector.h>
#include <LibGC/Heap.h>
#include <LibGC/RootVector.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/FunctionObject.h>
#include <LibJS/Runtime/Promise.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibWeb/Bindings/EventTarget.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/ImageBitmap.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/MessagePort.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Bindings/PrincipalHostDefined.h>
#include <LibWeb/Bindings/Request.h>
#include <LibWeb/Bindings/WorkerGlobalScope.h>
#include <LibWeb/CSS/FontFaceSet.h>
#include <LibWeb/Crypto/Crypto.h>
#include <LibWeb/Fetch/Request.h>
#include <LibWeb/FileAPI/Blob.h>
#include <LibWeb/HTML/HTMLCanvasElement.h>
#include <LibWeb/HTML/HTMLImageElement.h>
#include <LibWeb/HTML/HTMLVideoElement.h>
#include <LibWeb/HTML/ImageBitmap.h>
#include <LibWeb/HTML/ImageData.h>
#include <LibWeb/HTML/OffscreenCanvas.h>
#include <LibWeb/HTML/Scripting/Environments.h>
#include <LibWeb/HTML/WorkerGlobalScope.h>
#include <LibWeb/HTML/WorkerLocation.h>
#include <LibWeb/HTML/WorkerNavigator.h>
#include <LibWeb/HighResolutionTime/Performance.h>
#include <LibWeb/IndexedDB/IDBFactory.h>
#include <LibWeb/SVG/SVGImageElement.h>
#include <LibWeb/ServiceWorker/CacheStorage.h>
#include <LibWeb/TrustedTypes/TrustedTypePolicyFactory.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/CallbackType.h>
#include <LibWeb/WebIDL/OverloadResolution.h>
#include <LibWeb/WebIDL/OverloadTypes.h>
#include <LibWeb/WebIDL/Promise.h>
#include <LibWeb/WebIDL/Tracing.h>
#include <LibWeb/WebIDL/Types.h>

namespace Web::Bindings {

void WorkerGlobalScopeConstructor::initialize(JS::Realm& realm, JS::NativeFunction& object)
{
    auto& vm = realm.vm();
    [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable;

    object.set_prototype(&ensure_web_constructor<EventTargetPrototype>(realm, "EventTarget"_fly_string));
    object.define_direct_property(vm.names.length, JS::Value(0), JS::Attribute::Configurable);
    object.define_direct_property(vm.names.name, JS::PrimitiveString::create(vm, "WorkerGlobalScope"_utf16), JS::Attribute::Configurable);
    object.define_direct_property(vm.names.prototype, &ensure_web_prototype<WorkerGlobalScopePrototype>(realm, "WorkerGlobalScope"_fly_string), 0);
}

JS::ThrowCompletionOr<GC::Ref<JS::Object>> WorkerGlobalScopeConstructor::construct([[maybe_unused]] InterfaceConstructor& constructor, [[maybe_unused]] JS::FunctionObject& new_target)
{
    WebIDL::log_trace(constructor.vm(), "WorkerGlobalScopeConstructor::construct");
    return constructor.vm().throw_completion<JS::TypeError>(JS::ErrorType::NotAConstructor, "WorkerGlobalScope");
}

void WorkerGlobalScopePrototype::initialize(JS::Realm& realm, JS::Object& object)
{
    [[maybe_unused]] auto& vm = realm.vm();
    [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable | JS::Attribute::Writable;

    object.set_prototype(GC::Ref { ensure_web_prototype<EventTargetPrototype>(realm, "EventTarget"_fly_string) });

    auto self_id = "self"_utf16_fly_string;
    auto native_self_getter = JS::NativeFunction::create(realm, self_getter, 0, self_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_self_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto self_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(self_id, native_self_getter, native_self_setter, self_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto location_id = "location"_utf16_fly_string;
    auto native_location_getter = JS::NativeFunction::create(realm, location_getter, 0, location_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_location_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto location_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(location_id, native_location_getter, native_location_setter, location_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto navigator_id = "navigator"_utf16_fly_string;
    auto native_navigator_getter = JS::NativeFunction::create(realm, navigator_getter, 0, navigator_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_navigator_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto navigator_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(navigator_id, native_navigator_getter, native_navigator_setter, navigator_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto onerror_id = "onerror"_utf16_fly_string;
    auto native_onerror_getter = JS::NativeFunction::create(realm, onerror_getter, 0, onerror_id, &realm, "get"sv);
    auto native_onerror_setter = JS::NativeFunction::create(realm, onerror_setter, 1, onerror_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto onerror_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(onerror_id, native_onerror_getter, native_onerror_setter, onerror_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto onlanguagechange_id = "onlanguagechange"_utf16_fly_string;
    auto native_onlanguagechange_getter = JS::NativeFunction::create(realm, onlanguagechange_getter, 0, onlanguagechange_id, &realm, "get"sv);
    auto native_onlanguagechange_setter = JS::NativeFunction::create(realm, onlanguagechange_setter, 1, onlanguagechange_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto onlanguagechange_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(onlanguagechange_id, native_onlanguagechange_getter, native_onlanguagechange_setter, onlanguagechange_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto onoffline_id = "onoffline"_utf16_fly_string;
    auto native_onoffline_getter = JS::NativeFunction::create(realm, onoffline_getter, 0, onoffline_id, &realm, "get"sv);
    auto native_onoffline_setter = JS::NativeFunction::create(realm, onoffline_setter, 1, onoffline_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto onoffline_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(onoffline_id, native_onoffline_getter, native_onoffline_setter, onoffline_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto ononline_id = "ononline"_utf16_fly_string;
    auto native_ononline_getter = JS::NativeFunction::create(realm, ononline_getter, 0, ononline_id, &realm, "get"sv);
    auto native_ononline_setter = JS::NativeFunction::create(realm, ononline_setter, 1, ononline_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto ononline_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(ononline_id, native_ononline_getter, native_ononline_setter, ononline_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto onrejectionhandled_id = "onrejectionhandled"_utf16_fly_string;
    auto native_onrejectionhandled_getter = JS::NativeFunction::create(realm, onrejectionhandled_getter, 0, onrejectionhandled_id, &realm, "get"sv);
    auto native_onrejectionhandled_setter = JS::NativeFunction::create(realm, onrejectionhandled_setter, 1, onrejectionhandled_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto onrejectionhandled_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(onrejectionhandled_id, native_onrejectionhandled_getter, native_onrejectionhandled_setter, onrejectionhandled_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto onunhandledrejection_id = "onunhandledrejection"_utf16_fly_string;
    auto native_onunhandledrejection_getter = JS::NativeFunction::create(realm, onunhandledrejection_getter, 0, onunhandledrejection_id, &realm, "get"sv);
    auto native_onunhandledrejection_setter = JS::NativeFunction::create(realm, onunhandledrejection_setter, 1, onunhandledrejection_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto onunhandledrejection_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(onunhandledrejection_id, native_onunhandledrejection_getter, native_onunhandledrejection_setter, onunhandledrejection_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto fonts_id = "fonts"_utf16_fly_string;
    auto native_fonts_getter = JS::NativeFunction::create(realm, fonts_getter, 0, fonts_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_fonts_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto fonts_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(fonts_id, native_fonts_getter, native_fonts_setter, fonts_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto origin_id = "origin"_utf16_fly_string;
    auto native_origin_getter = JS::NativeFunction::create(realm, origin_getter, 0, origin_id, &realm, "get"sv);
    auto native_origin_setter = JS::NativeFunction::create(realm, origin_setter, 1, origin_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto origin_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(origin_id, native_origin_getter, native_origin_setter, origin_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto is_secure_context_id = "isSecureContext"_utf16_fly_string;
    auto native_is_secure_context_getter = JS::NativeFunction::create(realm, is_secure_context_getter, 0, is_secure_context_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_is_secure_context_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto is_secure_context_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(is_secure_context_id, native_is_secure_context_getter, native_is_secure_context_setter, is_secure_context_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto cross_origin_isolated_id = "crossOriginIsolated"_utf16_fly_string;
    auto native_cross_origin_isolated_getter = JS::NativeFunction::create(realm, cross_origin_isolated_getter, 0, cross_origin_isolated_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_cross_origin_isolated_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto cross_origin_isolated_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(cross_origin_isolated_id, native_cross_origin_isolated_getter, native_cross_origin_isolated_setter, cross_origin_isolated_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto performance_id = "performance"_utf16_fly_string;
    auto native_performance_getter = JS::NativeFunction::create(realm, performance_getter, 0, performance_id, &realm, "get"sv);
    auto native_performance_setter = JS::NativeFunction::create(realm, performance_setter, 1, performance_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto performance_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(performance_id, native_performance_getter, native_performance_setter, performance_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto indexed_db_id = "indexedDB"_utf16_fly_string;
    auto native_indexed_db_getter = JS::NativeFunction::create(realm, indexed_db_getter, 0, indexed_db_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_indexed_db_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto indexed_db_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(indexed_db_id, native_indexed_db_getter, native_indexed_db_setter, indexed_db_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto crypto_id = "crypto"_utf16_fly_string;
    auto native_crypto_getter = JS::NativeFunction::create(realm, crypto_getter, 0, crypto_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_crypto_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto crypto_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(crypto_id, native_crypto_getter, native_crypto_setter, crypto_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto trusted_types_id = "trustedTypes"_utf16_fly_string;
    auto native_trusted_types_getter = JS::NativeFunction::create(realm, trusted_types_getter, 0, trusted_types_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_trusted_types_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto trusted_types_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(trusted_types_id, native_trusted_types_getter, native_trusted_types_setter, trusted_types_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    if (HTML::is_secure_context(Bindings::principal_host_defined_environment_settings_object(realm))) {
        auto caches_id = "caches"_utf16_fly_string;
        auto native_caches_getter = JS::NativeFunction::create(realm, caches_getter, 0, caches_id, &realm, "get"sv);
        GC::Ptr<JS::NativeFunction> native_caches_setter;
    
        // 4. Let configurable be false if attr is unforgeable and true otherwise.
        auto caches_attributes = default_attributes;
    
        // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.
    
        // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
        object.define_direct_accessor(caches_id, native_caches_getter, native_caches_setter, caches_attributes);
    
        // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
        }
    object.define_native_function(realm, "importScripts"_utf16_fly_string, import_scripts, 0, default_attributes);

    object.define_native_function(realm, "btoa"_utf16_fly_string, btoa, 1, default_attributes);

    object.define_native_function(realm, "atob"_utf16_fly_string, atob, 1, default_attributes);

    object.define_native_function(realm, "queueMicrotask"_utf16_fly_string, queue_microtask, 1, default_attributes);

    object.define_native_function(realm, "structuredClone"_utf16_fly_string, structured_clone, 1, default_attributes);

    object.define_native_function(realm, "reportError"_utf16_fly_string, report_error, 1, default_attributes);

    object.define_native_function(realm, "setTimeout"_utf16_fly_string, set_timeout, 1, default_attributes);

    object.define_native_function(realm, "clearTimeout"_utf16_fly_string, clear_timeout, 0, default_attributes);

    object.define_native_function(realm, "setInterval"_utf16_fly_string, set_interval, 1, default_attributes);

    object.define_native_function(realm, "clearInterval"_utf16_fly_string, clear_interval, 0, default_attributes);

    object.define_native_function(realm, "createImageBitmap"_utf16_fly_string, create_image_bitmap, 1, default_attributes);

    object.define_native_function(realm, "fetch"_utf16_fly_string, fetch, 1, default_attributes);

    object.define_direct_property(vm.well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm, "WorkerGlobalScope"_utf16), JS::Attribute::Configurable);
}

void WorkerGlobalScopePrototype::define_unforgeable_attributes(JS::Realm& realm, [[maybe_unused]] JS::Object& object)
{
    [[maybe_unused]] auto& vm = realm.vm();
    [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable;
}

[[maybe_unused]] static JS::ThrowCompletionOr<HTML::WorkerGlobalScope*> impl_from(JS::VM& vm, JS::Value js_value)
{

    if (auto impl = js_value.as_if<HTML::WorkerGlobalScope>())
        return impl.ptr();
    return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "WorkerGlobalScope");
}

[[maybe_unused]] static JS::ThrowCompletionOr<HTML::WorkerGlobalScope*> impl_from(JS::VM& vm)
{
    auto this_value = vm.this_value();
    if (this_value.is_nullish())
        this_value = &vm.current_realm()->global_object();
    return impl_from(vm, this_value);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::self_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::self_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->self(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::location_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::location_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->location(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::navigator_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::navigator_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->navigator(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::onerror_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::onerror_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->onerror(); }));

    return [&]() -> JS::Value {
        // 1. If the IDL nullable type T? value is null, then the JavaScript value is null.
        if (!R)
            return JS::js_null();

        // 2. Otherwise, the JavaScript value is the result of converting the IDL nullable type value to the inner IDL type T.
        return JS::Value(R->callback);
    }();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::onlanguagechange_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::onlanguagechange_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->onlanguagechange(); }));

    return [&]() -> JS::Value {
        // 1. If the IDL nullable type T? value is null, then the JavaScript value is null.
        if (!R)
            return JS::js_null();

        // 2. Otherwise, the JavaScript value is the result of converting the IDL nullable type value to the inner IDL type T.
        return JS::Value(R->callback);
    }();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::onoffline_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::onoffline_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->onoffline(); }));

    return [&]() -> JS::Value {
        // 1. If the IDL nullable type T? value is null, then the JavaScript value is null.
        if (!R)
            return JS::js_null();

        // 2. Otherwise, the JavaScript value is the result of converting the IDL nullable type value to the inner IDL type T.
        return JS::Value(R->callback);
    }();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::ononline_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::ononline_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->ononline(); }));

    return [&]() -> JS::Value {
        // 1. If the IDL nullable type T? value is null, then the JavaScript value is null.
        if (!R)
            return JS::js_null();

        // 2. Otherwise, the JavaScript value is the result of converting the IDL nullable type value to the inner IDL type T.
        return JS::Value(R->callback);
    }();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::onrejectionhandled_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::onrejectionhandled_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->onrejectionhandled(); }));

    return [&]() -> JS::Value {
        // 1. If the IDL nullable type T? value is null, then the JavaScript value is null.
        if (!R)
            return JS::js_null();

        // 2. Otherwise, the JavaScript value is the result of converting the IDL nullable type value to the inner IDL type T.
        return JS::Value(R->callback);
    }();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::onunhandledrejection_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::onunhandledrejection_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->onunhandledrejection(); }));

    return [&]() -> JS::Value {
        // 1. If the IDL nullable type T? value is null, then the JavaScript value is null.
        if (!R)
            return JS::js_null();

        // 2. Otherwise, the JavaScript value is the result of converting the IDL nullable type value to the inner IDL type T.
        return JS::Value(R->callback);
    }();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::fonts_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::fonts_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->fonts(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::origin_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::origin_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->origin(); }));

    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::is_secure_context_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::is_secure_context_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->is_secure_context(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::cross_origin_isolated_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::cross_origin_isolated_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->cross_origin_isolated(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::performance_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::performance_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->performance(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::indexed_db_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::indexed_db_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->indexed_db(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::crypto_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::crypto_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->crypto(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::trusted_types_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::trusted_types_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->trusted_types(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::caches_getter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::caches_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->caches(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::onerror_setter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::onerror_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {
        GC::Ptr<WebIDL::CallbackType> value;
        if (V.is_object()) {

        if (!V.is_nullish()) {

            value = TRY([&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {

        return vm.heap().allocate<WebIDL::CallbackType>(V.as_object(),  HTML::incumbent_realm(), WebIDL::OperationReturnsPromise::No);
    }());
        }
        }
        return value;
    }(); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_onerror(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::onlanguagechange_setter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::onlanguagechange_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {
        GC::Ptr<WebIDL::CallbackType> value;
        if (V.is_object()) {

        if (!V.is_nullish()) {

            value = TRY([&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {

        return vm.heap().allocate<WebIDL::CallbackType>(V.as_object(),  HTML::incumbent_realm(), WebIDL::OperationReturnsPromise::No);
    }());
        }
        }
        return value;
    }(); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_onlanguagechange(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::onoffline_setter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::onoffline_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {
        GC::Ptr<WebIDL::CallbackType> value;
        if (V.is_object()) {

        if (!V.is_nullish()) {

            value = TRY([&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {

        return vm.heap().allocate<WebIDL::CallbackType>(V.as_object(),  HTML::incumbent_realm(), WebIDL::OperationReturnsPromise::No);
    }());
        }
        }
        return value;
    }(); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_onoffline(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::ononline_setter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::ononline_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {
        GC::Ptr<WebIDL::CallbackType> value;
        if (V.is_object()) {

        if (!V.is_nullish()) {

            value = TRY([&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {

        return vm.heap().allocate<WebIDL::CallbackType>(V.as_object(),  HTML::incumbent_realm(), WebIDL::OperationReturnsPromise::No);
    }());
        }
        }
        return value;
    }(); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_ononline(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::onrejectionhandled_setter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::onrejectionhandled_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {
        GC::Ptr<WebIDL::CallbackType> value;
        if (V.is_object()) {

        if (!V.is_nullish()) {

            value = TRY([&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {

        return vm.heap().allocate<WebIDL::CallbackType>(V.as_object(),  HTML::incumbent_realm(), WebIDL::OperationReturnsPromise::No);
    }());
        }
        }
        return value;
    }(); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_onrejectionhandled(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::onunhandledrejection_setter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::onunhandledrejection_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {
        GC::Ptr<WebIDL::CallbackType> value;
        if (V.is_object()) {

        if (!V.is_nullish()) {

            value = TRY([&]() -> JS::ThrowCompletionOr<GC::Ptr<WebIDL::CallbackType>> {

        return vm.heap().allocate<WebIDL::CallbackType>(V.as_object(),  HTML::incumbent_realm(), WebIDL::OperationReturnsPromise::No);
    }());
        }
        }
        return value;
    }(); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_onunhandledrejection(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::origin_setter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::origin_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    // 5. If attribute is declared with the [Replaceable] extended attribute, then:
    // 1. Perform ? CreateDataPropertyOrThrow(jsValue, id, V).
    TRY(idl_object->create_data_property_or_throw("origin"_utf16_fly_string, V));

    // 2. Return undefined.
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::performance_setter)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::performance_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    // 5. If attribute is declared with the [Replaceable] extended attribute, then:
    // 1. Perform ? CreateDataPropertyOrThrow(jsValue, id, V).
    TRY(idl_object->create_data_property_or_throw("performance"_utf16_fly_string, V));

    // 2. Return undefined.
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::import_scripts)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::import_scripts");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    Vector<String> urls;
    if (vm.argument_count() > 0) {
        urls.ensure_capacity(vm.argument_count() - 0);
        for (size_t i = 0; i < vm.argument_count(); ++i) {
            auto argument = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<String> {
        return TRY(WebIDL::to_usv_string(vm, vm.argument(i)));
    }(); }));
            urls.unchecked_append(move(argument));
        }
    }

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->import_scripts(urls); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::btoa)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::btoa");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "btoa");

    auto arg0 = vm.argument(0);
    auto data = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<String> {
        return TRY(WebIDL::to_string(vm, arg0));
    }(); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->btoa(data); }));
    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::atob)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::atob");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "atob");

    auto arg0 = vm.argument(0);
    auto data = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<String> {
        return TRY(WebIDL::to_string(vm, arg0));
    }(); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->atob(data); }));
    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::queue_microtask)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::queue_microtask");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "queueMicrotask");

    auto arg0 = vm.argument(0);
    auto callback = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<GC::Ref<WebIDL::CallbackType>> {

        if (!arg0.is_function())
            return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAFunction, arg0);

        return vm.heap().allocate<WebIDL::CallbackType>(arg0.as_object(),  HTML::incumbent_realm(), WebIDL::OperationReturnsPromise::No);
    }(); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->queue_microtask(callback); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::structured_clone)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::structured_clone");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "structuredClone");

    auto arg0 = vm.argument(0);
    auto value = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0; }));

    auto arg1 = vm.argument(1);
    StructuredSerializeOptions options = StructuredSerializeOptions {};
    if (!arg1.is_undefined())
        options = TRY(throw_dom_exception_if_needed(vm, [&] { return convert_to_idl_value_for_structured_serialize_options(vm, arg1); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->structured_clone(value, options); }));
    return R;
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::report_error)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::report_error");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "reportError");

    auto arg0 = vm.argument(0);
    auto e = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0; }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->report_error(e); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::set_timeout)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::set_timeout");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "setTimeout");

    auto arg0 = vm.argument(0);
    auto handler = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<Variant<String, GC::Ref<WebIDL::CallbackType>>> {

        if (arg0.is_object()) {
            [[maybe_unused]] auto& object = arg0.as_object();

            if (object.is_function()) {
                auto callback_function_union_type = TRY([&]() -> JS::ThrowCompletionOr<GC::Ref<WebIDL::CallbackType>> {

        if (!arg0.is_function())
            return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAFunction, arg0);

        return vm.heap().allocate<WebIDL::CallbackType>(arg0.as_object(),  HTML::incumbent_realm(), WebIDL::OperationReturnsPromise::No);
    }());
                return Variant<String, GC::Ref<WebIDL::CallbackType>> { callback_function_union_type };
            }

        }

        auto handler_string = TRY([&]() -> JS::ThrowCompletionOr<String> {
        return TRY(WebIDL::to_string(vm, arg0));
    }());
        return Variant<String, GC::Ref<WebIDL::CallbackType>> { handler_string };

        return vm.throw_completion<JS::TypeError>("No union types matched"_utf16);
    }(); }));

    auto arg1 = vm.argument(1);
    WebIDL::Long timeout = 0;
    if (!arg1.is_undefined())
        timeout = TRY(throw_dom_exception_if_needed(vm, [&] { return WebIDL::convert_to_int<WebIDL::Long>(vm, arg1, WebIDL::EnforceRange::No, WebIDL::Clamp::No); }));

    GC::RootVector<JS::Value> arguments;
    if (vm.argument_count() > 2) {
        arguments.ensure_capacity(vm.argument_count() - 2);
        for (size_t i = 2; i < vm.argument_count(); ++i) {
            auto argument = TRY(throw_dom_exception_if_needed(vm, [&] { return vm.argument(i); }));
            arguments.unchecked_append(move(argument));
        }
    }

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_timeout(handler, timeout, arguments); }));
    return JS::Value(static_cast<WebIDL::Long>(R));
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::clear_timeout)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::clear_timeout");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    WebIDL::Long id = 0;
    if (!arg0.is_undefined())
        id = TRY(throw_dom_exception_if_needed(vm, [&] { return WebIDL::convert_to_int<WebIDL::Long>(vm, arg0, WebIDL::EnforceRange::No, WebIDL::Clamp::No); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->clear_timeout(id); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::set_interval)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::set_interval");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "setInterval");

    auto arg0 = vm.argument(0);
    auto handler = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<Variant<String, GC::Ref<WebIDL::CallbackType>>> {

        if (arg0.is_object()) {
            [[maybe_unused]] auto& object = arg0.as_object();

            if (object.is_function()) {
                auto callback_function_union_type = TRY([&]() -> JS::ThrowCompletionOr<GC::Ref<WebIDL::CallbackType>> {

        if (!arg0.is_function())
            return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAFunction, arg0);

        return vm.heap().allocate<WebIDL::CallbackType>(arg0.as_object(),  HTML::incumbent_realm(), WebIDL::OperationReturnsPromise::No);
    }());
                return Variant<String, GC::Ref<WebIDL::CallbackType>> { callback_function_union_type };
            }

        }

        auto handler_string = TRY([&]() -> JS::ThrowCompletionOr<String> {
        return TRY(WebIDL::to_string(vm, arg0));
    }());
        return Variant<String, GC::Ref<WebIDL::CallbackType>> { handler_string };

        return vm.throw_completion<JS::TypeError>("No union types matched"_utf16);
    }(); }));

    auto arg1 = vm.argument(1);
    WebIDL::Long timeout = 0;
    if (!arg1.is_undefined())
        timeout = TRY(throw_dom_exception_if_needed(vm, [&] { return WebIDL::convert_to_int<WebIDL::Long>(vm, arg1, WebIDL::EnforceRange::No, WebIDL::Clamp::No); }));

    GC::RootVector<JS::Value> arguments;
    if (vm.argument_count() > 2) {
        arguments.ensure_capacity(vm.argument_count() - 2);
        for (size_t i = 2; i < vm.argument_count(); ++i) {
            auto argument = TRY(throw_dom_exception_if_needed(vm, [&] { return vm.argument(i); }));
            arguments.unchecked_append(move(argument));
        }
    }

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_interval(handler, timeout, arguments); }));
    return JS::Value(static_cast<WebIDL::Long>(R));
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::clear_interval)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::clear_interval");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    WebIDL::Long id = 0;
    if (!arg0.is_undefined())
        id = TRY(throw_dom_exception_if_needed(vm, [&] { return WebIDL::convert_to_int<WebIDL::Long>(vm, arg0, WebIDL::EnforceRange::No, WebIDL::Clamp::No); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->clear_interval(id); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::create_image_bitmap)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::create_image_bitmap");

    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
    Optional<int> chosen_overload_callable_id;
    Optional<WebIDL::EffectiveOverloadSet> effective_overload_set;

    switch (min(6, vm.argument_count())) {
    case 1:
        chosen_overload_callable_id = 0;
        break;
    case 2:
        chosen_overload_callable_id = 0;
        break;
    case 5:
        chosen_overload_callable_id = 1;
        break;
    case 6:
        chosen_overload_callable_id = 1;
        break;
    }

    Vector<StringView> dictionary_types {
        "ImageBitmapOptions"sv,
    };

    if (!chosen_overload_callable_id.has_value()) {
        if (!effective_overload_set.has_value())
            return vm.throw_completion<JS::TypeError>(JS::ErrorType::OverloadResolutionFailed);
        chosen_overload_callable_id = TRY(WebIDL::resolve_overload(vm, effective_overload_set.value(), dictionary_types)).callable_id;
    }


    switch (chosen_overload_callable_id.value()) {
    case 0:
        return create_image_bitmap0(vm);
    case 1:
        return create_image_bitmap1(vm);
    default:
        VERIFY_NOT_REACHED();
    }
    };

    auto maybe_result = steps();
    if (maybe_result.is_throw_completion())
        return WebIDL::create_rejected_promise(realm, maybe_result.error_value())->promise();

    return maybe_result.release_value();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::create_image_bitmap0)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::create_image_bitmap0");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "createImageBitmap");

    auto arg0 = vm.argument(0);
    auto image = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>>> {

        if (arg0.is_object()) {
            [[maybe_unused]] auto& object = arg0.as_object();

            if (is<PlatformObject>(object)) {

                if (auto* result = as_if<HTML::HTMLImageElement>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<SVG::SVGImageElement>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<HTML::HTMLVideoElement>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<HTML::HTMLCanvasElement>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<HTML::ImageBitmap>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<HTML::OffscreenCanvas>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<FileAPI::Blob>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<HTML::ImageData>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };
            }
        }

        return vm.throw_completion<JS::TypeError>("No union types matched"_utf16);
    }(); }));

    auto arg1 = vm.argument(1);
    ImageBitmapOptions options = ImageBitmapOptions {};
    if (!arg1.is_undefined())
        options = TRY(throw_dom_exception_if_needed(vm, [&] { return convert_to_idl_value_for_image_bitmap_options(vm, arg1); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->create_image_bitmap(image, options); }));
    return GC::Ref { as<JS::Promise>(*R->promise()) };
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::create_image_bitmap1)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::create_image_bitmap1");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 5)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountMany, "createImageBitmap", "5");

    auto arg0 = vm.argument(0);
    auto image = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>>> {

        if (arg0.is_object()) {
            [[maybe_unused]] auto& object = arg0.as_object();

            if (is<PlatformObject>(object)) {

                if (auto* result = as_if<HTML::HTMLImageElement>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<SVG::SVGImageElement>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<HTML::HTMLVideoElement>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<HTML::HTMLCanvasElement>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<HTML::ImageBitmap>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<HTML::OffscreenCanvas>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<FileAPI::Blob>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };

                if (auto* result = as_if<HTML::ImageData>(object))
                    return Variant<GC::Ref<HTML::HTMLImageElement>, GC::Ref<SVG::SVGImageElement>, GC::Ref<HTML::HTMLVideoElement>, GC::Ref<HTML::HTMLCanvasElement>, GC::Ref<HTML::ImageBitmap>, GC::Ref<HTML::OffscreenCanvas>, GC::Ref<FileAPI::Blob>, GC::Ref<HTML::ImageData>> { GC::Ref { *result } };
            }
        }

        return vm.throw_completion<JS::TypeError>("No union types matched"_utf16);
    }(); }));

    auto arg1 = vm.argument(1);
    auto sx = TRY(throw_dom_exception_if_needed(vm, [&] { return WebIDL::convert_to_int<WebIDL::Long>(vm, arg1, WebIDL::EnforceRange::No, WebIDL::Clamp::No); }));

    auto arg2 = vm.argument(2);
    auto sy = TRY(throw_dom_exception_if_needed(vm, [&] { return WebIDL::convert_to_int<WebIDL::Long>(vm, arg2, WebIDL::EnforceRange::No, WebIDL::Clamp::No); }));

    auto arg3 = vm.argument(3);
    auto sw = TRY(throw_dom_exception_if_needed(vm, [&] { return WebIDL::convert_to_int<WebIDL::Long>(vm, arg3, WebIDL::EnforceRange::No, WebIDL::Clamp::No); }));

    auto arg4 = vm.argument(4);
    auto sh = TRY(throw_dom_exception_if_needed(vm, [&] { return WebIDL::convert_to_int<WebIDL::Long>(vm, arg4, WebIDL::EnforceRange::No, WebIDL::Clamp::No); }));

    auto arg5 = vm.argument(5);
    ImageBitmapOptions options = ImageBitmapOptions {};
    if (!arg5.is_undefined())
        options = TRY(throw_dom_exception_if_needed(vm, [&] { return convert_to_idl_value_for_image_bitmap_options(vm, arg5); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->create_image_bitmap(image, sx, sy, sw, sh, options); }));
    return GC::Ref { as<JS::Promise>(*R->promise()) };
}

JS_DEFINE_NATIVE_FUNCTION(WorkerGlobalScopePrototype::fetch)
{
    WebIDL::log_trace(vm, "WorkerGlobalScopePrototype::fetch");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    auto steps = [&realm, &vm]() -> JS::ThrowCompletionOr<GC::Ref<WebIDL::Promise>> {
        (void)realm;
    [[maybe_unused]] HTML::WorkerGlobalScope* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "fetch");

    auto arg0 = vm.argument(0);
    auto input = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<Variant<GC::Ref<Fetch::Request>, String>> {

        if (arg0.is_object()) {
            [[maybe_unused]] auto& object = arg0.as_object();

            if (is<PlatformObject>(object)) {

                if (auto* result = as_if<Fetch::Request>(object))
                    return Variant<GC::Ref<Fetch::Request>, String> { GC::Ref { *result } };
            }
        }

        auto input_string = TRY([&]() -> JS::ThrowCompletionOr<String> {
        return TRY(WebIDL::to_usv_string(vm, arg0));
    }());
        return Variant<GC::Ref<Fetch::Request>, String> { input_string };

        return vm.throw_completion<JS::TypeError>("No union types matched"_utf16);
    }(); }));

    auto arg1 = vm.argument(1);
    RequestInit init = RequestInit {};
    if (!arg1.is_undefined())
        init = TRY(throw_dom_exception_if_needed(vm, [&] { return convert_to_idl_value_for_request_init(vm, arg1); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->fetch(input, init); }));
        return R;
    };

    auto maybe_R = steps();

    // And then, if an exception E was thrown:
    // 1. If op has a return type that is a promise type, then return ! Call(%Promise.reject%, %Promise%, «E»).
    // 2. Otherwise, end these steps and allow the exception to propagate.
    if (maybe_R.is_throw_completion())
        return WebIDL::create_rejected_promise(realm, maybe_R.error_value())->promise();

    return GC::Ref { as<JS::Promise>(*maybe_R.release_value()->promise()) };
}

} // namespace Web::Bindings
