# Global Metrics

path: .metrics.cognitive.average
old: null
new: 1.5
path: .metrics.cognitive.sum
old: 0.0
new: 27.0
path: .metrics.halstead.effort
old: 831.2045094254761
new: 397411.0552276002
path: .metrics.halstead.level
old: 0.21768707482993196
new: 0.024039133473095737
path: .metrics.halstead.purity_ratio
old: 2.0912871113600806
new: 1.1236606717563349
path: .metrics.halstead.time
old: 46.17802830141534
new: 22078.391957088905
path: .metrics.halstead.volume
old: 180.94247824228052
new: 9553.417400300104
path: .metrics.halstead.N2
old: 21.0
new: 530.0
path: .metrics.halstead.n1
old: 7.0
new: 27.0
path: .metrics.halstead.N1
old: 19.0
new: 721.0
path: .metrics.halstead.bugs
old: 0.029468000760988843
new: 1.8017949889327456
path: .metrics.halstead.n2
old: 16.0
new: 172.0
path: .metrics.halstead.vocabulary
old: 23.0
new: 199.0
path: .metrics.halstead.estimated_program_length
old: 83.65148445440323
new: 1405.6995003671746
path: .metrics.halstead.difficulty
old: 4.59375
new: 41.59883720930232
path: .metrics.halstead.length
old: 40.0
new: 1251.0
path: .metrics.nargs.sum
old: 0.0
new: 51.0
path: .metrics.nargs.average
old: null
new: 2.8333333333333335
path: .metrics.cyclomatic.average
old: 1.0
new: 2.5789473684210527
path: .metrics.cyclomatic.sum
old: 2.0
new: 49.0
path: .metrics.mi.mi_original
old: 88.41007067592315
new: 21.25980462138125
path: .metrics.mi.mi_sei
old: 83.98704878844356
new: -20.637218203154976
path: .metrics.mi.mi_visual_studio
old: 51.70179571691412
new: 12.432634281509502
path: .metrics.nexits.average
old: null
new: 1.2222222222222223
path: .metrics.nexits.sum
old: 0.0
new: 22.0
path: .metrics.nom.closures
old: 0.0
new: 1.0
path: .metrics.nom.total
old: 0.0
new: 18.0
path: .metrics.nom.functions
old: 0.0
new: 17.0
path: .metrics.loc.cloc
old: 6.0
new: 18.0
path: .metrics.loc.lloc
old: 0.0
new: 86.0
path: .metrics.loc.ploc
old: 15.0
new: 215.0
path: .metrics.loc.sloc
old: 30.0
new: 272.0
path: .metrics.loc.blank
old: 9.0
new: 39.0

# Spaces Data

## Minimal test - lines (18, 272)

path: .spaces[0].metrics.halstead.n1
old: 4.0
new: 27.0
path: .spaces[0].metrics.halstead.difficulty
old: 2.25
new: 43.333333333333336
path: .spaces[0].metrics.halstead.n2
old: 8.0
new: 162.0
path: .spaces[0].metrics.halstead.time
old: 6.721804688852168
new: 22592.89944999233
path: .spaces[0].metrics.halstead.vocabulary
old: 12.0
new: 189.0
path: .spaces[0].metrics.halstead.estimated_program_length
old: 32.0
new: 1317.437663025723
path: .spaces[0].metrics.halstead.purity_ratio
old: 2.1333333333333333
new: 1.061593604372057
path: .spaces[0].metrics.halstead.volume
old: 53.77443751081734
new: 9384.74284845835
path: .spaces[0].metrics.halstead.bugs
old: 0.008154255994324386
new: 1.82967966629573
path: .spaces[0].metrics.halstead.N2
old: 9.0
new: 520.0
path: .spaces[0].metrics.halstead.level
old: 0.4444444444444444
new: 0.023076923076923075
path: .spaces[0].metrics.halstead.effort
old: 120.99248439933902
new: 406672.1900998619
path: .spaces[0].metrics.halstead.N1
old: 6.0
new: 721.0
path: .spaces[0].metrics.halstead.length
old: 15.0
new: 1241.0
path: .spaces[0].metrics.mi.mi_visual_studio
old: 70.77341864342087
new: 13.232724980635474
path: .spaces[0].metrics.mi.mi_sei
old: 98.999594644585
new: -21.03323380094112
path: .spaces[0].metrics.mi.mi_original
old: 121.02254588024968
new: 22.627959716886664
path: .spaces[0].metrics.loc.ploc
old: 5.0
new: 205.0
path: .spaces[0].metrics.loc.blank
old: 1.0
new: 37.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 86.0
path: .spaces[0].metrics.loc.sloc
old: 6.0
new: 255.0
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 13.0
path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 51.0
path: .spaces[0].metrics.nargs.average
old: null
new: 2.8333333333333335
path: .spaces[0].metrics.nexits.average
old: null
new: 1.2222222222222223
path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 22.0
path: .spaces[0].metrics.nom.functions
old: 0.0
new: 17.0
path: .spaces[0].metrics.nom.total
old: 0.0
new: 18.0
path: .spaces[0].metrics.nom.closures
old: 0.0
new: 1.0
path: .spaces[0].metrics.cognitive.average
old: null
new: 1.5
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 27.0
path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 48.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 2.6666666666666665

