patchAndUpgradeTree(root, visitedImports = new Set()) {
    const elements = [];

    const gatherElements = element => {
      if (element.localName === 'link' && element.getAttribute('rel') === 'import') {
        // The HTML Imports polyfill sets a descendant element of the link to
        // the `import` property, specifically this is *not* a Document.
        const importNode = /** @type {?Node} */ (element.import);

        if (importNode instanceof Node && importNode.readyState === 'complete') {
          importNode.__CE_isImportDocument = true;

          // Connected links are associated with the registry.
          importNode.__CE_hasRegistry = true;
        } else {
          // If this link's import root is not available, its contents can't be
          // walked. Wait for 'load' and walk it when it's ready.
          element.addEventListener('load', () => {
            const importNode = /** @type {!Node} */ (element.import);

            if (importNode.__CE_documentLoadHandled) return;
            importNode.__CE_documentLoadHandled = true;

            importNode.__CE_isImportDocument = true;

            // Connected links are associated with the registry.
            importNode.__CE_hasRegistry = true;

            // Clone the `visitedImports` set that was populated sync during
            // the `patchAndUpgradeTree` call that caused this 'load' handler to
            // be added. Then, remove *this* link's import node so that we can
            // walk that import again, even if it was partially walked later
            // during the same `patchAndUpgradeTree` call.
            const clonedVisitedImports = new Set(visitedImports);
            visitedImports.delete(importNode);

            this.patchAndUpgradeTree(importNode, visitedImports);
          });
        }
      } else {
        elements.push(element);
      }
    };

    // `walkDeepDescendantElements` populates (and internally checks against)
    // `visitedImports` when traversing a loaded import.
    walkDeepDescendantElements(root, gatherElements, visitedImports);

    if (this._hasPatches) {
      for (let i = 0; i < elements.length; i++) {
        this.patch(elements[i]);
      }
    }

    for (let i = 0; i < elements.length; i++) {
      this.upgradeElement(elements[i]);
    }
  }
/**
   * Upgrades all uncustomized custom elements at and below a root node for
   * which there is a definition. When custom element reaction callbacks are
   * assumed to be called synchronously (which, by the current DOM / HTML spec
   * definitions, they are *not*), callbacks for both elements customized
   * synchronously by the parser and elements being upgraded occur in the same
   * relative order.
   *
   * NOTE: This function, when used to simulate the construction of a tree that
   * is already created but not customized (i.e. by the parser), does *not*
   * prevent the element from reading the 'final' (true) state of the tree. For
   * example, the element, during truly synchronous parsing / construction would
   * see that it contains no children as they have not yet been inserted.
   * However, this function does not modify the tree, the element will
   * (incorrectly) have children. Additionally, self-modification restrictions
   * for custom element constructors imposed by the DOM spec are *not* enforced.
   *
   *
   * The following nested list shows the steps extending down from the HTML
   * spec's parsing section that cause elements to be synchronously created and
   * upgraded:
   *
   * The "in body" insertion mode:
   * https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody
   * - Switch on token:
   *   .. other cases ..
   *   -> Any other start tag
   *      - [Insert an HTML element](below) for the token.
   *
   * Insert an HTML element:
   * https://html.spec.whatwg.org/multipage/syntax.html#insert-an-html-element
   * - Insert a foreign element for the token in the HTML namespace:
   *   https://html.spec.whatwg.org/multipage/syntax.html#insert-a-foreign-element
   *   - Create an element for a token:
   *     https://html.spec.whatwg.org/multipage/syntax.html#create-an-element-for-the-token
   *     - Will execute script flag is true?
   *       - (Element queue pushed to the custom element reactions stack.)
   *     - Create an element:
   *       https://dom.spec.whatwg.org/#concept-create-element
   *       - Sync CE flag is true?
   *         - Constructor called.
   *         - Self-modification restrictions enforced.
   *       - Sync CE flag is false?
   *         - (Upgrade reaction enqueued.)
   *     - Attributes appended to element.
   *       (`attributeChangedCallback` reactions enqueued.)
   *     - Will execute script flag is true?
   *       - (Element queue popped from the custom element reactions stack.
   *         Reactions in the popped stack are invoked.)
   *   - (Element queue pushed to the custom element reactions stack.)
   *   - Insert the element:
   *     https://dom.spec.whatwg.org/#concept-node-insert
   *     - Shadow-including descendants are connected. During parsing
   *       construction, there are no shadow-*excluding* descendants.
   *       However, the constructor may have validly attached a shadow
   *       tree to itself and added descendants to that shadow tree.
   *       (`connectedCallback` reactions enqueued.)
   *   - (Element queue popped from the custom element reactions stack.
   *     Reactions in the popped stack are invoked.)
   *
   * @param {!Node} root
   * @param {!Set<Node>=} visitedImports
   */
