1. /* eslint-disable dot-notation */
    
  2. 
    
  3. // Instruction set for Fizz inline scripts.
    
  4. // DO NOT DIRECTLY IMPORT THIS FILE. This is the source for the compiled and
    
  5. // minified code in ReactDOMFizzInstructionSetInlineCodeStrings.
    
  6. 
    
  7. import {
    
  8.   clientRenderBoundary,
    
  9.   completeBoundary,
    
  10.   completeSegment,
    
  11. } from './ReactDOMFizzInstructionSetShared';
    
  12. 
    
  13. export {clientRenderBoundary, completeBoundary, completeSegment};
    
  14. 
    
  15. // This function is almost identical to the version used by the external
    
  16. // runtime (ReactDOMFizzInstructionSetExternalRuntime), with the exception of
    
  17. // how we read completeBoundaryImpl and resourceMap
    
  18. export function completeBoundaryWithStyles(
    
  19.   suspenseBoundaryID,
    
  20.   contentID,
    
  21.   stylesheetDescriptors,
    
  22. ) {
    
  23.   const completeBoundaryImpl = window['$RC'];
    
  24.   const resourceMap = window['$RM'];
    
  25. 
    
  26.   const precedences = new Map();
    
  27.   const thisDocument = document;
    
  28.   let lastResource, node;
    
  29. 
    
  30.   // Seed the precedence list with existing resources and collect hoistable style tags
    
  31.   const nodes = thisDocument.querySelectorAll(
    
  32.     'link[data-precedence],style[data-precedence]',
    
  33.   );
    
  34.   const styleTagsToHoist = [];
    
  35.   for (let i = 0; (node = nodes[i++]); ) {
    
  36.     if (node.getAttribute('media') === 'not all') {
    
  37.       styleTagsToHoist.push(node);
    
  38.     } else {
    
  39.       if (node.tagName === 'LINK') {
    
  40.         resourceMap.set(node.getAttribute('href'), node);
    
  41.       }
    
  42.       precedences.set(node.dataset['precedence'], (lastResource = node));
    
  43.     }
    
  44.   }
    
  45. 
    
  46.   let i = 0;
    
  47.   const dependencies = [];
    
  48.   let href, precedence, attr, loadingState, resourceEl, media;
    
  49. 
    
  50.   // Sheets Mode
    
  51.   let sheetMode = true;
    
  52.   while (true) {
    
  53.     if (sheetMode) {
    
  54.       // Sheet Mode iterates over the stylesheet arguments and constructs them if new or checks them for
    
  55.       // dependency if they already existed
    
  56.       const stylesheetDescriptor = stylesheetDescriptors[i++];
    
  57.       if (!stylesheetDescriptor) {
    
  58.         // enter <style> Mode
    
  59.         sheetMode = false;
    
  60.         i = 0;
    
  61.         continue;
    
  62.       }
    
  63. 
    
  64.       let avoidInsert = false;
    
  65.       let j = 0;
    
  66.       href = stylesheetDescriptor[j++];
    
  67. 
    
  68.       if ((resourceEl = resourceMap.get(href))) {
    
  69.         // We have an already inserted stylesheet.
    
  70.         loadingState = resourceEl['_p'];
    
  71.         avoidInsert = true;
    
  72.       } else {
    
  73.         // We haven't already processed this href so we need to construct a stylesheet and hoist it
    
  74.         // We construct it here and attach a loadingState. We also check whether it matches
    
  75.         // media before we include it in the dependency array.
    
  76.         resourceEl = thisDocument.createElement('link');
    
  77.         resourceEl.href = href;
    
  78.         resourceEl.rel = 'stylesheet';
    
  79.         resourceEl.dataset['precedence'] = precedence =
    
  80.           stylesheetDescriptor[j++];
    
  81.         while ((attr = stylesheetDescriptor[j++])) {
    
  82.           resourceEl.setAttribute(attr, stylesheetDescriptor[j++]);
    
  83.         }
    
  84.         loadingState = resourceEl['_p'] = new Promise((resolve, reject) => {
    
  85.           resourceEl.onload = resolve;
    
  86.           resourceEl.onerror = reject;
    
  87.         });
    
  88.         // Save this resource element so we can bailout if it is used again
    
  89.         resourceMap.set(href, resourceEl);
    
  90.       }
    
  91.       media = resourceEl.getAttribute('media');
    
  92.       if (
    
  93.         loadingState &&
    
  94.         loadingState['s'] !== 'l' &&
    
  95.         (!media || window['matchMedia'](media).matches)
    
  96.       ) {
    
  97.         dependencies.push(loadingState);
    
  98.       }
    
  99.       if (avoidInsert) {
    
  100.         // We have a link that is already in the document. We don't want to fall through to the insert path
    
  101.         continue;
    
  102.       }
    
  103.     } else {
    
  104.       // <style> mode iterates over not-yet-hoisted <style> tags with data-precedence and hoists them.
    
  105.       resourceEl = styleTagsToHoist[i++];
    
  106.       if (!resourceEl) {
    
  107.         // we are done with all style tags
    
  108.         break;
    
  109.       }
    
  110. 
    
  111.       precedence = resourceEl.getAttribute('data-precedence');
    
  112.       resourceEl.removeAttribute('media');
    
  113.     }
    
  114. 
    
  115.     // resourceEl is either a newly constructed <link rel="stylesheet" ...> or a <style> tag requiring hoisting
    
  116.     const prior = precedences.get(precedence) || lastResource;
    
  117.     if (prior === lastResource) {
    
  118.       lastResource = resourceEl;
    
  119.     }
    
  120.     precedences.set(precedence, resourceEl);
    
  121. 
    
  122.     // Finally, we insert the newly constructed instance at an appropriate location
    
  123.     // in the Document.
    
  124.     if (prior) {
    
  125.       prior.parentNode.insertBefore(resourceEl, prior.nextSibling);
    
  126.     } else {
    
  127.       const head = thisDocument.head;
    
  128.       head.insertBefore(resourceEl, head.firstChild);
    
  129.     }
    
  130.   }
    
  131. 
    
  132.   Promise.all(dependencies).then(
    
  133.     completeBoundaryImpl.bind(null, suspenseBoundaryID, contentID, ''),
    
  134.     completeBoundaryImpl.bind(
    
  135.       null,
    
  136.       suspenseBoundaryID,
    
  137.       contentID,
    
  138.       'Resource failed to load',
    
  139.     ),
    
  140.   );
    
  141. }