### Code

    namespace mozilla {

    PreloadService::PreloadService(dom::Document* aDoc) : mDocument(aDoc) {}
    PreloadService::~PreloadService() = default;

    bool PreloadService::RegisterPreload(const PreloadHashKey& aKey,
                                         PreloaderBase* aPreload) {
      return mPreloads.WithEntryHandle(aKey, [&](auto&& lookup) {
        if (lookup) {
          lookup.Data() = aPreload;
          return true;
        }
        lookup.Insert(aPreload);
        return false;
      });
    }

    void PreloadService::DeregisterPreload(const PreloadHashKey& aKey) {
      mPreloads.Remove(aKey);
    }

    void PreloadService::ClearAllPreloads() { mPreloads.Clear(); }

    bool PreloadService::PreloadExists(const PreloadHashKey& aKey) {
      return mPreloads.Contains(aKey);
    }

    already_AddRefed PreloadService::LookupPreload(
        const PreloadHashKey& aKey) const {
      return mPreloads.Get(aKey);
    }

    already_AddRefed PreloadService::GetPreloadURI(const nsAString& aURL) {
      nsIURI* base = BaseURIForPreload();
      auto encoding = mDocument->GetDocumentCharacterSet();

      nsCOMPtr uri;
      nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, encoding, base);
      if (NS_FAILED(rv)) {
        return nullptr;
      }

      return uri.forget();
    }

    already_AddRefed PreloadService::PreloadLinkElement(
        dom::HTMLLinkElement* aLinkElement, nsContentPolicyType aPolicyType) {
      if (aPolicyType == nsIContentPolicy::TYPE_INVALID) {
        MOZ_ASSERT_UNREACHABLE("Caller should check");
        return nullptr;
      }

      if (!StaticPrefs::network_preload()) {
        return nullptr;
      }

      nsAutoString as, charset, crossOrigin, integrity, referrerPolicy, srcset,
          sizes, type, url;

      nsCOMPtr uri = aLinkElement->GetURI();
      aLinkElement->GetAs(as);
      aLinkElement->GetCharset(charset);
      aLinkElement->GetImageSrcset(srcset);
      aLinkElement->GetImageSizes(sizes);
      aLinkElement->GetHref(url);
      aLinkElement->GetCrossOrigin(crossOrigin);
      aLinkElement->GetIntegrity(integrity);
      aLinkElement->GetReferrerPolicy(referrerPolicy);
      aLinkElement->GetType(type);

      auto result = PreloadOrCoalesce(uri, url, aPolicyType, as, type, charset,
                                      srcset, sizes, integrity, crossOrigin,
                                      referrerPolicy, /* aFromHeader = */ false);

      if (!result.mPreloader) {
        NotifyNodeEvent(aLinkElement, result.mAlreadyComplete);
        return nullptr;
      }

      result.mPreloader->AddLinkPreloadNode(aLinkElement);
      return result.mPreloader.forget();
    }

    void PreloadService::PreloadLinkHeader(
        nsIURI* aURI, const nsAString& aURL, nsContentPolicyType aPolicyType,
        const nsAString& aAs, const nsAString& aType, const nsAString& aIntegrity,
        const nsAString& aSrcset, const nsAString& aSizes, const nsAString& aCORS,
        const nsAString& aReferrerPolicy) {
      if (aPolicyType == nsIContentPolicy::TYPE_INVALID) {
        MOZ_ASSERT_UNREACHABLE("Caller should check");
        return;
      }

      if (!StaticPrefs::network_preload()) {
        return;
      }

      PreloadOrCoalesce(aURI, aURL, aPolicyType, aAs, aType, u""_ns, aSrcset,
                        aSizes, aIntegrity, aCORS, aReferrerPolicy,
                        /* aFromHeader = */ true);
    }

    PreloadService::PreloadOrCoalesceResult PreloadService::PreloadOrCoalesce(
        nsIURI* aURI, const nsAString& aURL, nsContentPolicyType aPolicyType,
        const nsAString& aAs, const nsAString& aType, const nsAString& aCharset,
        const nsAString& aSrcset, const nsAString& aSizes,
        const nsAString& aIntegrity, const nsAString& aCORS,
        const nsAString& aReferrerPolicy, bool aFromHeader) {
      if (!aURI) {
        MOZ_ASSERT_UNREACHABLE("Should not pass null nsIURI");
        return {nullptr, false};
      }

      bool isImgSet = false;
      PreloadHashKey preloadKey;
      nsCOMPtr uri = aURI;

      if (aAs.LowerCaseEqualsASCII("script")) {
        preloadKey = PreloadHashKey::CreateAsScript(uri, aCORS, aType);
      } else if (aAs.LowerCaseEqualsASCII("style")) {
        preloadKey = PreloadHashKey::CreateAsStyle(
            uri, mDocument->NodePrincipal(), dom::Element::StringToCORSMode(aCORS),
            css::eAuthorSheetFeatures /* see Loader::LoadSheet */);
      } else if (aAs.LowerCaseEqualsASCII("image")) {
        uri = mDocument->ResolvePreloadImage(BaseURIForPreload(), aURL, aSrcset,
                                             aSizes, &isImgSet);
        if (!uri) {
          return {nullptr, false};
        }

        preloadKey = PreloadHashKey::CreateAsImage(
            uri, mDocument->NodePrincipal(), dom::Element::StringToCORSMode(aCORS));
      } else if (aAs.LowerCaseEqualsASCII("font")) {
        preloadKey = PreloadHashKey::CreateAsFont(
            uri, dom::Element::StringToCORSMode(aCORS));
      } else if (aAs.LowerCaseEqualsASCII("fetch")) {
        preloadKey = PreloadHashKey::CreateAsFetch(
            uri, dom::Element::StringToCORSMode(aCORS));
      } else {
        return {nullptr, false};
      }

      if (RefPtr preload = LookupPreload(preloadKey)) {
        return {std::move(preload), false};
      }

      if (aAs.LowerCaseEqualsASCII("script")) {
        PreloadScript(uri, aType, aCharset, aCORS, aReferrerPolicy, aIntegrity,
                      true /* isInHead - TODO */);
      } else if (aAs.LowerCaseEqualsASCII("style")) {
        auto status = mDocument->PreloadStyle(
            aURI, Encoding::ForLabel(aCharset), aCORS,
            PreloadReferrerPolicy(aReferrerPolicy), aIntegrity,
            aFromHeader ? css::StylePreloadKind::FromLinkRelPreloadHeader
                        : css::StylePreloadKind::FromLinkRelPreloadElement);
        switch (status) {
          case dom::SheetPreloadStatus::AlreadyComplete:
            return {nullptr, /* already_complete = */ true};
          case dom::SheetPreloadStatus::Errored:
          case dom::SheetPreloadStatus::InProgress:
            break;
        }
      } else if (aAs.LowerCaseEqualsASCII("image")) {
        PreloadImage(uri, aCORS, aReferrerPolicy, isImgSet);
      } else if (aAs.LowerCaseEqualsASCII("font")) {
        PreloadFont(uri, aCORS, aReferrerPolicy);
      } else if (aAs.LowerCaseEqualsASCII("fetch")) {
        PreloadFetch(uri, aCORS, aReferrerPolicy);
      }

      return {LookupPreload(preloadKey), false};
    }

    void PreloadService::PreloadScript(nsIURI* aURI, const nsAString& aType,
                                       const nsAString& aCharset,
                                       const nsAString& aCrossOrigin,
                                       const nsAString& aReferrerPolicy,
                                       const nsAString& aIntegrity,
                                       bool aScriptFromHead) {
      mDocument->ScriptLoader()->PreloadURI(
          aURI, aCharset, aType, aCrossOrigin, aIntegrity, aScriptFromHead, false,
          false, false, true, PreloadReferrerPolicy(aReferrerPolicy));
    }

    void PreloadService::PreloadImage(nsIURI* aURI, const nsAString& aCrossOrigin,
                                      const nsAString& aImageReferrerPolicy,
                                      bool aIsImgSet) {
      mDocument->PreLoadImage(aURI, aCrossOrigin,
                              PreloadReferrerPolicy(aImageReferrerPolicy),
                              aIsImgSet, true);
    }

    void PreloadService::PreloadFont(nsIURI* aURI, const nsAString& aCrossOrigin,
                                     const nsAString& aReferrerPolicy) {
      CORSMode cors = dom::Element::StringToCORSMode(aCrossOrigin);
      auto key = PreloadHashKey::CreateAsFont(aURI, cors);

      // * Bug 1618549: Depending on where we decide to do the deduplication, we may
      // want to check if the font is already being preloaded here.

      RefPtr preloader = new FontPreloader();
      dom::ReferrerPolicy referrerPolicy = PreloadReferrerPolicy(aReferrerPolicy);
      preloader->OpenChannel(key, aURI, cors, referrerPolicy, mDocument);
    }

    void PreloadService::PreloadFetch(nsIURI* aURI, const nsAString& aCrossOrigin,
                                      const nsAString& aReferrerPolicy) {
      CORSMode cors = dom::Element::StringToCORSMode(aCrossOrigin);
      auto key = PreloadHashKey::CreateAsFetch(aURI, cors);

      // * Bug 1618549: Depending on where we decide to do the deduplication, we may
      // want to check if a fetch is already being preloaded here.

      RefPtr preloader = new FetchPreloader();
      dom::ReferrerPolicy referrerPolicy = PreloadReferrerPolicy(aReferrerPolicy);
      preloader->OpenChannel(key, aURI, cors, referrerPolicy, mDocument);
    }

    // static
    void PreloadService::NotifyNodeEvent(nsINode* aNode, bool aSuccess) {
      if (!aNode->IsInComposedDoc()) {
        return;
      }

      // We don't dispatch synchronously since |node| might be in a DocGroup
      // that we're not allowed to touch. (Our network request happens in the
      // DocGroup of one of the mSources nodes--not necessarily this one).

      RefPtr dispatcher = new AsyncEventDispatcher(
          aNode, aSuccess ? u"load"_ns : u"error"_ns, CanBubble::eNo);

      dispatcher->RequireNodeInDocument();
      dispatcher->PostDOMEvent();
    }

    dom::ReferrerPolicy PreloadService::PreloadReferrerPolicy(
        const nsAString& aReferrerPolicy) {
      dom::ReferrerPolicy referrerPolicy =
          dom::ReferrerInfo::ReferrerPolicyAttributeFromString(aReferrerPolicy);
      if (referrerPolicy == dom::ReferrerPolicy::_empty) {
        referrerPolicy = mDocument->GetPreloadReferrerInfo()->ReferrerPolicy();
      }

      return referrerPolicy;
    }

    nsIURI* PreloadService::BaseURIForPreload() {
      nsIURI* documentURI = mDocument->GetDocumentURI();
      nsIURI* documentBaseURI = mDocument->GetDocBaseURI();
      return (documentURI == documentBaseURI)
                 ? (mSpeculationBaseURI ? mSpeculationBaseURI.get() : documentURI)
                 : documentBaseURI;
    }

    }  // namespace mozilla