Repository: LadybirdBrowser/ladybird
File: Libraries/LibWeb/HTML/Scripting/Fetching.cpp (C++)

Code before:
    EnvironmentSettingsObject& fetch_client,
    Fetch::Infrastructure::Request::Destination destination,
    ScriptFetchOptions const& options,
    JS::Realm& module_map_realm,
    Web::Fetch::Infrastructure::Request::ReferrerType const& referrer,
    Optional<JS::ModuleRequest> const& module_request,
    TopLevelModule is_top_level,
    PerformTheFetchHook perform_fetch,
    OnFetchScriptComplete on_complete)
{
    // 1. Let moduleType be "javascript".
    String module_type = "javascript"_string;

    // 2. If moduleRequest was given, then set moduleType to the result of running the module type from module request steps given moduleRequest.
    if (module_request.has_value())
        module_type = module_type_from_module_request(*module_request);

    // 3. Assert: the result of running the module type allowed steps given moduleType and moduleMapRealm is true.
    //    Otherwise we would not have reached this point because a failure would have been raised when inspecting moduleRequest.[[Assertions]]
    //    in create a JavaScript module script or fetch a single imported module script.
    VERIFY(module_type_allowed(module_map_realm, module_type));

    // 4. Let moduleMap be moduleMapRealm's module map.
    auto& module_map = module_map_of_realm(module_map_realm);

    // 5. Check if this entry has already been added
    auto entry = module_map.get(url, module_type.to_byte_string());
    if (entry.has_value()) {
        switch (entry->type)
        {
            // 1. Module has already been loaded
            case ModuleMap::EntryType::ModuleScript:
                HTML::queue_global_task(HTML::Task::Source::Networking, realm.global_object(), GC::create_function(realm.heap(), [on_complete, entry] {
                    on_complete->function()(entry->module_script);
                }));
                return;
            // 2. We have already tried and failed to load this module
            case ModuleMap::EntryType::Failed:
                HTML::queue_global_task(HTML::Task::Source::Networking, realm.global_object(), GC::create_function(realm.heap(), [on_complete] {
                    on_complete->function()(nullptr);
                }));
                return;
            // 3. We are currently fetching the module, defer invocation of the completion handler
            case ModuleMap::EntryType::Fetching:
                module_map.wait_for_change(realm.heap(), url, module_type.to_byte_string(), [on_complete, &realm](auto entry) -> void {
                    HTML::queue_global_task(HTML::Task::Source::Networking, realm.global_object(), GC::create_function(realm.heap(), [on_complete, entry] {
                        // FIXME: This should run other steps, for now we just assume the script loaded.
                        VERIFY(entry.type == ModuleMap::EntryType::ModuleScript || entry.type == ModuleMap::EntryType::Failed);

                        on_complete->function()(entry.module_script);
                    }));

Review comment (suggestion):
These comments are spec comments and are copied verbatim from the web specs - they're not intended to be modified or renumbered unless the spec itself was changed.

Modifications to the implementation that do not correspond to the spec steps can be annotated using `// AD-HOC: ..` comments.

Code after:
    EnvironmentSettingsObject& fetch_client,
    Fetch::Infrastructure::Request::Destination destination,
    ScriptFetchOptions const& options,
    JS::Realm& module_map_realm,
    Web::Fetch::Infrastructure::Request::ReferrerType const& referrer,
    Optional<JS::ModuleRequest> const& module_request,
    TopLevelModule is_top_level,
    PerformTheFetchHook perform_fetch,
    OnFetchScriptComplete on_complete)
{
    // 1. Let moduleType be "javascript".
    String module_type = "javascript"_string;

    // 2. If moduleRequest was given, then set moduleType to the result of running the module type from module request steps given moduleRequest.
    if (module_request.has_value())
        module_type = module_type_from_module_request(*module_request);

    // 3. Assert: the result of running the module type allowed steps given moduleType and moduleMapRealm is true.
    //    Otherwise we would not have reached this point because a failure would have been raised when inspecting moduleRequest.[[Assertions]]
    //    in create a JavaScript module script or fetch a single imported module script.
    VERIFY(module_type_allowed(module_map_realm, module_type));

    // 4. Let moduleMap be moduleMapRealm's module map.
    auto& module_map = module_map_of_realm(module_map_realm);

    // 5. If moduleMap[(url, moduleType)] is "fetching", wait in parallel until that entry's value changes,
    //    then queue a task on the networking task source to proceed with running the following steps.
    if (module_map.is_fetching(url, module_type.to_byte_string())) {
        module_map.wait_for_change(realm.heap(), url, module_type.to_byte_string(), [on_complete, &realm](auto entry) -> void {
            HTML::queue_global_task(HTML::Task::Source::Networking, realm.global_object(), GC::create_function(realm.heap(), [on_complete, entry] {
                // FIXME: This should run other steps, for now we just assume the script loaded.
                VERIFY(entry.type == ModuleMap::EntryType::ModuleScript || entry.type == ModuleMap::EntryType::Failed);

                on_complete->function()(entry.module_script);
            }));
        });

        return;
    }

    // 6. If moduleMap[(url, moduleType)] exists, run onComplete given moduleMap[(url, moduleType)], and return.
    auto entry = module_map.get(url, module_type.to_byte_string());
    if (entry.has_value()) {
        on_complete->function()(entry->module_script);
        return;
    }

    // 7. Set moduleMap[(url, moduleType)] to "fetching".
    module_map.set(url, module_type.to_byte_string(), { ModuleMap::EntryType::Fetching, nullptr });

    // 8. Let request be a new request whose URL is url, mode is "cors", referrer is referrer, and client is fetchClient.