1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow strict-local
    
  8.  */
    
  9. 
    
  10. 'use strict';
    
  11. 
    
  12. import {type ViewConfig} from './ReactNativeTypes';
    
  13. 
    
  14. // Event configs
    
  15. export const customBubblingEventTypes = {};
    
  16. export const customDirectEventTypes = {};
    
  17. 
    
  18. const viewConfigCallbacks = new Map();
    
  19. const viewConfigs = new Map();
    
  20. 
    
  21. function processEventTypes(viewConfig: ViewConfig): void {
    
  22.   const {bubblingEventTypes, directEventTypes} = viewConfig;
    
  23. 
    
  24.   if (__DEV__) {
    
  25.     if (bubblingEventTypes != null && directEventTypes != null) {
    
  26.       for (const topLevelType in directEventTypes) {
    
  27.         if (bubblingEventTypes[topLevelType] != null) {
    
  28.           throw new Error(
    
  29.             `Event cannot be both direct and bubbling: ${topLevelType}`,
    
  30.           );
    
  31.         }
    
  32.       }
    
  33.     }
    
  34.   }
    
  35. 
    
  36.   if (bubblingEventTypes != null) {
    
  37.     for (const topLevelType in bubblingEventTypes) {
    
  38.       if (customBubblingEventTypes[topLevelType] == null) {
    
  39.         customBubblingEventTypes[topLevelType] =
    
  40.           bubblingEventTypes[topLevelType];
    
  41.       }
    
  42.     }
    
  43.   }
    
  44. 
    
  45.   if (directEventTypes != null) {
    
  46.     for (const topLevelType in directEventTypes) {
    
  47.       if (customDirectEventTypes[topLevelType] == null) {
    
  48.         customDirectEventTypes[topLevelType] = directEventTypes[topLevelType];
    
  49.       }
    
  50.     }
    
  51.   }
    
  52. }
    
  53. 
    
  54. /**
    
  55.  * Registers a native view/component by name.
    
  56.  * A callback is provided to load the view config from UIManager.
    
  57.  * The callback is deferred until the view is actually rendered.
    
  58.  */
    
  59. export function register(name: string, callback: () => ViewConfig): string {
    
  60.   if (viewConfigCallbacks.has(name)) {
    
  61.     throw new Error(`Tried to register two views with the same name ${name}`);
    
  62.   }
    
  63. 
    
  64.   if (typeof callback !== 'function') {
    
  65.     throw new Error(
    
  66.       `View config getter callback for component \`${name}\` must be a function (received \`${
    
  67.         callback === null ? 'null' : typeof callback
    
  68.       }\`)`,
    
  69.     );
    
  70.   }
    
  71. 
    
  72.   viewConfigCallbacks.set(name, callback);
    
  73.   return name;
    
  74. }
    
  75. 
    
  76. /**
    
  77.  * Retrieves a config for the specified view.
    
  78.  * If this is the first time the view has been used,
    
  79.  * This configuration will be lazy-loaded from UIManager.
    
  80.  */
    
  81. export function get(name: string): ViewConfig {
    
  82.   let viewConfig;
    
  83.   if (!viewConfigs.has(name)) {
    
  84.     const callback = viewConfigCallbacks.get(name);
    
  85.     if (typeof callback !== 'function') {
    
  86.       throw new Error(
    
  87.         `View config getter callback for component \`${name}\` must be a function (received \`${
    
  88.           callback === null ? 'null' : typeof callback
    
  89.         }\`).${
    
  90.           typeof name[0] === 'string' && /[a-z]/.test(name[0])
    
  91.             ? ' Make sure to start component names with a capital letter.'
    
  92.             : ''
    
  93.         }`,
    
  94.       );
    
  95.     }
    
  96.     viewConfig = callback();
    
  97.     processEventTypes(viewConfig);
    
  98.     viewConfigs.set(name, viewConfig);
    
  99. 
    
  100.     // Clear the callback after the config is set so that
    
  101.     // we don't mask any errors during registration.
    
  102.     viewConfigCallbacks.set(name, null);
    
  103.   } else {
    
  104.     viewConfig = viewConfigs.get(name);
    
  105.   }
    
  106. 
    
  107.   if (!viewConfig) {
    
  108.     throw new Error(`View config not found for name ${name}`);
    
  109.   }
    
  110. 
    
  111.   return viewConfig;
    
  112. }