Upgrades all uncustomized custom elements at and below a root node for
which there is a definition. When custom element reaction callbacks are
assumed to be called synchronously (which, by the current DOM / HTML spec
definitions, they are *not*), callbacks for both elements customized
synchronously by the parser and elements being upgraded occur in the same
relative order.

This function, when used to simulate the construction of a tree that
is already created but not customized , does *not
prevent the element from reading the 'final' (true) state of the tree. For
example, the element, during truly synchronous parsing / construction would
see that it contains no children as they have not yet been inserted.
However, this function does not modify the tree, the element will
(incorrectly) have children. Additionally, self-modification restrictions
for custom element constructors imposed by the DOM spec are *not* enforced.

The following nested list shows the steps extending down from the HTML
spec's parsing section that cause elements to be synchronously created and
upgraded.





@param {!Node} root
@param {!Set=} visitedImports
Upgrades all uncustomized custom elements at and below a root node for which there is a definition . When custom element reaction callbacks are assumed to be called synchronously ( which by the current DOM / HTML spec definitions they are * not * ) callbacks for both elements customized synchronously by the parser and elements being upgraded occur in the same relative order . This function when used to simulate the construction of a tree that is already created but not customized does * not prevent the element from reading the ' final ' ( true ) state of the tree . For example the element during truly synchronous parsing / construction would see that it contains no children as they have not yet been inserted . However this function does not modify the tree the element will ( incorrectly ) have children . Additionally self - modification restrictions for custom element constructors imposed by the DOM spec are * not * enforced . The following nested list shows the steps extending down from the HTML spec ' s parsing section that cause elements to be synchronously created and upgraded . @param { !Node } root @param { !Set = } visitedImports
patchAndUpgradeTree(root, visitedImports = new Set()) {
    const elements = [];
    const gatherElements = element => {
      if (element.localName === 'link' && element.getAttribute('rel') === 'import') {
        const importNode =  (element.import);
        if (importNode instanceof Node && importNode.readyState === 'complete') {
          importNode.__CE_isImportDocument = true;
          importNode.__CE_hasRegistry = true;
        } else {
          element.addEventListener('load', () => {
            const importNode =  (element.import);
            if (importNode.__CE_documentLoadHandled) return;
            importNode.__CE_documentLoadHandled = true;
            importNode.__CE_isImportDocument = true;
            importNode.__CE_hasRegistry = true;
            const clonedVisitedImports = new Set(visitedImports);
            visitedImports.delete(importNode);
            this.patchAndUpgradeTree(importNode, visitedImports);
          });
        }
      } else {
        elements.push(element);
      }
    };
    walkDeepDescendantElements(root, gatherElements, visitedImports);
    if (this._hasPatches) {
      for (let i = 0; i < elements.length; i++) {
        this.patch(elements[i]);
      }
    }
    for (let i = 0; i < elements.length; i++) {
      this.upgradeElement(elements[i]);
    }
  }
patchAndUpgradeTree ( root , visitedImports = new Set ( ) ) { const elements = [ ] ; const gatherElements = element => { if ( element . localName === 'link' && element . getAttribute ( 'rel' ) === 'import' ) { const importNode = ( element . import ) ; if ( importNode instanceof Node && importNode . readyState === 'complete' ) { importNode . __CE_isImportDocument = true ; importNode . __CE_hasRegistry = true ; } else { element . addEventListener ( 'load' , ( ) => { const importNode = ( element . import ) ; if ( importNode . __CE_documentLoadHandled ) return ; importNode . __CE_documentLoadHandled = true ; importNode . __CE_isImportDocument = true ; importNode . __CE_hasRegistry = true ; const clonedVisitedImports = new Set ( visitedImports ) ; visitedImports . delete ( importNode ) ; this . patchAndUpgradeTree ( importNode , visitedImports ) ; } ) ; } } else { elements . push ( element ) ; } } ; walkDeepDescendantElements ( root , gatherElements , visitedImports ) ; if ( this . _hasPatches ) { for ( let i = 0 ; i < elements . length ; i ++ ) { this . patch ( elements [ i ] ) ; } } for ( let i = 0 ; i < elements . length ; i ++ ) { this . upgradeElement ( elements [ i ] ) ; } }
Upgrades all uncustomized custom elements at and below a root node for
 which there is a definition.
Upgrades all uncustomized custom elements at and below a root node for which there is a definition .
// The HTML Imports polyfill sets a descendant element of the link to // the `import` property, specifically this is *not* a Document. /** @type {?Node} */ // Connected links are associated with the registry. // If this link's import root is not available, its contents can't be // walked. Wait for 'load' and walk it when it's ready. /** @type {!Node} */ // Connected links are associated with the registry. // Clone the `visitedImports` set that was populated sync during // the `patchAndUpgradeTree` call that caused this 'load' handler to // be added. Then, remove *this* link's import node so that we can // walk that import again, even if it was partially walked later // during the same `patchAndUpgradeTree` call. // `walkDeepDescendantElements` populates (and internally checks against) // `visitedImports` when traversing a loaded import.