text: /**
   * Copyright (c) Facebook, Inc. and its affiliates.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   *
   * @flow
   */
  
  import {
    convertInspectedElementBackendToFrontend,
    hydrateHelper,
    inspectElement as inspectElementAPI,
  } from 'react-devtools-shared/src/backendAPI';
  import {fillInPath} from 'react-devtools-shared/src/hydration';
  
  import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
  import type {
    InspectElementFullData,
    InspectElementHydratedPath,
  } from 'react-devtools-shared/src/backend/types';
  import type {
    Element,
    InspectedElement as InspectedElementFrontend,
    InspectedElementResponseType,
  } from 'react-devtools-shared/src/devtools/views/Components/types';
  
  // Map an Element in the Store to the most recent copy of its inspected data.
  // As updates comes from the backend, inspected data is updated.
  // Both this map and the inspected objects in it are mutable.
  // They should never be read from directly during render;
  // Use a Suspense cache to ensure that transitions work correctly and there is no tearing.
  const inspectedElementMap: WeakMap<
    Element,
    InspectedElementFrontend,
  > = new WeakMap();
  
  type Path = Array<string | number>;
  
  type InspectElementReturnType = [
    InspectedElementFrontend,
    InspectedElementResponseType,
  ];
  
  export function inspectElement({
    bridge,
    element,
    path,
    rendererID,
  }: {|
    bridge: FrontendBridge,
    element: Element,
    path: Path | null,
    rendererID: number,
  |}): Promise<InspectElementReturnType> {
    const {id} = element;
    return inspectElementAPI({
      bridge,
      id,
      path,
      rendererID,
    }).then((data: any) => {
      const {type} = data;
  
      let inspectedElement;
      switch (type) {
        case 'no-change':
          // This is a no-op for the purposes of our cache.
          inspectedElement = inspectedElementMap.get(element);
          if (inspectedElement != null) {
            return [inspectedElement, type];
          }
          break;
  
        case 'not-found':
          // This is effectively a no-op.
          // If the Element is still in the Store, we can eagerly remove it from the Map.
          inspectedElementMap.delete(element);
  
          throw Error(`Element "${id}" not found`);
  
        case 'full-data':
          const fullData = ((data: any): InspectElementFullData);
  
          // New data has come in.
          // We should replace the data in our local mutable copy.
          inspectedElement = convertInspectedElementBackendToFrontend(
            fullData.value,
          );
  
          inspectedElementMap.set(element, inspectedElement);
  
          return [inspectedElement, type];
  
        case 'hydrated-path':
          const hydratedPathData = ((data: any): InspectElementHydratedPath);
          const {value} = hydratedPathData;
  
          // A path has been hydrated.
          // Merge it with the latest copy we have locally and resolve with the merged value.
          inspectedElement = inspectedElementMap.get(element) || null;
          if (inspectedElement !== null) {
            // Clone element
            inspectedElement = {...inspectedElement};
  
            // Merge hydrated data
            fillInPath(
              inspectedElement,
              value,
              ((path: any): Path),
              hydrateHelper(value, ((path: any): Path)),
            );
  
            inspectedElementMap.set(element, inspectedElement);
  
            return [inspectedElement, type];
          }
          break;
  
        default:
          // Should never happen.
          if (__DEV__) {
            console.error(
              `Unexpected inspected element response data: "${type}"`,
            );
          }
          break;
      }
  
      throw Error(`Unable to inspect element with id "${id}"`);
    });
  }
  